Tsql 如何识别客户列表随时间的变化

Tsql 如何识别客户列表随时间的变化,tsql,Tsql,我有一批客户,他们经常变动。每次队列更改时,新客户的完整转储都会附加到表中,并给出一个新的列表名。Alpha、Beta、Gamma等。每个列表通常会添加一些客户,删除一些客户,并保留一些客户。我试图创建一个简单的瀑布图来显示列表之间的变化。通常,我只需要完全外部加入AlphaBeta,然后完全外部加入Betagama等,以获得留下、离开和加入的客户。但是列表的版本正在增长,我想知道是否有一种更简单的方法来完成这个计算,而不是每次添加新列表时都要编辑它。我无法更改此过程,因为它支持旧系统,并且由其

我有一批客户,他们经常变动。每次队列更改时,新客户的完整转储都会附加到表中,并给出一个新的列表名。Alpha、Beta、Gamma等。每个列表通常会添加一些客户,删除一些客户,并保留一些客户。我试图创建一个简单的瀑布图来显示列表之间的变化。通常,我只需要完全外部加入AlphaBeta,然后完全外部加入Betagama等,以获得留下、离开和加入的客户。但是列表的版本正在增长,我想知道是否有一种更简单的方法来完成这个计算,而不是每次添加新列表时都要编辑它。我无法更改此过程,因为它支持旧系统,并且由其他部门控制。想法

编辑:Sql Server 2016 SP2

CREATE TABLE #customers(cust_id int, list_name varchar(10), create_dt date)
INSERT INTO #customers values (1,'Alpha','2019-01-01')
    ,(2,'Alpha','2019-01-01')
    ,(3,'Alpha','2019-01-01')
    ,(4,'Alpha','2019-01-01')
    ,(5,'Alpha','2019-01-01')
    ,(2,'Beta','2019-03-01')
    ,(3,'Beta','2019-03-01')
    ,(4,'Beta','2019-03-01')
    ,(5,'Beta','2019-03-01')
    ,(6,'Beta','2019-03-01')
    ,(7,'Beta','2019-03-01')
    ,(1,'Gamma','2019-05-05')
    ,(6,'Gamma','2019-05-05')
    ,(7,'Gamma','2019-05-05')
    ,(9,'Gamma','2019-05-05')

--Desired Output (long way that needs to be edited every time there is a new list)
SELECT List_Name, 'Starting' Descrip, count(*) Custs FROM #customers WHERE list_name = 'alpha' group by list_name
UNION ALL
SELECT List_Name, 'Add', count(*) FROM #customers a WHERE list_name = 'Beta' AND not exists(SELECT * FROM #customers x WHERE List_Name = 'Alpha' AND a.cust_id = x.cust_id) GROUP BY List_Name
UNION ALL
SELECT 'Beta', 'Remove', -count(*) FROM #customers a WHERE list_name = 'Alpha' AND not exists(SELECT * FROM #customers x WHERE List_Name = 'Beta' AND a.cust_id = x.cust_id) GROUP BY List_Name
UNION ALL
SELECT List_Name, 'Add', count(*) FROM #customers a WHERE list_name = 'Gamma' AND not exists(SELECT * FROM #customers x WHERE List_Name = 'Beta' AND a.cust_id = x.cust_id) GROUP BY List_Name
UNION ALL
SELECT 'Gamma', 'Remove', -count(*) FROM #customers a WHERE list_name = 'Beta' AND not exists(SELECT * FROM #customers x WHERE List_Name = 'Gamma' AND a.cust_id = x.cust_id) GROUP BY List_Name

不必硬编码列表名称,您可以创建一个临时表来生成ID,然后将ID用作聚合的连接条件。这将允许您将列表添加到上一个列表中,而无需知道名称及其生成顺序

CREATE TABLE #customers(cust_id int, list_name varchar(10), list_date date)
INSERT INTO #customers
(
    cust_id
    ,list_name
    ,list_date
)
values (1,'Alpha', '01-01-2019')
    ,(2,'Alpha', '01-01-2019')
    ,(3,'Alpha', '01-01-2019')
    ,(4,'Alpha', '01-01-2019')
    ,(5,'Alpha', '01-01-2019')
    ,(2,'Beta', '02-01-2019')
    ,(3,'Beta', '02-01-2019')
    ,(4,'Beta', '02-01-2019')
    ,(5,'Beta', '02-01-2019')
    ,(6,'Beta', '02-01-2019')
    ,(7,'Beta', '02-01-2019')
    ,(1,'Gamma', '03-01-2019')
    ,(6,'Gamma', '03-01-2019')
    ,(7,'Gamma', '03-01-2019')
    ,(9,'Gamma', '03-01-2019')


