Выберите количество строк, имеющих определенное количество строк в связанной таблице - PullRequest
2 голосов
/ 30 декабря 2011

Так что я не совсем уверен, почему этот доставляет мне столько проблем этим утром.Я собираюсь записать это до утра пятницы.:) Цель состоит в том, чтобы посчитать по частоте количество объектов недвижимости за этот период, которые имеют ноль фотографий, три фотографии и шесть или более фотографий.Мне нужен набор результатов, который выглядит следующим образом ( ПРИМЕЧАНИЕ: три или более столбца НЕ должны включать в себя те, которые имеют ровно шесть - может быть максимум шесть фотографий ):

Period Start      Period End        Zero      ThreeOrMore     ExactlySix
------------------------------------------------------------------------
1/1/2011          1/7/2011          15        132             512
1/8/2011          1/14/2011         44        123             402

Я составил даты, у меня SQL действительно выводит правильные даты начала / окончания недели.

Моя таблица "Свойств" выглядит так:

PropertyRecId    Other fields
-----------------------------
12345            <blah>
56789            <blah>

Мой "PropertyPhotoТаблица выглядит следующим образом (включены только необходимые поля):

PropertyPhotoId   PropertyRecId     CreatedOn
---------------------------------------------
1                 12345             3/1/2011
2                 12345             3/1/2011
etc...

Я использую приведенный ниже запрос, но я не обязан его выполнять. Мне просто нужно достичь цели. Имейте в виду, чтос моим существующим запросом у меня нет доступа к записи «Propery» в моем выборе верхнего уровня. Я попытался опустить запросы вниз во вторичный выбор, где создаются PeriodStart и PeriodEnd, но это просто вызвало различные проблемы.

DECLARE @DateStart datetime
DECLARE @DateEnd datetime
SET @DateStart = '1/1/2011'
SET @DateEnd = '12/31/2011'

DECLARE @Frequency varchar(50)
SET @Frequency = 'month'

SELECT
PeriodStart,
PeriodEnd,
??? As Zero,
??? As ThreeOrMore,
??? As ExactlySix
FROM (
SELECT
PeriodStart = CASE @Frequency
WHEN 'day'     THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, CreatedOn))
WHEN 'week'    THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(DAY, 1 - DATEPART(WEEKDAY, CreatedOn), CreatedOn)))
WHEN 'month'   THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(MONTH,   DATEDIFF(MONTH,   0, CreatedOn), 0)))
WHEN 'quarter' THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(QUARTER, DATEDIFF(QUARTER, 0, CreatedOn), 0)))
WHEN 'year'    THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(YEAR,    DATEDIFF(YEAR,    0, CreatedOn), 0)))
END,
PeriodEnd   = CASE @Frequency
WHEN 'day'     THEN DATEADD(s, -1, DATEADD(day, 1, DATEDIFF(DAY, 0, CreatedOn)))
WHEN 'week'    THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, 7 - DATEPART(WEEKDAY, CreatedOn), CreatedOn))))
WHEN 'month'   THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, -1, DATEADD(MONTH,   DATEDIFF(MONTH,   0, CreatedOn) + 1, 0)))))
WHEN 'quarter' THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, -1, DATEADD(QUARTER, DATEDIFF(QUARTER, 0, CreatedOn) + 1, 0)))))
WHEN 'year'    THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, -1, DATEADD(YEAR,    DATEDIFF(YEAR,    0, CreatedOn) + 1, 0)))))
END     
FROM Property P
WHERE CreatedOn BETWEEN @DateStart AND @DateEnd
) s
GROUP BY
PeriodStart,
PeriodEnd
ORDER BY PeriodStart

Ответы [ 2 ]

4 голосов
/ 30 декабря 2011

Вы можете использовать функцию over в своем подзапросе, чтобы получить это, и операторы case в вашем внешнем выборе, чтобы добавить их:

DECLARE @Frequency varchar(50)
SET @Frequency = 'month'

SELECT
    PeriodStart,
    PeriodEnd,
    SUM(case when s.PhotoCount = 0 then 1 else 0 end) As Zero,
    SUM(case when s.PhotoCount between 3 and 5 then 1 else 0 end) As ThreeOrMore,
    SUM(case when s.PhotoCount = 6 then 1 else 0 end) As ExactlySix
FROM (
    SELECT
        PeriodStart = 
        CASE @Frequency
            WHEN 'day'     THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, CreatedOn))
            WHEN 'week'    THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(DAY, 1 - DATEPART(WEEKDAY, CreatedOn), CreatedOn)))
            WHEN 'month'   THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(MONTH,   DATEDIFF(MONTH,   0, CreatedOn), 0)))
            WHEN 'quarter' THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(QUARTER, DATEDIFF(QUARTER, 0, CreatedOn), 0)))
            WHEN 'year'    THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(YEAR,    DATEDIFF(YEAR,    0, CreatedOn), 0)))
        END,
        PeriodEnd   = 
        CASE @Frequency
            WHEN 'day'     THEN DATEADD(s, -1, DATEADD(day, 1, DATEDIFF(DAY, 0, CreatedOn)))
            WHEN 'week'    THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, 7 - DATEPART(WEEKDAY, CreatedOn), CreatedOn))))
            WHEN 'month'   THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, -1, DATEADD(MONTH,   DATEDIFF(MONTH,   0, CreatedOn) + 1, 0)))))
            WHEN 'quarter' THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, -1, DATEADD(QUARTER, DATEDIFF(QUARTER, 0, CreatedOn) + 1, 0)))))
            WHEN 'year'    THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, -1, DATEADD(YEAR,    DATEDIFF(YEAR,    0, CreatedOn) + 1, 0)))))
        END,
        p.PropertyRecId,
        COUNT(ph.PropertyPhotoId) over (partition by p.PropertyRecId) as PhotoCount
    FROM
        Property P
        left join PropertyPhoto ph on
            p.PropertyRecId = ph.PropertyRecId
    WHERE 
        CreatedOn BETWEEN @DateStart AND @DateEnd
) s
GROUP BY
    PeriodStart,
    PeriodEnd
