如何在 Pro*C 查询中指定变量表达式列表?

发布于 2024-08-11 02:40:16 字数 2799 浏览 5 评论 0原文

我尝试优化的 Pro*C 查询出现问题。

解释一下,我们的应用程序在一个巨大的数据库中搜索行。这些行存在于多种语言中,旧代码为数组中的每种语言选择一行。现在,由于这些查询是我们应用程序中最耗时的部分,因此我只想进行一个直接写入数组的查询。

语言代码是 2 个字母的 ISO-639 代码(en 表示英语,fr 表示法语)。

老方法(这只是一个简化的代码来显示意图)

struct ROW arr[MAX_LAN];
struct ROW_IND arr_ind[MAX_LAN];
uint_t LanIdx;
for(LanIdx=0; LanIdx<MAX_LAN; LanIdx++) {
  EXEC SQL SELECT *  /* Don't look at the *, it's for obfuscation only */
      INTO :arr[LanIdx]:arr_ind[LanIdx]
      FROM table WHERE id=:uniqid AND language=:LanCode[LanIdx];
}

我想做这样的事情:

EXEC SQL SELECT *  /* Don't look at the *, it's for obfuscation only */
    INTO :arr:arr_ind
    FROM table WHERE id=:uniqid AND language IN (:LanCodes);

但不知道我应该如何定义LanCodes。

它适用于像这样的常量(编译时)列表,

EXEC SQL SELECT *  /* Don't look at the *, it's for obfuscation only */
    INTO :arr:arr_ind
    FROM table WHERE id=:uniqid AND language IN ('en','fr','de');

但这没有用,因为语言可能因情况而异。

如果我写这样的东西,

char LanCodes[MAX_LANS*5];
sprintf(LanCodes, "%s", LanCode[LanIdx]);

EXEC SQL SELECT *  /* Don't look at the *, it's for obfuscation only */
    INTO :arr:arr_ind
    FROM table WHERE id=:uniqid AND language IN (:LanCodes);

只有当字符串中有 1 种语言代码时它才有效。

所以我的问题是,有人知道如何做到这一点吗? Oracle文档太大了,不知道去哪里看。我尝试了不同的方法,但没有一个有效。

编辑 好的,我找到了一个有效的解决方案。它不优雅,不先进,但效果很好。我在查询中放置了一个 OR 子句列表,它以我需要的形式返回我需要的内容。

EXEC SQL SELECT *  /* Don't look at the *, it's for obfuscation only */
    INTO :arr:arr_ind
    FROM table WHERE id=:uniqid AND (
                language=:v1[ 0] OR
                language=:v1[ 1] OR
                language=:v1[ 2] OR
                language=:v1[ 3] OR
                language=:v1[ 4] OR
                language=:v1[ 5] OR
                language=:v1[ 6] OR
                language=:v1[ 7] OR
                language=:v1[ 8] OR
                language=:v1[ 9] OR
                language=:v1[10] OR
                language=:v1[11] OR
                language=:v1[12] OR
                language=:v1[13] OR
                language=:v1[14] OR
                language=:v1[15] OR
                language=:v1[16] OR
                language=:v1[17] OR
                language=:v1[18] OR
                language=:v1[19] OR
                language=:v1[20] OR
                language=:v1[21] OR
                language=:v1[22] OR
                language=:v1[23] OR
                language=:v1[24] OR
                language=:v1[25] OR
                language=:v1[26] OR
                language=:v1[27] OR
                language=:v1[28] OR
                language=:v1[29] OR
                language=:v1[30]);

当有超过 2 种语言时,速度会更快,因此我根据要获取的语言数量将其称为此变体或旧变体。

I have a problem with a Pro*C query I'm trying to optimise.

To explain, our application searches for rows in a huge database. These rows exist in several languages and the old code selected a row for each language in an array. Now as these queries are the most time consuming part of our app, I wanted to make only one query which writes directly in an array.

The language codes are 2 letter ISO-639 codes (en for english, fr for french).

Old way (this is only a simplified code to show the intention)

struct ROW arr[MAX_LAN];
struct ROW_IND arr_ind[MAX_LAN];
uint_t LanIdx;
for(LanIdx=0; LanIdx<MAX_LAN; LanIdx++) {
  EXEC SQL SELECT *  /* Don't look at the *, it's for obfuscation only */
      INTO :arr[LanIdx]:arr_ind[LanIdx]
      FROM table WHERE id=:uniqid AND language=:LanCode[LanIdx];
}

I would like to do something like this:

EXEC SQL SELECT *  /* Don't look at the *, it's for obfuscation only */
    INTO :arr:arr_ind
    FROM table WHERE id=:uniqid AND language IN (:LanCodes);

