如何从两列之间的差异创建新列?

Posted

技术标签:

【中文标题】如何从两列之间的差异创建新列?【英文标题】:how to create new column from difference between two columns? 【发布时间】:2020-05-15 09:49:58 【问题描述】:

我使用 join、listagg 等创建新表。我使用 listagg 函数确定了如下两列。该列包含以下信息。

Listagg_1_Column | Listagg_2_Column
---------------- |-----------------
123,234,565,321  |  123,234

我想在此表中添加新列。新列包含 Listagg_1_Column 和 Listagg_2_Column 之间的差异,如下所示

New_Column
----------
565,321

为此,我使用了replace(Listagg_1_Column,Listagg_2_Column,'') 语句,但我检索到了错误的结果。如何通过更改查询来获取新列?任何帮助将不胜感激。提前致谢。

【问题讨论】:

比较 listagg 数据真的是解决您业务问题的最佳选择吗?创建一个只有前 2 个 listagg 列的数据集相交的第三个 listagg 列不是更容易吗?不确定该选项在您的情况下是否可行,但肯定会是一个更像“sql”的答案...... 您可以在查询中使用条件逻辑执行此操作,但您没有提供足够的信息来了解是否是这种情况。 我得到了我想要的结果。首先,我将其分为两部分,主要查询和两列之间的差异通过使用减法函数进行过滤。对找到的数据使用listagg函数,检索数据效果很好。 Koen Lostrie 的评论启发了我。感谢他的宝贵意见。 【参考方案1】:

我有测试数据:

CREATE TABLE data ( col1, col2 ) AS
SELECT '123,234,565,321', '123,234' FROM DUAL UNION ALL
SELECT '123,234,1123,2345', '123,234' FROM DUAL UNION ALL
SELECT '123,565,321,234', '123,234' FROM DUAL

然后您可以使用XMLTABLE 拆分字符串并使用MINUS 查找两组之间的差异并将结果整理到一个集合中,然后您可以聚合该集合:

SELECT col1,
       col2,
       ( SELECT LISTAGG( column_value, ',' ) WITHIN GROUP ( ORDER BY column_value )
         FROM   TABLE( d.new_col )
       ) AS new_col
FROM   (
  SELECT col1,
         col2,
         CAST(
           MULTISET(
             ( SELECT TO_NUMBER( column_value )
               FROM   XMLTABLE( ('"' || REPLACE( d.col1, ',', '","' ) || '"') )
               MINUS
               SELECT TO_NUMBER( column_value )
               FROM   XMLTABLE( ('"' || REPLACE( d.col2, ',', '","' ) || '"') )
             )
           ) AS SYS.ODCINUMBERLIST
         ) AS new_col
  FROM   data d
) d;

哪些输出:

COL1 | COL2 | NEW_COL :---------------- | :-------- | :-------- 123,234,565,321 | 123,234 | 321,565 123,234,1123,2345 | 123,234 | 1123,2345 123,565,321,234 | 123,234 | 321,565

db小提琴here

【讨论】:

【参考方案2】:

在这里我将两列转换为两个表。之后很容易找到差异。

with xxx
     as (select '123,565,321,234' listagg_1_column,
                '123,234' listagg_2_column
           from DUAL)
  select listagg_1_column,
         listagg_2_column,
         LISTAGG (myrow, ',') within group (order by myrow) diff
    from (    select REGEXP_SUBSTR (listagg_1_column,
                                    '[^,]+',
                                    1,
                                    LEVEL)
                        myrow,
                     listagg_1_column,
                     listagg_2_column
                from xxx
          connect by REGEXP_SUBSTR (listagg_1_column,
                                    '[^,]+',
                                    1,
                                    LEVEL)
                        is not null) xx
   where xx.myrow not in (    select REGEXP_SUBSTR (listagg_2_column,
                                                    '[^,]+',
                                                    1,
                                                    LEVEL)
                                        myrow
                                from xxx
                          connect by REGEXP_SUBSTR (listagg_2_column,
                                                    '[^,]+',
                                                    1,
                                                    LEVEL)
                                        is not null)
group by listagg_1_column, listagg_2_column

上面的代码只适用于一个计数。这里是多记录的。

WITH data ( listagg_1_column, listagg_2_column ) 
     AS (SELECT '123,234,565,321', 
                '123,234' 
         FROM   dual 
         UNION ALL 
         SELECT '123,234,1123,2345', 
                '123,234' 
         FROM   dual 
         UNION ALL 
         SELECT '123,565,321,234', 
                '123,234' 
         FROM   dual 
         UNION ALL 
         SELECT '123,565,321,234', 
                '321,565' 
         FROM   dual) 
SELECT listagg_1_column, 
       listagg_2_column, 
       Listagg (myrow, ',') 
         within GROUP (ORDER BY myrow ) diff 
FROM   (SELECT DISTINCT Regexp_substr (xx.listagg_1_column, '+[^,]+', 1, LEVEL) 
                        myrow, 
                        xx.listagg_1_column, 
                        xx.listagg_2_column, 
                        Regexp_count (listagg_1_column, '[^,]+') 
                        a, 
                        LEVEL 
        FROM   data xx 
        CONNECT BY Regexp_count (listagg_1_column, '[^,]+') >= LEVEL 
        ORDER  BY listagg_1_column, 
                  LEVEL)xx 
WHERE  xx.myrow NOT IN (SELECT Regexp_substr (yy.listagg_2_column, '[^,]+', 1, 
                               LEVEL) 
                               myrow 
                        FROM   data yy 
                        WHERE  XX.listagg_1_column = YY.listagg_1_column 
                               AND XX.listagg_2_column = YY.listagg_2_column 
                        CONNECT BY Regexp_count (yy.listagg_2_column, '[^,]+') 
                                   >= LEVEL 
                              ) 
GROUP  BY listagg_1_column, 
          listagg_2_column 

db小提琴here

【讨论】:

这并不总是像你期望的那样工作db<>fiddle。 你是对的。谢谢分享。我想我已经修好了。但我无法解释我该怎么做。我的大脑一片空白。

以上是关于如何从两列之间的差异创建新列?的主要内容,如果未能解决你的问题,请参考以下文章

SQL查询从两列中检索两个日期之间的数据

如何找到两列数据之间的差异?

使用每列的选择性聚合从两列创建 SQL 值

如何在sql中将两列连接成一个新列?

如何计算Python Pandas中两列之间的日期差异[重复]

如果两列是 1 则创建新列