T-SQL:如何return 为从相同table 中选择的不同日期范围分隔数据列?

T-SQL: How to return separate columns of data for different date ranges selected from same table?

我正在尝试从订单 table 中按范围获取客户支出数据,但脚本似乎总是将每个客户 ID 的所有 table 行组合在一起,无论我如何尝试指定日期范围。非常感谢任何关于如何在这里实现我的目标的指导。

EX:

CREATE TABLE customers 
(
    idCustomer INT IDENTITY(100,1),
    name VARCHAR(100),
    PRIMARY KEY (idCustomer)
);

INSERT INTO customers 
VALUES ('Bob'), ('Barb');

CREATE TABLE orders 
(
    idOrder INT IDENTITY(1,1),
    idCustomer INT,
    orderTotal DECIMAL(19,2),
    orderDate DATETIME2
    PRIMARY KEY (idOrder)
);

INSERT INTO orders 
VALUES (100, 25.25, '2018-4-15'),
       (100, 37.00, '2018-6-15'),
       (100, 175.00, '2019-3-1'),
       (100, 232.33, '2019-8-3'),
       (101, 18.56, '2018-1-17'),
       (101, 3004.50, '2018-5-12'),
       (101, 2.98, '2019-6-1'),
       (101, 15.00, '2019-11-3')

SELECT
    c.idCustomer,
    c.name,
    COUNT(ord2018.idOrder) AS '#Orders 2018',
    SUM(ord2018.orderTotal) AS 'Total Spent 2018'
    COUNT(ord2019.idOrder) AS '#Orders 2019',
    SUM(ord2019.orderTotal) AS 'Total Spent 2019'
    COUNT(ordersAll.idOrder) AS '#Orders Lifetime',
    SUM(ordersAll.orderTotal) AS 'Total Spent Lifetime'
FROM 
    customers c
JOIN 
    orders ord2018 ON ord2018.idCustomer = c.idCustomer 
                   AND ord2018.orderDate > '2017-12-31'
                   AND ord2018.orderDate < '2019-1-1'
JOIN 
    orders ord2019 ON ord2019.idCustomer = c.idCustomer
                   AND ord2019.orderDate > '2018-12-31'
                   AND ord2019.orderDate < '2020-1-1'
JOIN
    orders ordersAll on ordersAll.idCustomer = c.idCustomer
GROUP BY 
    c.idCustomer, c.name

我想看这样的东西:

idCustomer Name #Orders 2018 Total Spent 2018 #Orders 2019 Total Spent 2019 #Orders Lifetime Total Spent Lifetime
100 Bob 2 62.25 2 407.33 4 469.58
101 Barb 2 3023.06 2 17.98 4 3041.04

但我在总计列中得到重复值,这些值似乎只是每个客户订单 table 中所有记录的总和。

提前致谢。

对于您的 提供的示例数据 并考虑您的示例查询尝试,您可以将条件总和与 apply 结合使用。

select * 
from customers c
outer apply (
    select 
      IsNull(Sum(case when Year(orderdate) = 2018 then 1 end),0) [#Orders2018],
      IsNull(Sum(case when Year(orderdate) = 2018 then ordertotal end),0) [Total spent 2018],
      IsNull(Sum(case when Year(orderdate) = 2019 then 1 end),0) [#Orders2019],
      IsNull(Sum(case when Year(orderdate) = 2019 then ordertotal end),0) [Total spent 2019],
      Count(*) TotalOrders,
      Sum(Ordertotal) TotalSpend
    from orders o
    where o.idCustomer = c.idCustomer
)o;

Example DB<>Fiddle

  • 编辑,为了完整性添加了总计:)

对于定义的问题以及您从样本数据中了解的年份 hard-coded:

;WITH agg AS
(
  SELECT idCustomer, y = YEAR(orderDate), 
    OrderCount = COUNT(*), 
    TotalSpent = COALESCE(SUM(orderTotal),0)
  FROM dbo.orders
  GROUP BY idCustomer, DATEPART(YEAR, orderDate)
)
SELECT agg.idCustomer, c.name,
  OrderCount2018 = MAX(CASE WHEN y = 2018 THEN OrderCount END),
  TotalSpent2018 = MAX(CASE WHEN y = 2018 THEN TotalSpent END),
  OrderCount2019 = MAX(CASE WHEN y = 2019 THEN OrderCount END),
  TotalSpent2019 = MAX(CASE WHEN y = 2019 THEN TotalSpent END),
  LifetimeCount  = SUM(OrderCount),
  LifetimeSpent  = SUM(TotalSpent)
FROM agg
INNER JOIN dbo.customers AS c
  ON c.idCustomer = agg.idCustomer
GROUP BY agg.idCustomer, c.name;

但是您希望查询是动态的,所以您不能 hard-coding 年和列名。要动态执行此操作:

DECLARE @MinYear int, @MaxYear int;

SELECT @MinYear = MIN(YEAR(orderDate)), @MaxYear = MAX(YEAR(orderDate))
  FROM dbo.orders;
  
DECLARE @sql nvarchar(max) = N';WITH agg AS
(
  SELECT idCustomer, y = YEAR(orderDate), 
    OrderCount = COUNT(*), 
    TotalSpent = COALESCE(SUM(orderTotal),0)
  FROM dbo.orders
  GROUP BY idCustomer, DATEPART(YEAR, orderDate)
)
SELECT agg.idCustomer, c.name';

;WITH y(y) AS (SELECT @MinYear UNION ALL
  SELECT y+1 FROM y WHERE y < @MaxYear),
  z(y) AS (SELECT CONVERT(char(4), y) FROM y)
 SELECT @sql += N',
  OrderCount' + y + N' = MAX(CASE WHEN y = ' + y + N' THEN OrderCount END),
  TotalSpent' + y + N' = MAX(CASE WHEN y = ' + y + N' THEN TotalSpent END)'
 FROM z;
  
SET @sql += N',
  LifetimeCount  = SUM(OrderCount),
  LifetimeSpent  = SUM(TotalSpent)
FROM agg
INNER JOIN dbo.customers AS c
  ON c.idCustomer = agg.idCustomer
GROUP BY agg.idCustomer, c.name;';

SELECT @sql;
EXEC sys.sp_executesql @sql;

两种情况下的输出:

idCustomer name OrderCount2018 TotalSpent2018 OrderCount2019 TotalSpent2019 LifetimeCount LifetimeSpent
100 Bob 2 62.25 2 407.33 4 469.58
101 Barb 2 3023.06 2 17.98 4 3041.04