我有以下临时表:

CREATE TABLE #COMPANY_CHANGE 
        (       
        Risk_ID VARCHAR(50),
        LINKED_COMPANIES VARCHAR(MAX),
        PERIOD VARCHAR(20)

-- Populate the #COMPANY_CHANGE 
)

INSERT INTO #COMPANY_CHANGE (Risk_ID, LINKED_COMPANIES,PERIOD)
VALUES(1, 'X,y,z', 202202),
        (1, 'X,y', 202208),
        (2, 'A,B,C', 202202),
        (2, 'B,C,D', 202208),
      (4,'Z',202202),
      (4,'Z',202208) 

因此,对于每个Risk_ID,我try 比较起始时间段=202202和结束时间段=202208中的Linked_Companies,例如,对于Risk_ID=1,我们有3个公司链接在202202上,即X,y,z,但在结束时间段202208中,我们只有两个公司X,y,这意味着公司z已被移除

我想要的输出应该是这样的

Risk_ID  PERIOD   Change  Company_Added Company_Removed
1         202208   Yes       Null               z
2         202208   Yes       D                  A
4         202208   No        NUll               Null

下面是我的代码:

WITH CompanyChanges AS (
  SELECT
    RISK_ID,
    PERIOD,
    LINKED_COMPANIES,
    LAG(LINKED_COMPANIES) OVER (PARTITION BY RISK_ID ORDER BY PERIOD) AS PREVIOUS_LINKED_COMPANIES
  FROM COMPANY_CHANGE
)
SELECT
  RISK_ID,
  PERIOD,
  STRING_AGG(REPLACE(LINKED_COMPANIES, PREVIOUS_LINKED_COMPANIES, ''), ',') AS Change
FROM CompanyChanges
WHERE PREVIOUS_LINKED_COMPANIES IS NOT NULL AND PREVIOUS_LINKED_COMPANIES <> LINKED_COMPANIES
GROUP BY RISK_ID, PERIOD
ORDER BY RISK_ID, PERIOD;

推荐答案

这有点棘手,一个潜在的解决方案是:

WITH cte AS (
    SELECT  *
    ,   lag(linked_companies) OVER(partition BY risk_id ORDER BY period) AS prev_companies
    FROM    #COMPANY_CHANGE c
)
SELECT  risk_id, period
,   MAX(CASE WHEN a.value = prevvalue THEN 0 ELSE 1 END) AS changed
,   STRING_AGG(CASE WHEN a.value = a.prevvalue THEN NULL ELSE a.value END, ',') within GROUP (ORDER BY value) AS added
,   STRING_AGG(CASE WHEN a.value = a.prevvalue THEN NULL ELSE a.prevvalue END, ',') within GROUP (ORDER BY value) AS removed
FROM    cte
CROSS APPLY (
        SELECT  curr.value
        ,   prev.value AS prevValue
        FROM    STRING_SPLIT(LINKED_COMPANIES, ',') curr
        FULL JOIN STRING_SPLIT(prev_companies, ',') prev
            ON  prev.value = curr.value
    ) a
WHERE prev_companies IS NOT NULL --Remove period without history
GROUP BY risk_id, period

主要思想是使用FullJOIN来获取故事的双方,新添加和删除的.

通过使用STRING_SPLIT,我们每行得到一家公司.通过完全加入,如果删除了公司,则左侧为空,如果添加了公司,则右侧为空.

如果没有发生任何更改,则CASE WHEN a.value = a.prevvalue THEN NULL ELSE a.value END生成NULL,否则显示自上一行以来的增加值. CASE WHEN a.value = a.prevvalue THEN NULL ELSE a.prevvalue END执行相同的操作,但在值之间进行切换,并生成已移除的.

最后,我使用STRING_AGG将更改聚合回来.

输出:

risk_id period changed added removed
1 202208 1 NULL z
2 202208 1 D A
4 202208 0 NULL NULL

Sql相关问答推荐

SQL:创建查询以添加减少的总数

Microsoft Access UNION将长文本字段限制为255个字符

JSON列之间的Postgr聚合

有没有一种正确的方法来利用SQL UNION来从三个潜在查询中 Select 最大值?

在Golang中管理数据库事务的简洁方法

连接特定行号

使用CTE在SNOWFLAKE中创建临时表

Snowflake 中的分层数据

我可以在 T-SQL (SQL Server) 的函数内使用 OPTION 子句吗?

SQL 根据前一天的最大值计算每天的值数

如何优化仅返回符合条件的三条记录的查询?

如何通过CROSS APPLY获取多级嵌套JSON属性的值?

SQL 函数 DIFFERENCE 返回有趣的分数

在 BigQuery 数据集中查找表大小和占总数据集大小的百分比

如何更改 duckdb R 中的数据约束

具有关联统计信息 N+1 的 Rails 6 索引资源?

包含多行的 SQL 查询

如何在 Oracle 中获取此变量的值?

snowflake插入覆盖行为

在 UTF 编码字符上应用 SQL LIKE 语句没有给出任何结果