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

我认为对于所有代码,可读性胜过字符数。