Циклический запрос SQL Server - PullRequest
2 голосов
/ 12 января 2011

У меня есть подзапрос, который суммирует дни, в которые листинг был активен. У этих списков есть 3 различных приоритета, которые мы хотим проанализировать отдельно. Подзапросы работают нормально, но мне приходится повторяться 3 раза, и я не могу не чувствовать, что кто-то может указать мне более элегантное направление.

Я ищу что-то вроде

Declare @Priorities text = ['H','M','L']

Foreach(priority in priorities)
  (SELECT SUM(
        CASE
            WHEN(jlh_inner.StartDate IS NULL) THEN 0
            WHEN(jlh_inner.EndDate IS NULL) THEN
                DATEDIFF(dd, jlh_inner.StartDate, GETDATE())
            ELSE
                DATEDIFF(dd, jlh_inner.StartDate, jlh_inner.EndDate)
        END)
    FROM ListingHistory jlh_inner
    WHERE jlh_inner.JobTitleId = jlh.JobTitleId
    AND jlh_inner.OfficeCode = rof.code
    AND jlh_inner.Priority = priority)

Полный код прямо сейчас:

BEGIN
SELECT rof.location AS location,
    jlh.TitleId AS TitleId,
    jt.Title AS Title,
    (SELECT SUM(
        CASE
            WHEN(jlh_inner.StartDate IS NULL) THEN 0
            WHEN(jlh_inner.EndDate IS NULL) THEN
                DATEDIFF(dd, jlh_inner.StartDate, GETDATE())
            ELSE
                DATEDIFF(dd, jlh_inner.StartDate, jlh_inner.EndDate)
        END)
    FROM ListingHistory jlh_inner
    WHERE jlh_inner.JobTitleId = jlh.JobTitleId
    AND jlh_inner.OfficeCode = rof.code
    AND jlh_inner.Priority = 'H') AS HighPriorityDays,
    (SELECT SUM(
        CASE
            WHEN(jlh_inner.StartDate IS NULL) THEN 0
            WHEN(jlh_inner.EndDate IS NULL) THEN
                DATEDIFF(dd, jlh_inner.StartDate, GETDATE())
            ELSE
                DATEDIFF(dd, jlh_inner.StartDate, jlh_inner.EndDate)
        END)
    FROM ListingHistory jlh_inner
    WHERE jlh_inner.JobTitleId = jlh.JobTitleId
    AND jlh_inner.OfficeCode = rof.code
    AND jlh_inner.Priority = 'M') AS MediumPriorityDays,
    (SELECT SUM(
        CASE
            WHEN(jlh_inner.StartDate IS NULL) THEN 0
            WHEN(jlh_inner.EndDate IS NULL) THEN
                DATEDIFF(dd, jlh_inner.StartDate, GETDATE())
            ELSE
                DATEDIFF(dd, jlh_inner.StartDate, jlh_inner.EndDate)
        END)
    FROM ListingHistory jlh_inner
    WHERE jlh_inner.JobTitleId = jlh.JobTitleId
    AND jlh_inner.OfficeCode = rof.code
    AND jlh_inner.Priority = 'L') AS LowPriorityDays

FROM Offices rof,
    ListingHistory jlh,
    JobTitle jt

WHERE rof.code = jlh.OfficeCode
AND jt.JobTitleID = jlh.JobTitleId

GROUP BY rof.location, rof.code, jlh.TitleId, jt.Title

ORDER BY location

END

Ответы [ 4 ]

3 голосов
/ 12 января 2011

Согласитесь с HLGEM, лучше использовать синтаксис соединения. Это также вписывается в синтаксис OUTER APPLY. Это позволяет достичь того, что вы хотите, с помощью кода consis без повторного просмотра таблицы 3 раза.

SELECT rof.location AS location,
    jlh.TitleId AS TitleId,
    jt.Title AS Title,
    sum(case when PD.Priority='H' then PD.PriorityDays end) as HighPriorityDays,
    sum(case when PD.Priority='M' then PD.PriorityDays end) as MediumPriorityDays,
    sum(case when PD.Priority='L' then PD.PriorityDays end) as LowPriorityDays
FROM Offices rof
inner join ListingHistory jlh on rof.code = jlh.OfficeCode
inner join JobTitle jt on jt.JobTitleID = jlh.JobTitleId
outer apply
    (SELECT jlh_inner.Priority, SUM(
        CASE
            WHEN(jlh_inner.StartDate IS NULL) THEN 0
            WHEN(jlh_inner.EndDate IS NULL) THEN
                DATEDIFF(dd, jlh_inner.StartDate, GETDATE())
            ELSE
                DATEDIFF(dd, jlh_inner.StartDate, jlh_inner.EndDate)
        END) as PriorityDays
    FROM ListingHistory jlh_inner
    WHERE jlh_inner.JobTitleId = jlh.JobTitleId
    AND jlh_inner.OfficeCode = rof.code
    AND jlh_inner.Priority in ('H','L','M')
    GROUP BY jlh_inner.Priority) PD
GROUP BY rof.location, rof.code, jlh.TitleId, jt.Title
ORDER BY location
2 голосов
/ 12 января 2011

У вас есть несколько очень плохих методов кодирования, которые вам необходимо прекратить использовать полностью, и коррелированные подзапросы являются одним из них.Они - убийцы производительности, и нет никаких причин когда-либо использовать их.Кроме того, вам следует начать использовать явные объединения, тем более что вы используете SQL Server, а синтаксис неявного соединения для внешних объединений не только устарел, но фактически нарушается даже в SQL Server 2000, а объединение неявных внутренних и явных выходных соединений часто приводит к неверным результатамтаким образом, неявные объединения сложнее поддерживать, и они с большей вероятностью имеют случайные перекрестные объединения и, конечно, устарели почти на 20 лет.

