将位图存储到适当的列-Oracle

时间:2019-05-22 08:19:17

标签: sql oracle

我有一张桌子:

表1

id      col     val         rec_pos
1       Test 1  10          1
1       Test 2  20          2
1       Test 3  30          3
1       Test 2  20          4
1       Empty   0101        5
1       Invalid 1011        6

2       Test 4  30          2
2       Test 5  30          3
2       Test 6  30          4
2       Test 5  30          5
2       Empty   11101       6
2       Invalid 10101       7


3       Test 7  30          5
3       Test 8  30          6
3       Test 8  30          7
3       Test 8  30          8
3       Empty   11110101    9
3       Invalid 10010101    10

4       Test 9  30          3
4       Empty   1101        5
4       Invalid 1011        6

对于每个唯一的id,我需要获取val ='Empty'的col,然后使用rec_pos,添加一个名为empty的新列并添加适当的值。

等同于无效,对于每个唯一的id,我需要为val ='Invalid'抓取col,然后使用rec_pos,添加一个名为{ {1}}并添加适当的值。

示例:

  1. 对于id = 1,col =空,val = 0101

    • rec_pos = 1,在空列= 0中添加值
    • rec_pos = 2,在空列= 1中添加值
    • rec_pos = 3,在空列= 0中添加值
    • rec_pos = 4,在空列= 1中添加值
  2. 对于id = 4,col =空,val = 1101

    • rec_pos = 1,在空列= 1中添加值
    • rec_pos = 2,在空列= 1中添加值
    • rec_pos = 3,在空列= 0中添加值
    • rec_pos = 4,在空列= 1中添加值

输出为:

invalid

如何读取值,然后将其适当地分配给具有相同ID的各自rec_pos?

3 个答案:

答案 0 :(得分:2)

测试用例(仅适用于ID的第1和第4个;不太喜欢输入):

SQL> create table test
  2    (id       number,
  3     col      varchar2(10),
  4     val      varchar2(10),
  5     rec_pos  number,
  6     empty    number,
  7     invalid  number);

Table created.

SQL> insert into test (id, col, val, rec_pos)
  2    (select 1, 'test 1',  '10'  , 1 from dual union all
  3     select 1, 'test 2' , '20'  , 2 from dual union all
  4     select 1, 'test 3' , '30'  , 3 from dual union all
  5     select 1, 'test 2' , '20'  , 4 from dual union all
  6     select 1, 'empty'  , '0101', 5 from dual union all
  7     select 1, 'invalid', '1011', 6 from dual union all
  8     --
  9     select 4, 'test 9' , '30'  , 3 from dual union all
 10     select 4, 'empty'  , '1101', 5 from dual union all
 11     select 4, 'invalid', '1011', 6 from dual
 12    );

9 rows created.

SQL> select * From test;

        ID COL        VAL           REC_POS      EMPTY    INVALID
---------- ---------- ---------- ---------- ---------- ----------
         1 test 1     10                  1
         1 test 2     20                  2
         1 test 3     30                  3
         1 test 2     20                  4
         1 empty      0101                5
         1 invalid    1011                6
         4 test 9     30                  3
         4 empty      1101                5
         4 invalid    1011                6

9 rows selected.

SQL>

更新声明:

SQL> update test e set
  2    e.empty = (select nvl(x.digit, 0)
  3               from ( select t.id,
  4                             substr(t.val, column_value, 1) digit,
  5                             column_value rec_pos
  6                      from test t join
  7                           table(cast(multiset(select level from dual
  8                                               connect by level <= (select max(t1.rec_pos)
  9                                                                    from test t1
 10                                                                    where t1.id = t.id
 11                                                                   )
 12                                               ) as sys.odcinumberlist ))
 13                           on 1 = 1
 14                      where t.col = 'empty'
 15                     ) x
 16               where x.id = e.id
 17                 and x.rec_pos = e.rec_pos
 18              ),
 19    --
 20    e.invalid = (select nvl(x.digit, 0)
 21                 from ( select t.id,
 22                               substr(t.val, column_value, 1) digit,
 23                               column_value rec_pos
 24                        from test t join
 25                              table(cast(multiset(select level from dual
 26                                                  connect by level <= (select max(t1.rec_pos)
 27                                                                       from test t1
 28                                                                       where t1.id = t.id
 29                                                                      )
 30                                                  ) as sys.odcinumberlist ))
 31                             on 1 = 1
 32                        where t.col = 'invalid'
 33                       ) x
 34                 where x.id = e.id
 35                   and x.rec_pos = e.rec_pos
 36                );

9 rows updated.

SQL>

它是做什么的?

  • 获取VAL并将其拆分为行
  • (对于SUBSTR
  • 位置由该REC_POS的最大值ID确定,因此以后可以在更新NVL时使用EMPTY (或INVALID)列
  • 基本上,两个更新都是相同的,只是在您要更新的 (第14行和第32行)上有所不同

结果:

SQL> select * from test;

        ID COL        VAL           REC_POS      EMPTY    INVALID
---------- ---------- ---------- ---------- ---------- ----------
         1 test 1     10                  1          0          1
         1 test 2     20                  2          1          0
         1 test 3     30                  3          0          1
         1 test 2     20                  4          1          1
         1 empty      0101                5          0          0
         1 invalid    1011                6          0          0
         4 test 9     30                  3          0          1
         4 empty      1101                5          0          0
         4 invalid    1011                6          0          0

9 rows selected.

SQL>

答案 1 :(得分:2)

我认为这可以为您提供所需的输出。

SELECT  t.id,
    t.col,
    t.val,
    t.rec_pos,
    NVL(e.empty, 0) AS empty,
    NVL(i.invalid, 0) AS invalid
FROM
    table1 t
LEFT
JOIN    (SELECT DISTINCT t.id, levels.column_value AS rec_pos, SUBSTR(val, levels.column_value, 1) AS empty
     FROM table1 t, TABLE(CAST(MULTISET(SELECT level FROM dual CONNECT BY level <= LENGTH(val)) AS sys.OdciNumberList)) levels
     WHERE t.col = 'Empty' ORDER BY id) e ON e.id = t.id AND e.rec_pos = t.rec_pos
LEFT
JOIN    (SELECT DISTINCT t.id, levels.column_value AS rec_pos, SUBSTR(val, levels.column_value, 1) AS invalid
     FROM table1 t, TABLE(CAST(MULTISET(SELECT level FROM dual CONNECT BY level <= LENGTH(val)) AS sys.OdciNumberList)) levels
     WHERE t.col = 'Invalid' ORDER BY id) i ON i.id = t.id AND i.rec_pos = t.rec_pos
ORDER
BY  t.id, t.rec_pos;

答案 2 :(得分:2)

如果位置由rec_pos确定,那么您可以简单地将susbtr与分析性max结合使用:

select t.*, 
       nvl(substr(max(case col when 'Empty' then val end) 
                     over (partition by id), rec_pos, 1), 0) empty,
       nvl(substr(max(case col when 'Invalid' then val end) 
                     over (partition by id), rec_pos, 1), 0) invalid
  from  table1 t

或具有相关子查询:

select t.*, 
       nvl(substr((select val 
                    from table1 e 
                    where e.id = t.id and col= 'Empty'), rec_pos, 1), 0) empty,
       nvl(substr((select val 
                    from table1 i 
                    where i.id = t.id and col= 'Invalid'), rec_pos, 1), 0) invalid
  from  table1 t

dbfiddle demo

如果emptyinvald是表中的真实列,则对以上任何查询使用简单合并来更新它们。但是最好查看一列是由其他人的计算得出的结果。