【问题标题】:Calculated column value based on rows above SQL基于 SQL 上面的行计算的列值
【发布时间】:2019-12-08 12:00:07
【问题描述】:

我的程序 db 中有这个愚蠢的表。程序不是我们的,所以无法更改表格内容。该表以不可读的代码存储类似 SQL 的表达式。我将这些值转换回 SQL 表达式以运行这些表达式。到目前为止,翻译部分进展顺利。到目前为止的结果是如下表:

+--------+--------+---------+----------------+-----------------+
| CODE   | SEQNUM | LOGICAL | EXPRESSION     | EXPRESSIONVALUE |
+--------+--------+---------+----------------+-----------------+
| A23000 | 1      | NULL    | OTHERCODE LIKE | 'A522%'         |
+--------+--------+---------+----------------+-----------------+
| A23000 | 2      | OR      | OTHERCODE =    | 'A62342'        |
+--------+--------+---------+----------------+-----------------+
| A23000 | 3      | OR      | OTHERCODE =    | 'A62343'        |
+--------+--------+---------+----------------+-----------------+
| B43000 | 1      | NULL    | OTHERCODE IN   | 'B34324'        |
+--------+--------+---------+----------------+-----------------+
| B43000 | 2      | NULL    | NULL           | 'B92338'        |
+--------+--------+---------+----------------+-----------------+
| B43000 | 3      | NULL    | NULL           | 'B92342'        |
+--------+--------+---------+----------------+-----------------+
| B43000 | 4      | NULL    | NULL           | 'B02349'        |
+--------+--------+---------+----------------+-----------------+
| B43000 | 5      | OR      | OTHERCODE =    | 'B32443'        |
+--------+--------+---------+----------------+-----------------+

或者为了让我有有效的 SQL 语句,我需要在有“in-expression”的行后面加上逗号。我认为这需要基于之前的行。我需要一张像这样的桌子:

+--------+--------+---------+----------------+-----------------+------------+
| CODE   | SEQNUM | LOGICAL | EXPRESSION     | EXPRESSIONVALUE | CALCULETED |
+--------+--------+---------+----------------+-----------------+------------+
| A23000 | 1      | NULL    | OTHERCODE LIKE | 'A522%'         | NULL       |
+--------+--------+---------+----------------+-----------------+------------+
| A23000 | 2      | OR      | OTHERCODE =    | 'A62342'        | NULL       |
+--------+--------+---------+----------------+-----------------+------------+
| A23000 | 3      | OR      | OTHERCODE =    | 'A62343'        | NULL       |
+--------+--------+---------+----------------+-----------------+------------+
| B43000 | 1      | NULL    | OTHERCODE IN   | 'B34324'        | ','        |
+--------+--------+---------+----------------+-----------------+------------+
| B43000 | 2      | NULL    | NULL           | 'B92338'        | ','        |
+--------+--------+---------+----------------+-----------------+------------+
| B43000 | 3      | NULL    | NULL           | 'B92342'        | ','        |
+--------+--------+---------+----------------+-----------------+------------+
| B43000 | 4      | NULL    | NULL           | 'B02349'        | NULL       |
+--------+--------+---------+----------------+-----------------+------------+
| B43000 | 5      | OR      | OTHERCODE =    | 'B32443'        | NULL       |
+--------+--------+---------+----------------+-----------------+------------+

这可能与 SQL 有关吗?

【问题讨论】:

    标签: sql oracle calculated-columns


    【解决方案1】:

    这会有帮助吗?

    SQL> with test (code, seqnum, logical, expression, value) as
      2    (select 'a23', 1, null, 'othercode like', 'a522%'  from dual union all
      3     select 'a23', 2, 'or', 'othercode ='   , 'a62342' from dual union all
      4     select 'a23', 3, 'or', 'othercode ='   , 'a62343' from dual union all
      5     --
      6     select 'b43', 1, null, 'othercode in'  , 'b34324' from dual union all
      7     select 'b43', 2, null, 'null'          , 'b92342' from dual union all
      8     select 'b43', 3, null, 'null'          , 'b02349' from dual union all
      9     select 'b43', 4, 'or', 'othercode ='   , 'b34243' from dual
     10    ),
     11  poc as
     12    -- SEQNUM where "IN" begins
     13   (select code, min(seqnum) minseq
     14    from test
     15    where expression = 'othercode in'
     16    group by code
     17    ),
     18  zav as
     19    -- SEQNUM where "IN" part ends
     20    (select t.code, max(t.seqnum) maxseq
     21     from test t join poc p on p.code = t.code
     22     where t.seqnum > p.minseq
     23       and t.expression <> 'null'
     24     group by t.code
     25    )
     26  select t.code, t.seqnum, t.logical, t.expression, t.value,
     27    case when t.seqnum >= p.minseq and t.seqnum < z.maxseq then ','
     28         else null
     29    end calc
     30  from test t left join poc p on p.code = t.code
     31              left join zav z on z.code = t.code
     32  order by code, seqnum;
    
    COD     SEQNUM LO EXPRESSION     VALUE   C
    --- ---------- -- -------------- ------- -
    a23          1    othercode like a522%
    a23          2 or othercode =    a62342
    a23          3 or othercode =    a62343
    b43          1    othercode in   b34324  ,
    b43          2    null           b92342  ,
    b43          3    null           b02349  ,
    b43          4 or othercode =    b342443
    
    7 rows selected.
    
    SQL>
    

    【讨论】:

      【解决方案2】:

      你可以用分析函数来做这个逻辑:

      select t.*,
             (case when coalesce(expression, lag(expression ignore nulls) over (partition by code order by seqnum)) like '% in' and
                        ((lead(logical) over (partition by code order by seqnum) is null and
                          lead(seqnum) over (partition by code order by seqnum) is not null
                         ) or
                         lead(seqnum) over (partition by code order by seqnum) is not null
                        )
                   then ','
              end) as calculated
      from test t;
      

      实现的逻辑标识与in 逻辑关联的行——即lag(ignore nulls)

      所有这些行都有一个逗号,最后一行除外。这很棘手,因为最后一行可能是表达式的结尾(code 的最后一行 seqnum)。或者,可能会出现一个新的布尔表达式。

      我添加了更多测试用例来证明这是可行的:

      • in 后面没有表达式。
      • in 列表中只有一个值。
      • 另一个表达式之前in

      Here 是数据库小提琴。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-03
        • 1970-01-01
        • 1970-01-01
        • 2022-06-14
        • 2018-01-13
        • 1970-01-01
        相关资源
        最近更新 更多