CREATE TABLE #lists
(
    list_id INT IDENTITY(1,1)
    ,list_name varchar(10)
    ,Starting INT
    ,Added INT
    ,Removed INT
    ,list_date date
)

INSERT INTO #lists
(
    list_name
    ,Starting
    ,Added
    ,Removed
    ,list_date
)
SELECT DISTINCT 
    a.list_name 
    ,Starting = (SELECT COUNT(*) FROM #customers b WHERE b.list_name = a.list_name)
    ,Added = 0
    ,Removed = 0
    ,a.list_date
FROM #customers a
ORDER BY a.list_date ASC
现在使用此临时表创建另一个带有客户ID和列表ID的临时表。我这样做是为了不必一直写连接到链接列表名称和列表ID

SELECT c.cust_id
      ,l.list_id
INTO #ListCus
FROM #customers c
INNER JOIN #lists l ON l.list_name = c.list_name
接下来,您可以计算添加和删除的数字

UPDATE l 
SET l.Added = (SELECT COUNT(*) FROM #ListCus c1 WHERE c1.list_id = l.list_id AND NOT EXISTS (SELECT * FROM #ListCus x WHERE x.list_id = l.list_id-1 AND c1.cust_id = x.cust_id))
    ,l.Removed = (SELECT -COUNT(*) FROM #ListCus c1 WHERE c1.list_id = l.list_id-1 AND NOT EXISTS (SELECT * FROM #ListCus x WHERE x.list_id = l.list_id AND c1.cust_id = x.cust_id)) 
FROM #lists l
WHERE l.list_id > 1 --the first list won't have Added or Removed records
最后,我们通过取消提示并过滤掉不需要的描述符来格式化数据

;WITH unpivoted AS
(
    SELECT
        u.list_id
        ,u.Descrip
        ,u.custs
    FROM #lists l 
    UNPIVOT
    (
        custs 
        FOR Descrip IN (Starting, Added, Removed)
    )u
)
,SubResults AS
(
    SELECT u.list_id
          ,u.Descrip
          ,u.custs
    FROM unpivoted u 
    WHERE u.list_id = 1
        AND u.Descrip = 'Starting'

    UNION ALL

    SELECT u.list_id
          ,u.Descrip
          ,u.custs
    FROM unpivoted u 
    WHERE u.list_id <> 1
        AND u.Descrip <> 'Starting'
)
SELECT 
    l.list_name
    ,s.Descrip
    ,s.custs
FROM SubResults s
INNER JOIN #lists l ON l.list_id = s.list_id
ORDER BY s.list_id ASC, s.Descrip

好的,那么你可以把你的“列表”存储在一个文件夹中,然后执行以下操作。它不性感,但它会给你下面的输出。很明显,你可以根据自己的意愿选择*1

WITH lists (ListName, ListDate, PreceedingDate)
AS
(
    select distinct list_name, create_dt, PreceedingDate
    from #customers C1
        outer apply (select top 1 PreceedingDate = C3.create_dt
                     from #customers C3
                     where C3.create_dt < C1.create_dt
                     order by C3.create_dt desc) C3
)
select ListID = coalesce(lists.ListDate, CTE2.ListDate)
    , ListName = max(lists.ListName)
    , Added = SUM(IIF(C2.cust_id is null, 1, 0))
    , Removed = SUM(IIF(C1.cust_id is null and C2.cust_id is not null, 1, 0))
    , Remained = SUM(IIF(C2.cust_id = C1.cust_id, 1, 0))
from lists
    inner join #customers C1 on C1.create_dt = lists.ListDate
    full outer join #customers C2 on C1.cust_id = C2.cust_id
                                    and C2.create_dt = lists.PreceedingDate
    --since for removed customers the current List will be NULL
    --we join it back on, which leads to all those COALESCEs
    left join lists CTE2 on CTE2.PreceedingDate = C2.create_dt
where coalesce(lists.ListDate, CTE2.ListDate) is not null
group by coalesce(lists.ListDate, CTE2.ListDate)

您可以添加一个流程吗?您可以使用SQL Server中的MERGE命令将数据合并到不影响当前进程的新表中。其概念是将未出现在目标中的新记录添加到表中,而不再出现在源中的旧记录在表中已过时。最终得到的表基本上只记录了时间间隔之间的差异。您使用的是哪个版本的SQL Server?SQL Server 2016 SP2C能否为我们提供一个表定义和一些示例数据?是否需要为每个客户保留更改的历史记录?如果一个客户从队列中删除,它是否只是不包括在附加到表中的数据中?
ListID     | ListName | Added | Removed | Remained
-----------|----------|-------|---------|---------
2019-01-01 | Alpha    | 5     | 0       | 0
2019-03-01 | Beta     | 2     | 1       | 4
2019-05-05 | Gamma    | 2     | 4       | 2