在 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 = res
,res 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_ID
and NEW_BIN_STR
。
其他方式可能是递归因子子查询、用户定义的聚合(例如,像 listagg 但一个执行异或的聚合),甚至可能是 xquery(没有想到这一点,但它也可能有能力这样做)。