but do not know how I should define LanCodes.

It works with a constant (compile time) list like this

EXEC SQL SELECT *  /* Don't look at the *, it's for obfuscation only */
    INTO :arr:arr_ind
    FROM table WHERE id=:uniqid AND language IN ('en','fr','de');

but this is not useful, as the languages may vary from case to case.

If I write something like

char LanCodes[MAX_LANS*5];
sprintf(LanCodes, "%s", LanCode[LanIdx]);

EXEC SQL SELECT *  /* Don't look at the *, it's for obfuscation only */
    INTO :arr:arr_ind
    FROM table WHERE id=:uniqid AND language IN (:LanCodes);

it works only if there is 1 language code in the string.

So my question is, does anybody know how to make this work? The Oracle documentation is so big, I don't know where to look at. I tried different ways, but none worked.

EDIT
Ok, I found a solution that works. It's not elegant, it's not advanced but it works well. I put a list of OR clauses in my query and it returns what I need in the form that I need.

EXEC SQL SELECT *  /* Don't look at the *, it's for obfuscation only */
    INTO :arr:arr_ind
    FROM table WHERE id=:uniqid AND (
                language=:v1[ 0] OR
                language=:v1[ 1] OR
                language=:v1[ 2] OR
                language=:v1[ 3] OR
                language=:v1[ 4] OR
                language=:v1[ 5] OR
                language=:v1[ 6] OR
                language=:v1[ 7] OR
                language=:v1[ 8] OR
                language=:v1[ 9] OR
                language=:v1[10] OR
                language=:v1[11] OR
                language=:v1[12] OR
                language=:v1[13] OR
                language=:v1[14] OR
                language=:v1[15] OR
                language=:v1[16] OR
                language=:v1[17] OR
                language=:v1[18] OR
                language=:v1[19] OR
                language=:v1[20] OR
                language=:v1[21] OR
                language=:v1[22] OR
                language=:v1[23] OR
                language=:v1[24] OR
                language=:v1[25] OR
                language=:v1[26] OR
                language=:v1[27] OR
                language=:v1[28] OR
                language=:v1[29] OR
                language=:v1[30]);

It's faster when there is more than 2 languages, so I call this variant or the old one depending on number of languages to fetch.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

愁杀 2024-08-18 02:40:16

可能是这个 AskTom 文章 可以帮助你。

Probably this AskTom article can help you.

旧人 2024-08-18 02:40:16

如果没有 Oracle 动态 SQL,则无法执行此操作。您必须在运行时构建 IN 子句并立即执行。至少你可以根据你的查询使用方法1。

You can't do this without Oracle Dynamic SQL. You will have to build your IN clause at runtime and EXECUTE IMMEDIATE. At least you can use Method 1, based on your queries.

失与倦" 2024-08-18 02:40:16

我之前使用过一个由 ID 和一组行组成的表,其中行是“in”列表中可能值的排列。然后我根据以下内容加入到表中
ID 它给了我我需要的结果。

create table permute (
  id number,
  lang char(2)
);
create index permute_p1 on permute ( lang, id );
insert into permute ( id, lang ) values ( 1, 'en' );
insert into permute ( id, lang ) values ( 2, 'en' );
insert into permute ( id, lang ) values ( 2, 'fr' );
...

然后您所要做的就是选择正确的“ID”值 2、3、4 ... 并将其放入
加入。

I have used a table before composed of an ID and a set of rows where the rows are the permutation of the possible values in the "in" list. Then I join to the table based on the
ID and it gives me the results I need.

create table permute (
  id number,
  lang char(2)
);
create index permute_p1 on permute ( lang, id );
insert into permute ( id, lang ) values ( 1, 'en' );
insert into permute ( id, lang ) values ( 2, 'en' );
insert into permute ( id, lang ) values ( 2, 'fr' );
...

All you have to do then is pick the correct "ID" value 2, 3, 4 ... and put that into the
join.

茶底世界 2024-08-18 02:40:16

...
Main String:= 'Select * FROM table WHERE id=:uniqid AND language IN'; -- 可以分成两部分来容纳 :uniqd
...
选择 Language_code 到 v_string
来自 x_表;
环形
复制&将 v_string 连接到 LanCode_String 并使用 ' ', ;
结束循环;
..
将 Lancode 连接到主字符串。
..
准备并执行主字符串。

...
Main String:= 'Select * FROM table WHERE id=:uniqid AND language IN'; -- can split into two to accomadate :uniqd
...
Select Language_code into v_string
from x_table;
loop
Copy & Concat v_string to LanCode_String and with ' ', ;
end loop;
..
Concat Lancode to Main String.
..
Prepare and execute the Main String.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文