期间间隙的T-SQL

时间:2010-10-06 21:58:54

标签: sql sql-server-2005 tsql

我的桌子上有一些数据,如:

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- 我知道我可以创建一个循环来解决我的问题,但速度很慢。

有没有人有任何想法如何优化?

4 个答案:

答案 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

虽然解决方案是正确的,但由于递归限制,不适合我的需要。

希望这个脚本可以帮助任何有类似问题的人

谢谢大家