2

甲骨文 11G

  • Table1 有 T1_ID
  • Table2 有 T1_ID 和一个表示二进制数的字符串 (BIN_STR)

    1. 如果 Table1.T1_ID 不在 Table2 中,则返回一串 0
    2. 如果 Table1.T1_ID 在 Table2 中只找到一次,则返回是 Table2 中的字符串
    3. 如果在 Table2 中多次找到 Table1.T1_ID,则返回需要是 Table2 中字符串的按位或。

例子:

表格1

T1_ID 
    1 
    2 
    3

表2有这些记录

T1_ID   BIN_STR 
    2    '0101'
    3    '0100'
    3    '1000'

结果集需要有

T1_ID   BIN_STR 
    1    '0000'
    2    '0101'
    3    '1100'

我有:

SELECT Tbl1.T1_ID,
       CASE (SELECT COUNT(*) FROM Table2 Tbl2 WHERE Tbl1.T1_ID = Tbl2.T1_ID)
         WHEN 0 THEN '0000'
         WHEN 1 THEN (SELECT Tbl2.BIN_STR FROM Table2 Tbl2 WHERE Tbl1.T1_ID = Tbl2.T1_ID)
         ELSE ???
       END AS "BINSTR"
FROM Table1 Tbl1

我知道这可以通过存储过程中的自定义函数调用来完成。有没有办法在 SQL PLUS 中做到这一点?

4

2 回答 2

0

在 SQL 11g 中有几种方法可以做到这一点。这是实际的 MODEL 子句:

SQL> with data as (select t1.t1_id, nvl(t2.bin_str, '0000') bin_str
  2    from table1 t1
  3         left outer join table2 t2
  4                      on t1.t1_id = t2.t1_id)
  5  select t1_id, new_bin_str bin_str
  6    from (select *
  7    from data
  8   model
  9   partition by (t1_id)
 10   dimension by (row_number() over (partition by t1_id order by bin_str) rn )
 11   measures (bin_str, cast(null as varchar2(16)) new_bin_str,
 12   count(*) over (partition by t1_id ) c)
 13  rules (
 14  new_bin_str[any] order by rn  =
 15                    case when bin_str[cv() - 1 ] is null
 16               then bin_str[cv()]
 17                        else cast(utl_raw.bit_or(new_bin_str[cv()-1],bin_str[cv()]) as varchar2(16))
 18           end ))
 19   where c = rn;

     T1_ID BIN_STR
---------- --------------------
         1 0000
         2 0101
         3 1100

让我们分解一下。

SQL> with data as (select t1.t1_id, nvl(t2.bin_str, '0000') bin_str
  2    from table1 t1
  3         left outer join table2 t2
  4                      on t1.t1_id = t2.t1_id)

这只是我们的基本查询,其中包含我们感兴趣的所有数据。

现在我们需要对它进行异或(可通过 utl_raw.bit_or 获得),并且只显示每个 T1_ID 的最终结果。

示范条款可以为我们做到这一点。首先,我们定义一个“分区”,因为我们希望将计算隔离到特定的 T1_ID。

  9   partition by (t1_id)

接下来,我们对每一行应用一个顺序,以便我们每次都以相同的方式做事。即对于 T1_ID = 3 你有 0101 和 1100 所以我们想要做0101 XOR 1100和计算这个结果。如果有第三个二进制“0001”,我们就想这样做0101 XOR 1100 = resres XOR 0001依此类推。而且我们只对最终结果感兴趣,所以我们可以使用行号最后为我们过滤:

 10   dimension by (row_number() over (partition by t1_id order by bin_str) rn )

我们也将维护每行的计数T1_ID

 12   count(*) over (partition by t1_id ) c)

即,当rn = c这是每个T1_ID.

措施条款

 11   measures (bin_str, cast(null as varchar2(16)) new_bin_str,

现在将是我们正在操作的。即bin_str,而且,你看我已经定义了一个空白列new_bin_str。这将是我们的保存列,保存 XOR 操作的结果。

现在计算部分是执行 XOR 的部分:

14 new_bin_str[any] order by rn = 15 case when bin_str[cv() - 1] 为空 16 then bin_str[cv()] 17 else cast(utl_raw.bit_or(new_bin_str[cv()-1],bin_str[cv ()]) as varchar2(16)) 18 结束))

所以这就是说,对于第一行的每一行 (new_bin_str[ANY]) 只需使用 的值,bin_str但对于随后的每一行,我们将先验new_bin_str和 XOR 与当前bin_str值相异。这给了我们以下输出:

     T1_ID         RN BIN_STR              NEW_BIN_STR               C
---------- ---------- -------------------- ---------------- ----------
         1          1 0000                 0000                      1
         2          1 0101                 0101                      1
         3          1 0100                 0100                      2
         3          2 1000                 1100                      2

你现在可以看到 NEW_BIN_STR 有我们需要的结果,但它也有所有的中间“工作”。所以我们过滤 c=rn 最终得到:

     T1_ID         RN BIN_STR              NEW_BIN_STR               C
---------- ---------- -------------------- ---------------- ----------
         1          1 0000                 0000                      1
         2          1 0101                 0101                      1
         3          2 1000                 1100                      2

在外部选择中,我只选择T1_IDand NEW_BIN_STR

其他方式可能是递归因子子查询、用户定义的聚合(例如,像 listagg 但一个执行异或的聚合),甚至可能是 xquery(没有想到这一点,但它也可能有能力这样做)。

于 2012-12-06T23:18:46.640 回答
0

我认为您需要的是按位或聚合函数。而且,Oracle 提供了它(参见http://docs.oracle.com/cd/E17952_01/refman-5.1-en/group-by-functions.html#function_bit-or)。

您需要将这些值转换为 BIGINT。这假设您在字符串中少于 64 位:

select t1_id, cast(bit_or(cast(bin_str as bigint)) as varchar(255))
from table2
group by t1_id
于 2012-12-05T17:19:55.243 回答