Sql server 如何在使用T-SQL的多列查询中使用填充0的计数表

Sql server 如何在使用T-SQL的多列查询中使用填充0的计数表,sql-server,tsql,Sql Server,Tsql,我在查询日期时使用了计数表来填充缺少的值,通常是0,效果很好,但我从来没有在查询多个计数时使用过它们 我有一个匆忙制作的示例表和查询 id Value Name Date 1 1 foo 2018-06-02 2 2 foo 2018-06-01 3 3 barr 2018-06-02 4 4 barr 2018-06-03 5 3 barr 2018-06-01 6

我在查询日期时使用了计数表来填充缺少的值,通常是0,效果很好,但我从来没有在查询多个计数时使用过它们

我有一个匆忙制作的示例表和查询

id  Value   Name    Date
1   1   foo         2018-06-02
2   2   foo         2018-06-01
3   3   barr        2018-06-02
4   4   barr        2018-06-03
5   3   barr        2018-06-01
6   2   foo         2018-06-05
7   3   barr        2018-06-01
8   4   barr        2018-06-10
9   5   fum         2018-06-07
10  2   barr        2018-06-02
我可以用一个计数表做一个右外连接,在那里我硬编码了barr的名字,这样我就可以提取出一个名字的相关数据。请注意,数字表是一个大的整数表

select  'barr' as Name,T2.Date,isnull(T1.Sum,0) as Sum

/* All records by date */
from
(
    select Name,Date,Sum(Value) as Sum
    from Test
    where Name='barr'
    group by Test.Date
) as T1

/* Tally table converted to date table.   This gives a list of all dates */
right outer join
(   
    select convert(date,DateAdd(day,number,'2018-6-1')) as Date
    from Numbers
    where Number < 7
) as T2
on T1.Date = T2.Date 
这是可行的,但我不想只过滤一个名字。我想我宁愿使用一个交叉连接来填充所有名字的空日。给出这样的结果:

foo 2018-06-01  2
foo 2018-06-02  1
foo 2018-06-03  0
foo 2018-06-04  0
foo 2018-06-05  2
foo 2018-06-06  0
foo 2018-06-07  0
barr    2018-06-01  6
barr    2018-06-02  5
barr    2018-06-03  4
barr    2018-06-04  0
barr    2018-06-05  0
barr    2018-06-06  0
barr    2018-06-07  0
fum 2018-06-01  0
fum 2018-06-02  0
fum 2018-06-03  0
fum 2018-06-04  0
fum 2018-06-05  0
fum 2018-06-06  0
fum 2018-06-07  5
我是否需要对不同的名称进行迭代并对每个名称进行并集,或者是否有方法使用完整/交叉连接,或者其他干净的tsql构造?

我会使用交叉连接

如果您有比从测试中的值计算更有效的其他DistinctNames源,则使用它

WITH Dates
     AS (SELECT CONVERT(DATE, DATEADD(day, number, '2018-6-1')) AS Date
         FROM   Numbers
         WHERE  Number < 7),
     DistinctNames
     AS (SELECT DISTINCT Name
         FROM   Test),
     Summed
     AS (SELECT Name,
                Date,
                SUM(Value) AS Sum
         FROM   Test
         GROUP  BY Test.Date,
                   Test.Name)
SELECT dn.Name,
       d.Date,
       isnull(s.Sum, 0) AS Sum
FROM   Dates d
       CROSS JOIN DistinctNames dn
       LEFT JOIN Summed s
              ON s.Name = dn.Name
                 AND s.Date = d.Date 

开箱即用…我离得太近了。这是非常接近我所需要的…和不同的名称是最好的,如果它来自我的日期范围。我的问题的标题很差,我想改进一下。我希望我能检查两个答案。参数化查询是我需要做的事情,因为它将在存储过程中结束+1表示合并。
WITH Dates
     AS (SELECT CONVERT(DATE, DATEADD(day, number, '2018-6-1')) AS Date
         FROM   Numbers
         WHERE  Number < 7),
     DistinctNames
     AS (SELECT DISTINCT Name
         FROM   Test),
     Summed
     AS (SELECT Name,
                Date,
                SUM(Value) AS Sum
         FROM   Test
         GROUP  BY Test.Date,
                   Test.Name)
SELECT dn.Name,
       d.Date,
       isnull(s.Sum, 0) AS Sum
FROM   Dates d
       CROSS JOIN DistinctNames dn
       LEFT JOIN Summed s
              ON s.Name = dn.Name
                 AND s.Date = d.Date 
-- Sample data.
declare @StartDate as Date = '2018-06-01';
declare @EndDate as Date = DateAdd( day, 6, @StartDate );
select @StartDate as 'StartDate', @EndDate as 'EndDate';

declare @Samples as Table ( Id Int Identity, Val Int, Name VarChar(10), SampleDate Date );
insert into @Samples ( Val, Name, SampleDate ) values
  ( 1, 'foo', '2018-06-02' ),
  ( 2, 'foo', '2018-06-01' ),
  ( 3, 'barr', '2018-06-02' ),
  ( 4, 'barr', '2018-06-03' ),
  ( 3, 'barr', '2018-06-01' ),
  ( 2, 'foo', '2018-06-05' ),
  ( 3, 'barr', '2018-06-01' ),
  ( 4, 'barr', '2018-06-10' ),
  ( 5, 'fum', '2018-06-07' ),
  ( 2, 'barr', '2018-06-02' );
select * from @Samples;

-- The query.
with
  -- All of the data summarized by   Name   and    SampleDate .
  GroupedData as (
    select Name, SampleDate, Sum( Val ) as Total
      from @Samples
      where @StartDate <= SampleDate and SampleDate <= @EndDate
      group by Name, SampleDate ),
  -- The range of dates to be reported.
  --   Use your existing   Numbers   table for better performance.
  Dates as (
    select @StartDate as ReportDate
    union all
    select DateAdd( day, 1, ReportDate )
      from Dates
      where ReportDate < @EndDate ),
  -- The following assumes that you don't want to include names that have no data for the date range.
  --   You may want to change it, e.g. to ignore only names without data in or prior to the date range.
  DistinctNames as (
    select distinct Name
      from @Samples
      where @StartDate <= SampleDate and SampleDate <= @EndDate )
  -- Combine the data.
  --   The   cross join   creates rows for every Name/Date pair.
  --   The   left outer join   and   coalesce   merge the data together.
  select Coalesce( GD.Name, DN.Name ) as Name,
    Coalesce( GD.SampleDate, D.ReportDate ) as SampleDate,
    Coalesce( Total, 0 ) as Total
    from DistinctNames as DN cross join
      Dates as D left outer join
      GroupedData as GD on GD.Name = DN.Name and GD.SampleDate = D.ReportDate
    order by Name, SampleDate;