识别NULL并分配位图

时间:2019-06-03 07:17:55

标签: sql oracle

我有一张桌子

表1

u_a_id  e_id   e_nm    e_val    e_seq
1       104    test    100      4
1       102    test2   x        2
1       102    test2   (null)   1
1       104    test    (null)   1

2       102    test2   (null)   2
2       102    test2   (null)   1
2       104    test    101      1
2       104    test    102      2

我首先需要对每个u_a_id按e_ide_seq进行排序,并将每个(null)标识为1,然后创建如下的位图。

例如

  • u_a_id = 1-第一个e_id = 102,e_seq = 1,e_val =(空),因此将其分配为1
  • u_a_id = 1-第一个e_id = 102,e_seq = 2,e_val = x,因此将其分配为0
  • u_a_id = 1-第一个e_id = 104,e_seq = 1,e_val =(空),因此将其分配为1
  • u_a_id = 1-第一个e_id = 104,e_seq = 4,e_val = 100,因此将其分配为0

因此,对于u_a_id = 1,添加新行-EMPTY = 1010

输出为:

u_a_id  e_id   e_nm    e_val    e_seq
1       104    test    100      4
1       102    test2   x        2
1       102    test2   (null)   1
1       104    test    (null)   1
1       (null) EMPTY   1010     (null)

2       102    test2   (null)   2
2       102    test2   (null)   1
2       104    test    101      1
2       104    test    102      2
2       (null) EMPTY   1100     (null)

Oracle SQL中有一种方法可以做到吗?

4 个答案:

答案 0 :(得分:3)

您可以使用LISTAGG进行字符串聚合,并使用GROUPING SETS

SELECT U_A_ID, E_ID
 ,CASE WHEN GROUPING_ID(U_A_ID, E_ID, E_NM, E_VAL, E_SEQ) = 15 
       THEN 'EMPTY' 
       ELSE E_NM END AS E_NM
 ,CASE WHEN GROUPING_ID(U_A_ID, E_ID, E_NM, E_VAL, E_SEQ) = 15 
       THEN LISTAGG(NVL2(E_VAL, '1', '0'),'') WITHIN GROUP (ORDER BY E_ID DESC, E_SEQ DESC) 
       ELSE E_VAL END AS E_VAL
 ,E_SEQ
FROM E
GROUP BY GROUPING SETS ((U_A_ID, E_ID, E_NM, E_VAL, E_SEQ), (U_A_ID))
ORDER BY U_A_ID, E_ID, E_SEQ;

db<>fiddle demo

答案 1 :(得分:1)

这应该按照您的要求执行,创建一个带有1和0的文本字符串。 请注意,将UNION放在此处只是为了复制与数据混合的预期结果行。您可以删除UNION及其后面的SQL位。

创建适当的数字位图而不是文本字符串一样容易。

设置:

create table e(
  u_a_id integer,
  e_id integer,
  e_nm varchar2(10),
  e_val varchar2(10),
  e_seq integer
);

INSERT INTO E(U_A_ID, E_ID, E_NM, E_VAL, E_SEQ) VALUES (1,102,'test2','x',2);
INSERT INTO E(U_A_ID, E_ID, E_NM, E_VAL, E_SEQ) VALUES (1,102,'test2',NULL,1);
INSERT INTO E(U_A_ID, E_ID, E_NM, E_VAL, E_SEQ) VALUES (1,104,'test','100',4);
INSERT INTO E(U_A_ID, E_ID, E_NM, E_VAL, E_SEQ) VALUES (1,104,'test',NULL,1);
INSERT INTO E(U_A_ID, E_ID, E_NM, E_VAL, E_SEQ) VALUES (2,102,'test2',NULL,1);
INSERT INTO E(U_A_ID, E_ID, E_NM, E_VAL, E_SEQ) VALUES (2,102,'test2',NULL,2);
INSERT INTO E(U_A_ID, E_ID, E_NM, E_VAL, E_SEQ) VALUES (2,104,'test','101',1);
INSERT INTO E(U_A_ID, E_ID, E_NM, E_VAL, E_SEQ) VALUES (2,104,'test','102',2);

查询:

with x as(
  -- This gets the rows with a "row number" within each U_A_ID group
  select e.*,row_number() over (PARTITION BY u_a_id ORDER BY e_id, e_seq) R from e
),
y as(
  -- This produces the bit, as a character, based on the E_VAL column
  select x.u_a_id, x.e_id, x.e_seq, nvl2(x.e_val, '1', '0') as bit from x
),
z as(
  -- This concatenates the bits, in the same reversed order that you provided
  select u_a_id, listagg(bit, '') within group (order by e_id desc, e_seq desc) bits from y group by u_a_id
)
select u_a_id, null as e_id, 'EMPTY' as e_nm, to_char(bits) as e_val, null as e_seq from z
union
select u_a_id, e_id, e_nm, e_val, e_seq from e
order by u_a_id, e_id nulls last, e_seq
/

答案 2 :(得分:0)

以下内容会生成您的“位图”:

select distinct t2.u_a_id,
    (select case when t1.e_val is null then '1' else '0' end as [text()]
     from table1 as t1
     where t1.u_a_id = t2.u_a_id
     order by u_a_id, e_id, e_seq
     for xml path ('')
    ) as bitmap
from table1 as t2

答案 3 :(得分:0)

最短的将会是

SELECT * FROM E -- Get the unchanged records
UNION ALL
-- And add the new rows:
SELECT U_A_ID
     , NULL
     , 'EMPTY'
     , listagg(NVL2(E_VAL, 0, 1),'') WITHIN GROUP (ORDER BY e_id, e_seq)
     , NULL
  FROM e
 GROUP BY u_a_id
ORDER BY 1,2 nulls last, 5 nulls last -- Order to get your desired order