Sql server 如何在使用T-SQL的多列查询中使用填充0的计数表
我在查询日期时使用了计数表来填充缺少的值,通常是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
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;