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;
- 编辑,为了完整性添加了总计:)
对于定义的问题以及您从样本数据中了解的年份 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
我正在尝试从订单 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;
- 编辑,为了完整性添加了总计:)
对于定义的问题以及您从样本数据中了解的年份 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 |