【问题标题】:Recursive Self Query With Associated Tables (SQL Server)具有关联表的递归自查询 (SQL Server)
【发布时间】:2015-08-23 23:38:59
【问题描述】:

鉴于以下结构和数据,我正在寻找制造商发生变化的客户加入:

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 容易得多。

谢谢!

【问题讨论】:

  • 如果客户不止一次更换制造商怎么办。预期的结果是什么?另外,到目前为止,您尝试过什么 SQL?
  • @sstan 如果他们多次切换,它将显示为另一条记录。到目前为止,我认为我的 SQL 毫无价值。我正在考虑做几个派生表并加入它们以按客户显示所有不同的制造商和日期(最多 10 个不同的制造商更改,例如 102 | 制造商 1 | 2015 年 6 月 1 日 | 制造商 2 | 1/1 /2015)。这并不理想,但递归部分对我构成挑战,因为它不是我的强项。

标签: sql sql-server join recursive-query


【解决方案1】:

这是使用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

SQLFiddle

【讨论】:

  • LAG() 绝对是更好的选择。
  • 感谢 sstan 的回答。我已经接受了另一个答案,但我给了你一个赞成票。很高兴尝试 LAG,然后发现它在 SQLAzure 中不受支持......真可惜。
  • 很抱歉听到这个消息。很高兴你也得到了一个“无滞后”的解决方案:)
【解决方案2】:

查询

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 ║
╚════════════╩═══════════════════════╩══════════════════╩════════════╝

【讨论】:

    猜你喜欢
    • 2017-08-14
    • 2014-12-19
    • 2012-12-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多