关联表的递归自查询(SQL 服务器)
Recursive Self Query With Associated Tables (SQL Server)
鉴于以下结构和数据,我正在寻找制造商已更改的客户加入:
create table #sale (
saleid int,
customerid int,
productid int,
saledate date
);
create table #product (
productId int,
name varchar(max),
manufacturerId int
);
create table #manufacturer (
manufacturerid int,
name varchar(max)
)
insert into #manufacturer values (1, 'Manufacturer 1');
insert into #manufacturer values (2, 'Manufacturer 2');
insert into #product values (1, 'Product A', 1);
insert into #product values (2, 'Product B', 1);
insert into #product values (3, 'Product C', 2);
insert into #sale values (1, 101, 1, '2013-01-01');
insert into #sale values (2, 101, 2, '2015-04-01');
insert into #sale values (3, 102, 3, '2013-03-01');
insert into #sale values (4, 102, 3, '2015-01-01');
insert into #sale values (5, 103, 1, '2013-01-01');
insert into #sale values (6, 103, 3, '2015-06-01');
insert into #sale values (7, 102, 1, '2015-06-01');
在这种情况下,两个客户换用了不同制造商的产品,理想的结果是这样的:
customerid previous manufacturer new manufacturer date
102 Manufacturer 2 Manufacturer 1 6/1/2015
103 Manufacturer 1 Manufacturer 2 6/1/2015
我一直在尝试使用 CTE,但没有成功。欣赏和见解或指导。
更新 - 我可以忍受在 customerid 上横向扩展一定数量的连接以显示不同的制造商和日期(5-10 个连接)。对我来说,这比使用 CTE 尝试 UNION ALL 容易得多。
谢谢!
查询
WITH X AS
(
SELECT s.*
,M.manufacturerid
,m.name
,ROW_NUMBER() OVER (PARTITION BY s.CustomerID
ORDER BY saledate ASC) rn
FROM #sale s
INNER JOIN #product p ON s.productid = p.productId
INNER JOIN #manufacturer m ON p.manufacturerId = m.manufacturerid
)
SELECT xx.customerid
,xy.name [previous manufacturer]
,xx.name [new manufacturer]
,xx.saledate [Date]
FROM x xy
INNER JOIN x xx ON xx.customerid = xy.customerid
AND xx.rn = xy.rn + 1
AND xx.manufacturerid <> xy.manufacturerid
结果:
╔════════════╦═══════════════════════╦══════════════════╦════════════╗
║ customerid ║ previous manufacturer ║ new manufacturer ║ Date ║
╠════════════╬═══════════════════════╬══════════════════╬════════════╣
║ 102 ║ Manufacturer 2 ║ Manufacturer 1 ║ 2015-06-01 ║
║ 103 ║ Manufacturer 1 ║ Manufacturer 2 ║ 2015-06-01 ║
╚════════════╩═══════════════════════╩══════════════════╩════════════╝
这是使用 LAG
的替代方法:
select customerid,
[previous manufacturer],
[new manufacturer],
saledate
from (
select s.customerid,
m.name as [new manufacturer],
s.saledate,
lag(m.name) over (partition by s.customerid order by s.saledate) as [previous manufacturer],
case when
lag(m.manufacturerId) over (partition by s.customerid order by s.saledate) is not null
and lag(m.manufacturerId) over (partition by s.customerid order by s.saledate) <> m.manufacturerId
then 1 else 0
end as is_manufacturer_change
from sale s
join product p on p.productid = s.productid
join manufacturer m on m.manufacturerid = p.manufacturerid) x
where x.is_manufacturer_change = 1
order by customerid, saledate
鉴于以下结构和数据,我正在寻找制造商已更改的客户加入:
create table #sale (
saleid int,
customerid int,
productid int,
saledate date
);
create table #product (
productId int,
name varchar(max),
manufacturerId int
);
create table #manufacturer (
manufacturerid int,
name varchar(max)
)
insert into #manufacturer values (1, 'Manufacturer 1');
insert into #manufacturer values (2, 'Manufacturer 2');
insert into #product values (1, 'Product A', 1);
insert into #product values (2, 'Product B', 1);
insert into #product values (3, 'Product C', 2);
insert into #sale values (1, 101, 1, '2013-01-01');
insert into #sale values (2, 101, 2, '2015-04-01');
insert into #sale values (3, 102, 3, '2013-03-01');
insert into #sale values (4, 102, 3, '2015-01-01');
insert into #sale values (5, 103, 1, '2013-01-01');
insert into #sale values (6, 103, 3, '2015-06-01');
insert into #sale values (7, 102, 1, '2015-06-01');
在这种情况下,两个客户换用了不同制造商的产品,理想的结果是这样的:
customerid previous manufacturer new manufacturer date
102 Manufacturer 2 Manufacturer 1 6/1/2015
103 Manufacturer 1 Manufacturer 2 6/1/2015
我一直在尝试使用 CTE,但没有成功。欣赏和见解或指导。
更新 - 我可以忍受在 customerid 上横向扩展一定数量的连接以显示不同的制造商和日期(5-10 个连接)。对我来说,这比使用 CTE 尝试 UNION ALL 容易得多。
谢谢!
查询
WITH X AS
(
SELECT s.*
,M.manufacturerid
,m.name
,ROW_NUMBER() OVER (PARTITION BY s.CustomerID
ORDER BY saledate ASC) rn
FROM #sale s
INNER JOIN #product p ON s.productid = p.productId
INNER JOIN #manufacturer m ON p.manufacturerId = m.manufacturerid
)
SELECT xx.customerid
,xy.name [previous manufacturer]
,xx.name [new manufacturer]
,xx.saledate [Date]
FROM x xy
INNER JOIN x xx ON xx.customerid = xy.customerid
AND xx.rn = xy.rn + 1
AND xx.manufacturerid <> xy.manufacturerid
结果:
╔════════════╦═══════════════════════╦══════════════════╦════════════╗
║ customerid ║ previous manufacturer ║ new manufacturer ║ Date ║
╠════════════╬═══════════════════════╬══════════════════╬════════════╣
║ 102 ║ Manufacturer 2 ║ Manufacturer 1 ║ 2015-06-01 ║
║ 103 ║ Manufacturer 1 ║ Manufacturer 2 ║ 2015-06-01 ║
╚════════════╩═══════════════════════╩══════════════════╩════════════╝
这是使用 LAG
的替代方法:
select customerid,
[previous manufacturer],
[new manufacturer],
saledate
from (
select s.customerid,
m.name as [new manufacturer],
s.saledate,
lag(m.name) over (partition by s.customerid order by s.saledate) as [previous manufacturer],
case when
lag(m.manufacturerId) over (partition by s.customerid order by s.saledate) is not null
and lag(m.manufacturerId) over (partition by s.customerid order by s.saledate) <> m.manufacturerId
then 1 else 0
end as is_manufacturer_change
from sale s
join product p on p.productid = s.productid
join manufacturer m on m.manufacturerid = p.manufacturerid) x
where x.is_manufacturer_change = 1
order by customerid, saledate