SQL группировка и итоговое количество открытых позиций за диапазон дат - PullRequest
4 голосов
/ 13 июля 2011

У меня есть таблица предметов, которая для простоты содержит ItemID, StartDate и EndDate для списка предметов.

ItemID     StartDate     EndDate
1          1/1/2011      1/15/2011
2          1/2/2011      1/14/2011
3          1/5/2011      1/17/2011
...

Моя цель - присоединиться к этой таблице к таблице с последовательным списком дат, и скажите, сколько элементов открыто на определенную дату, а также, сколько элементов кумулятивно открыто.

Date      ItemsOpened     CumulativeItemsOpen
1/1/2011  1               1
1/2/2011  1               2
...

Я вижу, как это можно сделать с помощью цикла WHILE, но это влияет на производительность. Мне интересно как это можно сделать с помощью подхода, основанного на множестве?

Ответы [ 4 ]

2 голосов
/ 13 июля 2011

Вы можете найти это полезным.Реквизивную часть можно заменить на стол.Чтобы продемонстрировать, что это работает, мне нужно было заполнить какую-то таблицу дат.Как видите, фактический sql короткий и простой.

DECLARE @i table (itemid INT, startdate DATE, enddate DATE)

INSERT @i VALUES (1,'1/1/2011', '1/15/2011') 
INSERT @i VALUES (2,'1/2/2011', '1/14/2011')
INSERT @i VALUES (3,'1/5/2011', '1/17/2011') 

DECLARE @from DATE
DECLARE @to DATE
SET @from = '1/1/2011'
SET @to = '1/18/2011'

-- the recusive sql is strictly to make a datelist between @from and @to
;WITH cte(Date) 
AS ( 
SELECT @from DATE 
UNION ALL 
SELECT DATEADD(day, 1, DATE) 
FROM cte ch     
WHERE DATE < @to 
) 
SELECT cte.Date, sum(case when cte.Date=i.startdate then 1 else 0 end) ItemsOpened, count(i.itemid) ItemsOpenedCumulative 
FROM cte 
left join @i i on cte.Date between i.startdate and i.enddate
GROUP BY cte.Date
OPTION( MAXRECURSION 0)
2 голосов
/ 13 июля 2011
SELECT COUNT(CASE WHEN d.CheckDate = i.StartDate THEN 1 ELSE NULL END)
         AS ItemsOpened
     , COUNT(i.StartDate)
         AS ItemsOpenedCumulative
FROM Dates AS d
  LEFT JOIN Items AS i
    ON d.CheckDate BETWEEN i.StartDate AND i.EndDate
GROUP BY d.CheckDate
2 голосов
/ 13 июля 2011

Это может дать вам то, что вы хотите

SELECT DATE, 
    SUM(ItemOpened) AS ItemsOpened, 
    COUNT(StartDate) AS ItemsOpenedCumulative
FROM
    (
    SELECT d.Date, i.startdate, i.enddate,
        CASE WHEN i.StartDate = d.Date THEN 1 ELSE 0 END AS ItemOpened
    FROM Dates d
    LEFT OUTER JOIN Items i ON d.Date BETWEEN i.StartDate AND i.EndDate
    ) AS x
GROUP BY DATE
ORDER BY DATE

Это предполагает, что ваши значения даты имеют тип данных DATE.Или даты - DATETIME без значений времени.

0 голосов
/ 13 июля 2011

Если вы используете SQL Server 2005+, вы можете использовать рекурсив CTE для получения промежуточных итогов с дополнительной помощью функции rating ROW_NUMBER(), вот так:

WITH grouped AS (
  SELECT
    d.Date,
    ItemsOpened = COUNT(i.ItemID),
    rn = ROW_NUMBER() OVER (ORDER BY d.Date)
  FROM Dates d
    LEFT JOIN Items i ON d.Date BETWEEN i.StartDate AND i.EndDate
  GROUP BY d.Date
  WHERE d.Date BETWEEN @FilterStartDate AND @FilterEndDate
),
cumulative AS (
  SELECT
    Date,
    ItemsOpened,
    ItemsOpenedCumulative = ItemsOpened
  FROM grouped
  WHERE rn = 1
  UNION ALL
  SELECT
    g.Date,
    g.ItemsOpened,
    ItemsOpenedCumulative = g.ItemsOpenedCumulative + c.ItemsOpened
  FROM grouped g
    INNER JOIN cumulative c ON g.Date = DATEADD(day, 1, c.Date)
)
SELECT *
FROM cumulative
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...