Посмотрите, делает ли этот код то, что вам нужно:

SELECT rof.location AS location,     
jlh.TitleId AS TitleId,     
jt.Title AS Title,     
SUM(CASE WHEN(jlh.StartDate IS NULL and Priority <> 'H') THEN 0  
    WHEN(jlh.EndDate IS NULL AND Priority = 'H') 
    THEN DATEDIFF(dd, jlh.StartDate, GETDATE())             
    WHEN (jlh.EndDate IS NOT NULL AND Priority = 'H') THEN DATEDIFF(dd, jlh.StartDate, jlh.EndDate) END) AS HighPriorityDays,     
SUM(CASE WHEN(jlh.StartDate IS NULL and Priority <> 'M') THEN 0  
    WHEN(jlh.EndDate IS NULL AND Priority = 'M') 
    THEN DATEDIFF(dd, jlh.StartDate, GETDATE())             
    WHEN (jlh.EndDate IS NOT NULL AND Priority = 'M') THEN DATEDIFF(dd, jlh.StartDate, jlh.EndDate) END) AS MediumPriorityDays,
SUM(CASE WHEN(jlh.StartDate IS NULL and Priority <> 'L') THEN 0  
    WHEN(jlh.EndDate IS NULL AND Priority = 'L') 
    THEN DATEDIFF(dd, jlh.StartDate, GETDATE())             
    WHEN (jlh.EndDate IS NOT NULL AND Priority = 'L') THEN DATEDIFF(dd, jlh.StartDate, jlh.EndDate) END) AS LowPriorityDays  
FROM Offices rof 
JOIN    ListingHistory jlh 
    ON rof.code = jlh.OfficeCode
JOIN     JobTitle jt  
    ON jt.JobTitleID = jlh.JobTitleId  
GROUP BY rof.location, rof.code, jlh.TitleId, jt.Title  
ORDER BY location 
2 голосов
/ 12 января 2011

Вместо того, чтобы объявлять @priorities как массив текстов, сделайте его таблицей, затем вставьте три значения в таблицу @priorities и присоедините существующий агрегирующий запрос к недавно созданной таблице @priorities.Это даст вам одну строку результатов на строку вашей таблицы приоритетов, и я думаю, что вы на самом деле ищете, не так ли?

Вот как я могу выполнить настройку таблицы в MS SQL:

declare @priorities table (
priority char(1)
)

insert into @priorities (priority) values ('H')
insert into @priorities (priority) values ('M')
insert into @priorities (priority) values ('L')

Это приведет к тому, что ваша конечная реализация будет включать в себя что-то вроде этого:

SELECT jlh_inner.Priority, SUM(
        CASE
            WHEN(jlh_inner.StartDate IS NULL) THEN 0
            WHEN(jlh_inner.EndDate IS NULL) THEN
                DATEDIFF(dd, jlh_inner.StartDate, GETDATE())
            ELSE
                DATEDIFF(dd, jlh_inner.StartDate, jlh_inner.EndDate)
        END)
    FROM ListingHistory jlh_inner
    INNER JOIN @priorities p on jlh_inner.Priority = p.priorities
    WHERE jlh_inner.JobTitleId = jlh.JobTitleId
    AND jlh_inner.OfficeCode = rof.code

Затем вы добавите поле Priority в предложение GROUP BY, которое вы уже получили, и все должно хорошо сгруппироваться.

1 голос
/ 12 января 2011

Вот как я бы реорганизовал его, используя общее табличное выражение (которое представляет собой резюме, сгруппированные соответствующим образом) и явные объединения:

WITH Summaries AS (
   SELECT jlh.JobTitleId
          ,jlh.OfficeCode
          ,jlh.Priority
          ,SUM(
            CASE
                WHEN(jlh.StartDate IS NULL) THEN 0
                WHEN(jlh.EndDate IS NULL) THEN
                    DATEDIFF(dd, jlh.StartDate, GETDATE())
                ELSE
                    DATEDIFF(dd, jlh.StartDate, jlh.EndDate)
            END
          ) AS DayCount
    FROM ListingHistory jlh
    GROUP BY jlh.JobTitleId
          ,jlh.OfficeCode
          ,jlh.Priority
)
SELECT rof.location AS location
    ,jlh.TitleId AS TitleId
    ,jt.Title AS Title
    ,s_h.DayCount AS HighPriorityDays
    ,s_m.DayCount AS MediumPriorityDays
    ,s_l.DayCount AS LowPriorityDays
FROM Offices rof
INNER JOIN ListingHistory jlh
    ON rof.code = jlh.OfficeCode
INNER JOIN JobTitle jt
    ON jt.JobTitleID = jlh.JobTitleId
LEFT JOIN Summaries s_h
    ON s_h.JobTitleId = jlh.JobTitleId
    AND s_h.OfficeCode = rof.code
    AND s_h.Priority = 'H'
LEFT JOIN Summaries s_m
    ON s_m.JobTitleId = jlh.JobTitleId
    AND s_m.OfficeCode = rof.code
    AND s_m.Priority = 'M'
LEFT JOIN Summaries s_l
    ON s_l.JobTitleId = jlh.JobTitleId
    AND s_l.OfficeCode = rof.code
    AND s_l.Priority = 'L'
GROUP BY rof.location, rof.code, jlh.TitleId, jt.Title
ORDER BY location
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...