SQL 服务器:强制汇总所有不同值的结果
SQL Server : force results for all distinct values in aggregate
我试图强制显示结果集中一列的不同值。换句话说,我希望任何不同的值都显示为零,而不是在给定组中没有值时丢弃。
比如我的数据大致如下:
ID |Quality | Date | Dollars
-------------------------------------
1 |Good | 02/28/15 | 1
2 |Better | 02/28/15 | 2
3 |Best | 02/28/15 | 3
4 |*Fair* | 02/28/15 | 1
1 |Good | 01/31/15 | 1
2 |Better | 01/31/15 | 2
3 |Best | 01/31/15 | 3
1 |Good | 12/31/15 | 1
3 |Best | 12/31/15 | 3
我加星号 "Fair" 以引起注意,因为它应该在结果集中产生一个不同的值 "fair"。但是,如果我按 "Date".
分组,"Fair" 将不会显示任何其他月份
我为解决问题所做的工作似乎比必要的要困难一些,但我无法弄清楚什么会更容易。我想 return "Dollars" 的总和 "Dollars" 来自这个 table.
的最近两个 "Dates" 的所有不同 "Quality" 结果
我做了以下事情:
declare @currdt date = '02/28/2015'
declare @prevdt date = DATEADD(d,-1,DATEADD(mm, DATEDIFF(m,0,@currdt),0)) --last day of month prior
declare @dates table (date1 date);
insert into @dates (date1) values (@currdt), (@prevdt);
with qualities (quality, date) as
(
select distinct quality, date1
from mytableA
join (select * from @dates) a on 1=1
),
history (ID, Quality, Add_Date, Dollars)
(
select ID, Quality, Add_Date, Dollars
from mytableA
where Add_Date <= @currdt
and Add_Date >= @prevdt
)
select
q.quality, q.date, sum(h.Dollars)
from
qualities q
left join
history h on h.quality = q.quality and h.date = q.date
group by
q.quality, q.date
基于上面显示的 table 的期望结果应如下所示:
Quality | Date | Dollars
------------------------------
Fair | 02/28/15 | 1
Good | 02/28/15 | 1
Better | 02/28/15 | 2
Best | 02/28/15 | 3
Fair | 01/31/15 | 0
Good | 01/31/15 | 1
Better | 01/31/15 | 2
Best | 01/31/15 | 3
我应该在给定的月份列出一些重复的品质以使总和更有趣,但希望这是清楚的。
如果您的目标只是减少查询长度,那么这应该相当于您现在拥有的(加上它输出两个日期的所有质量):
declare @currdt date = '02/28/2015'
declare @prevdt date = DATEADD(d,-1,DATEADD(mm, DATEDIFF(m,0,@currdt),0)) --last day of month prior
select a.quality, a.date, sum(isnull(b.Dollars,0)) as dollars
from (select quality, d.date from mytableA, (VALUES (@currdt), (@prevdt)) AS d(date) group by Quality, d.date) a
left join mytableA b on a.Date = b.date and a.Quality = b.Quality
group by a.quality, a.date
order by 2 desc, 3 asc
使用您的示例数据,这将输出:
quality date dollars
Fair 2015-02-28 1
Good 2015-02-28 1
Better 2015-02-28 2
Best 2015-02-28 3
Fair 2015-01-31 0
Good 2015-01-31 1
Better 2015-01-31 2
Best 2015-01-31 3
如果您想维持质量订单 (fair -> good -> better -> best
),您可以这样做:
select a.quality, a.date, sum(isnull(b.Dollars,0)) as sum
from (select quality, sort, date from
(values (1, 'Fair'), (2, 'Good'), (3, 'Better'), (4, 'Best')) as q(sort, quality),
(values (@currdt), (@prevdt)) as d(date) group by q.quality, d.date, sort) a
left join mytableA b on a.Date = b.date and a.Quality = b.Quality
group by a.quality, a.date, sort
order by date desc, sort
如果我没有另一个列出品质的 table,我会这样做:
DECLARE @Table TABLE
(
ID INT IDENTITY
,RateableItemID INT
,Quality VARCHAR(15)
,Date DATE
,Dollars MONEY
)
INSERT INTO @Table
(
RateableItemID
,Quality
,Date
,Dollars
)
VALUES
(1 ,'Good' , '02/28/15' , 1 )
,(2 ,'Better' , '02/28/15' , 2 )
,(3 ,'Best' , '02/28/15' , 3 )
,(4 ,'Fair' , '02/28/15' , 1 )
,(1 ,'Good' , '01/31/15' , 1 )
,(2 ,'Better' , '01/31/15' , 2 )
,(3 ,'Best' , '01/31/15' , 3 )
,(1 ,'Good' , '12/31/15' , 1 )
,(3 ,'Best' , '12/31/15' , 3 )
SELECT
TwoMostRecentDates.Date
,Qualities.Quality
,ISNULL(SUM(Details.Dollars),0) AS DollarsForThisDateAndQuality
FROM
(
SELECT DISTINCT TOP 2
Date
FROM
@Table
ORDER BY Date DESC
) TwoMostRecentDates
CROSS JOIN
(
SELECT DISTINCT
Quality
FROM @Table
) Qualities
LEFT JOIN
@Table Details
ON TwoMostRecentDates.Date = Details.Date
AND Qualities.Quality = Details.Quality
GROUP BY
TwoMostRecentDates.Date
,Qualities.Quality
ORDER BY
TwoMostRecentDates.Date
,CASE
Qualities.Quality
WHEN 'Best' THEN 1
WHEN 'Better' THEN 2
WHEN 'Good' THEN 3
WHEN 'Fair' THEN 4
END
我认为对于所有代码,可读性胜过字符数。
我试图强制显示结果集中一列的不同值。换句话说,我希望任何不同的值都显示为零,而不是在给定组中没有值时丢弃。
比如我的数据大致如下:
ID |Quality | Date | Dollars
-------------------------------------
1 |Good | 02/28/15 | 1
2 |Better | 02/28/15 | 2
3 |Best | 02/28/15 | 3
4 |*Fair* | 02/28/15 | 1
1 |Good | 01/31/15 | 1
2 |Better | 01/31/15 | 2
3 |Best | 01/31/15 | 3
1 |Good | 12/31/15 | 1
3 |Best | 12/31/15 | 3
我加星号 "Fair" 以引起注意,因为它应该在结果集中产生一个不同的值 "fair"。但是,如果我按 "Date".
分组,"Fair" 将不会显示任何其他月份我为解决问题所做的工作似乎比必要的要困难一些,但我无法弄清楚什么会更容易。我想 return "Dollars" 的总和 "Dollars" 来自这个 table.
的最近两个 "Dates" 的所有不同 "Quality" 结果我做了以下事情:
declare @currdt date = '02/28/2015'
declare @prevdt date = DATEADD(d,-1,DATEADD(mm, DATEDIFF(m,0,@currdt),0)) --last day of month prior
declare @dates table (date1 date);
insert into @dates (date1) values (@currdt), (@prevdt);
with qualities (quality, date) as
(
select distinct quality, date1
from mytableA
join (select * from @dates) a on 1=1
),
history (ID, Quality, Add_Date, Dollars)
(
select ID, Quality, Add_Date, Dollars
from mytableA
where Add_Date <= @currdt
and Add_Date >= @prevdt
)
select
q.quality, q.date, sum(h.Dollars)
from
qualities q
left join
history h on h.quality = q.quality and h.date = q.date
group by
q.quality, q.date
基于上面显示的 table 的期望结果应如下所示:
Quality | Date | Dollars
------------------------------
Fair | 02/28/15 | 1
Good | 02/28/15 | 1
Better | 02/28/15 | 2
Best | 02/28/15 | 3
Fair | 01/31/15 | 0
Good | 01/31/15 | 1
Better | 01/31/15 | 2
Best | 01/31/15 | 3
我应该在给定的月份列出一些重复的品质以使总和更有趣,但希望这是清楚的。
如果您的目标只是减少查询长度,那么这应该相当于您现在拥有的(加上它输出两个日期的所有质量):
declare @currdt date = '02/28/2015'
declare @prevdt date = DATEADD(d,-1,DATEADD(mm, DATEDIFF(m,0,@currdt),0)) --last day of month prior
select a.quality, a.date, sum(isnull(b.Dollars,0)) as dollars
from (select quality, d.date from mytableA, (VALUES (@currdt), (@prevdt)) AS d(date) group by Quality, d.date) a
left join mytableA b on a.Date = b.date and a.Quality = b.Quality
group by a.quality, a.date
order by 2 desc, 3 asc
使用您的示例数据,这将输出:
quality date dollars
Fair 2015-02-28 1
Good 2015-02-28 1
Better 2015-02-28 2
Best 2015-02-28 3
Fair 2015-01-31 0
Good 2015-01-31 1
Better 2015-01-31 2
Best 2015-01-31 3
如果您想维持质量订单 (fair -> good -> better -> best
),您可以这样做:
select a.quality, a.date, sum(isnull(b.Dollars,0)) as sum
from (select quality, sort, date from
(values (1, 'Fair'), (2, 'Good'), (3, 'Better'), (4, 'Best')) as q(sort, quality),
(values (@currdt), (@prevdt)) as d(date) group by q.quality, d.date, sort) a
left join mytableA b on a.Date = b.date and a.Quality = b.Quality
group by a.quality, a.date, sort
order by date desc, sort
如果我没有另一个列出品质的 table,我会这样做:
DECLARE @Table TABLE
(
ID INT IDENTITY
,RateableItemID INT
,Quality VARCHAR(15)
,Date DATE
,Dollars MONEY
)
INSERT INTO @Table
(
RateableItemID
,Quality
,Date
,Dollars
)
VALUES
(1 ,'Good' , '02/28/15' , 1 )
,(2 ,'Better' , '02/28/15' , 2 )
,(3 ,'Best' , '02/28/15' , 3 )
,(4 ,'Fair' , '02/28/15' , 1 )
,(1 ,'Good' , '01/31/15' , 1 )
,(2 ,'Better' , '01/31/15' , 2 )
,(3 ,'Best' , '01/31/15' , 3 )
,(1 ,'Good' , '12/31/15' , 1 )
,(3 ,'Best' , '12/31/15' , 3 )
SELECT
TwoMostRecentDates.Date
,Qualities.Quality
,ISNULL(SUM(Details.Dollars),0) AS DollarsForThisDateAndQuality
FROM
(
SELECT DISTINCT TOP 2
Date
FROM
@Table
ORDER BY Date DESC
) TwoMostRecentDates
CROSS JOIN
(
SELECT DISTINCT
Quality
FROM @Table
) Qualities
LEFT JOIN
@Table Details
ON TwoMostRecentDates.Date = Details.Date
AND Qualities.Quality = Details.Quality
GROUP BY
TwoMostRecentDates.Date
,Qualities.Quality
ORDER BY
TwoMostRecentDates.Date
,CASE
Qualities.Quality
WHEN 'Best' THEN 1
WHEN 'Better' THEN 2
WHEN 'Good' THEN 3
WHEN 'Fair' THEN 4
END
我认为对于所有代码,可读性胜过字符数。