我的桌子上有一些数据,如:
DAY | QTY | Name
1/1/2010 | 1 | jack
5/1/2010 | 5 | jack
2/1/2010 | 3 | wendy
5/1/2010 | 2 | wendy
我的目标是让SP请求一段时间(例如:'2010-1-1'到'2010-1-5'),并且没有差距。 输出示例:
DAY | QTY | Name
1/1/2010 | 1 | jack
2/1/2010 | 0 | jack
3/1/2010 | 0 | jack
4/1/2010 | 0 | jack
5/1/2010 | 5 | jack
1/1/2010 | 3 | wendy
2/1/2010 | 0 | wendy
3/1/2010 | 0 | wendy
4/1/2010 | 2 | wendy
5/1/2010 | 0 | wendy
任何差距都填充0- 我知道我可以创建一个循环来解决我的问题,但速度很慢。
有没有人有任何想法如何优化?
答案 0 :(得分:0)
这是另一种方式:
DECLARE @output TABLE (
DateValue datetime,
Qty varchar(50),
LastName varchar(25)
PRIMARY KEY (DateValue, LastName)
)
DECLARE @minMonth datetime, @maxMonth datetime, @lastName varchar(25)
-- whatever your business logic dictates for these
SET @minMonth = '01/01/2010'
SET @maxMonth = '12/01/2010';
with cte as (
SELECT @minMonth AS DateValue
UNION ALL
SELECT DATEADD(month, 1, DateValue)
FROM cte
WHERE DATEADD(month, 1, DateValue) <= @maxMonth
)
INSERT INTO @output (DateValue, Qty, LastName)
SELECT cte.DateValue,
ISNULL(tbl.Alias,0),
tbl.Name
FROM cte LEFT JOIN dbo.YourTable tbl ON tbl.[Day] = cte.Mth
UPDATE @output SET
LastName = CASE WHEN LastName IS NULL THEN @lastName ELSE LastName END,
@lastName = LastName
FROM @output
SELECT * FROM @output
答案 1 :(得分:0)
WITH DateRangeCTE([d]) AS
(
SELECT
CONVERT(DATETIME, '2010-01-01') AS [d]
UNION ALL
SELECT
DATEADD(d, 1, [d]) AS [d]
FROM
DateRangeCTE
WHERE [d] < DATEADD(d, -1, CONVERT(DATETIME, '2010-1-31'))
)
SELECT
DateRangeCTE.d, YourTable.Qty, YourTable.Name
FROM DateRangeCTE
LEFT JOIN YourTable ON DateRangeCTE.d = YourTable.DAY
如果您收到错误“语句已终止。在语句完成之前,最大递归100已用尽。”然后使用maxrecursion提示。
答案 2 :(得分:0)
如果您事先不知道日期范围,可以使用以下解决方案。它根据数据推导出日期范围。该解决方案使用数字表,该表使用master数据库中的现有表(spt_values)。
WITH MinMax AS
( SELECT DISTINCT [Name],
MIN([DAY]) OVER () AS min_day, MAX([DAY]) OVER () AS max_day
FROM mytable
)
, DateRange AS
( SELECT MinMax.[Name], DATEADD(mm, n.number, MinMax.min_day) AS [Date]
FROM MinMax
JOIN master.dbo.spt_values n ON n.type = 'P'
AND DATEADD(mm, n.number, MinMax.min_day) <= MinMax.max_day
)
SELECT dr.[Name], COALESCE(mt.[qty], 0) AS [QTY], dr.Date
FROM DateRange dr
LEFT OUTER JOIN MyTable mt ON dr.Name = mt.Name AND mt.Day = dr.Date
ORDER BY dr.Name, dr.Date ;
答案 3 :(得分:0)
我基于每个人的帮助离开了正确答案
-- dummy data
declare @table table
(
DAY datetime,
QTY int,
Name nvarchar (500) NULL
)
insert @table values('2010-1-1', 1, 'jack')
insert @table values('2010-1-3', 5, 'jack')
insert @table values('2010-1-2', 3 , 'wendy')
insert @table values('2010-1-6', 2 , 'wendy')
-- algorithm
DECLARE @output TABLE (
DAY datetime,
Qty int,
Name varchar(25)
)
DECLARE @minMonth datetime, @maxMonth datetime, @lastName varchar(25)
SET @minMonth = '2010-1-1'
SET @maxMonth = '2010-1-6';
WITH cte AS (
SELECT @minMonth AS DateValue
UNION ALL
SELECT DATEADD(day, 1, DateValue)
FROM cte
WHERE DATEADD(day, 1, DateValue) <= @maxMonth
)
INSERT INTO @output
SELECT
cte.DateValue,
ISNULL(tbl.qty,0),
tbl.Name
FROM
cte cross JOIN
@table tbl
update @output
set qty = 0
where cast(DAY as nvarchar)+'@'+cast(Qty as nvarchar)+'@'+Name in
(
select cast(DAY as nvarchar)+'@'+cast(Qty as nvarchar)+'@'+Name from @output
except
select cast(DAY as nvarchar)+'@'+cast(Qty as nvarchar)+'@'+Name from @table
)
SELECT DAY, sum(qty) as qty, Name
FROM @output
GROUP BY DAY, Name
order by 3,1
和我假装的输出
2010-01-01 00:00:00.000 1 jack
2010-01-02 00:00:00.000 0 jack
2010-01-03 00:00:00.000 5 jack
2010-01-04 00:00:00.000 0 jack
2010-01-05 00:00:00.000 0 jack
2010-01-06 00:00:00.000 0 jack
2010-01-01 00:00:00.000 0 wendy
2010-01-02 00:00:00.000 3 wendy
2010-01-03 00:00:00.000 0 wendy
2010-01-04 00:00:00.000 0 wendy
2010-01-05 00:00:00.000 0 wendy
2010-01-06 00:00:00.000 2 wendy
虽然解决方案是正确的,但由于递归限制,不适合我的需要。
希望这个脚本可以帮助任何有类似问题的人
谢谢大家