ORDER BY 
    PeriodStart

Вы также можете сделать свой внутренний запрос с помощьютрадиционный group by, но я люблю меня немного over и хотел бы обратить ваше внимание:

SELECT
    PeriodStart = 
    CASE @Frequency
        WHEN 'day'     THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, CreatedOn))
        WHEN 'week'    THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(DAY, 1 - DATEPART(WEEKDAY, CreatedOn), CreatedOn)))
        WHEN 'month'   THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(MONTH,   DATEDIFF(MONTH,   0, CreatedOn), 0)))
        WHEN 'quarter' THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(QUARTER, DATEDIFF(QUARTER, 0, CreatedOn), 0)))
        WHEN 'year'    THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(YEAR,    DATEDIFF(YEAR,    0, CreatedOn), 0)))
    END,
    PeriodEnd   = 
    CASE @Frequency
        WHEN 'day'     THEN DATEADD(s, -1, DATEADD(day, 1, DATEDIFF(DAY, 0, CreatedOn)))
        WHEN 'week'    THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, 7 - DATEPART(WEEKDAY, CreatedOn), CreatedOn))))
        WHEN 'month'   THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, -1, DATEADD(MONTH,   DATEDIFF(MONTH,   0, CreatedOn) + 1, 0)))))
        WHEN 'quarter' THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, -1, DATEADD(QUARTER, DATEDIFF(QUARTER, 0, CreatedOn) + 1, 0)))))
        WHEN 'year'    THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, -1, DATEADD(YEAR,    DATEDIFF(YEAR,    0, CreatedOn) + 1, 0)))))
    END,
    p.PropertyRecId,
    COUNT(ph.PropertyPhotoId) over (partition by p.PropertyRecId) as PhotoCount
FROM
    Property P
    left join PropertyPhoto ph on
        p.PropertyRecId = ph.PropertyRecId
WHERE 
    CreatedOn BETWEEN @DateStart AND @DateEnd
GROUP BY
    p.PropertyRecId,
    p.CreatedOn
1 голос
/ 30 декабря 2011

Это работает?:

--1 : Make a lookup-up table of period start/end
CREATE TABLE #PERIODS (
    [Period Start] datetime
  , [Period End]   datetime
);

DECLARE @firstDay datetime
DECLARE @rowid int
SET @firstDay = '2011-01-01'
WHILE @firstDay < '2012-01-01'
BEGIN
    INSERT INTO #PERIODS VALUES ( @firstDay, DATEADD(DAY,6,@firstDay));
    SET @firstDay = @firstDay + 7
END
GO

-- 2 Count the photos per property per period
CREATE TABLE #PHOTOCOUNT (
    [Period Start] datetime
  , [Period End]   datetime
  , PropertyRecId  int
  , PhotoCount     int
);
GO

INSERT INTO #PHOTOCOUNT
SELECT 
    PD.[Period Start]
  , PD.[Period End]   
  , Property.PropertyRecId
  , COUNT(PropertyPhoto.PropertyPhotoId) AS PhotoCount
FROM 
    #PERIODS AS PD,
    Property
    LEFT JOIN PropertyPhoto
        ON Property.PropertyRecId = PropertyPhoto.PropertyRecId 
WHERE 
    PropertyPhoto.PropertyRecId Is Null
    OR PropertyPhoto.CreatedOn BETWEEN PD.[Period Start] AND PD.[Period End]
GROUP BY 
    PD.[Period Start]
  , PD.[Period End]   
  , Property.PropertyRecId;
GO

-- 3 Categorize by 0, 3 to 5, 6
SELECT 
    [Period Start]
  , [Period End]
  , SUM(RANGES.Zero) AS Zero
  , SUM(RANGES.ThreeToFive) AS ThreeToFive
  , SUM(RANGES.Six) AS Six
FROM (
    SELECT 
        [Period Start]
      , [Period End]
      , Zero = CASE WHEN PhotoCount = 0 THEN 1 ELSE 0 END 
      , ThreeToFive = CASE WHEN PhotoCount BETWEEN 3 AND 5 THEN 1 ELSE 0 END 
      , Six = CASE WHEN PhotoCount = 6 THEN 1 ELSE 0 END 
    FROM #PHOTOCOUNT
) RANGES
GROUP BY
    [Period Start]
  , [Period End] 
;

DROP TABLE #PERIODS;
DROP TABLE #PHOTOCOUNT;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...