T-SQL между промежутками между периодами - PullRequest
0 голосов
/ 07 октября 2010

У меня есть некоторые данные в моей таблице, такие как:

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 голосов
/ 12 октября 2010

Я оставляю правильный ответ, основанный на помощи каждого

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

Хотя решение правильное, оно не соответствует моим потребностям, потому что ограничение рекурсии

Надеюсь, этот скрипт поможет любому с похожими вопросами

Спасибо всем

0 голосов
/ 07 октября 2010
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.

0 голосов
/ 07 октября 2010

Вот решение, которое вы можете использовать, если заранее не знаете диапазон дат. Он выводит диапазон дат на основе данных. В решении используется таблица чисел, которая использует существующую таблицу в базе данных 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 ;
0 голосов
/ 07 октября 2010

Вот еще один способ:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...