通过union加入的多个查询的查询优化

时间:2013-10-18 19:36:00

标签: sql sql-server

我正在尝试找到一种方法来增强我的SQL查询。有人可以推荐我最好的方法来优化这个查询。总之,我想让它更快。此查询用于计算目前位于看台内的人数,每直至此HOUR 。我必须获得每张票的最大LogDatetime ,直到那个小时,然后将其加入基本视图,这样我就可以获得日志信息(日志位置和日志类型)。 LogType = 1是Checkin票,0 = Checkout。

这是查询:

SELECT DISTINCT fld.Grandstand,log9h.LogHour,Count(log9h.TicketNo) AS TotalOccupancy
FROM (
SELECT DISTINCT TicketNo, logDay,9 as Loghour, MAX(LogDateTime) AS LastLog
       FROM          dbo.viewF1LogDetail
        WHERE LogDay = 14 AND LogHour < = 9
       GROUP BY TicketNo, logDay
) AS log9h 
INNER JOIN dbo.viewF1LogDetail AS fld ON fld.TicketNo = log9h.TicketNo 
                            AND fld.LogDateTime = log9h.LastLog
WHERE (fld.ScanningLogLocationType =('Grandstand')) AND (fld.LogType = 1)
GROUP BY fld.Grandstand,log9h.LogHour

UNION

SELECT DISTINCT fld.Grandstand,log10h.LogHour,Count(log10h.TicketNo) AS TotalOccupancy
FROM (
SELECT DISTINCT TicketNo, logDay,10 as Loghour, MAX(LogDateTime) AS LastLog
       FROM          dbo.viewF1LogDetail
        WHERE LogDay = 14 AND LogHour < = 10
       GROUP BY TicketNo, logDay
) AS log10h 
INNER JOIN dbo.viewF1LogDetail AS fld ON fld.TicketNo = log10h.TicketNo 
                            AND fld.LogDateTime = log10h.LastLog
WHERE (fld.ScanningLogLocationType =('Grandstand')) AND (fld.LogType = 1)
GROUP BY fld.Grandstand,log10h.LogHour

UNION


SELECT DISTINCT fld.Grandstand,log11h.LogHour,Count(log11h.TicketNo) AS TotalOccupancy
FROM (
SELECT DISTINCT TicketNo, logDay,11 as Loghour, MAX(LogDateTime) AS LastLog
       FROM          dbo.viewF1LogDetail
        WHERE LogDay = 14 AND LogHour < = 11
       GROUP BY TicketNo, logDay
) AS log11h 
INNER JOIN dbo.viewF1LogDetail AS fld ON fld.TicketNo = log11h.TicketNo 
                            AND fld.LogDateTime = log11h.LastLog
WHERE (fld.ScanningLogLocationType =('Grandstand')) AND (fld.LogType = 1)
GROUP BY fld.Grandstand,log11h.LogHour

UNION

SELECT DISTINCT fld.Grandstand,log12h.LogHour,Count(log12h.TicketNo) AS TotalOccupancy
FROM (
SELECT DISTINCT TicketNo, logDay,12 as Loghour, MAX(LogDateTime) AS LastLog
       FROM          dbo.viewF1LogDetail
        WHERE LogDay = 14 AND LogHour < = 12
       GROUP BY TicketNo, logDay
) AS log12h 
INNER JOIN dbo.viewF1LogDetail AS fld ON fld.TicketNo = log12h.TicketNo 
                            AND fld.LogDateTime = log12h.LastLog
WHERE (fld.ScanningLogLocationType =('Grandstand')) AND (fld.LogType = 1)
GROUP BY fld.Grandstand,log12h.LogHour

UNION

SELECT DISTINCT fld.Grandstand,log13h.LogHour,Count(log13h.TicketNo) AS TotalOccupancy
FROM (
SELECT DISTINCT TicketNo, logDay,13 as Loghour, MAX(LogDateTime) AS LastLog
       FROM          dbo.viewF1LogDetail
        WHERE LogDay = 14 AND LogHour < = 13
       GROUP BY TicketNo, logDay
) AS log13h 
INNER JOIN dbo.viewF1LogDetail AS fld ON fld.TicketNo = log13h.TicketNo 
                            AND fld.LogDateTime = log13h.LastLog
WHERE (fld.ScanningLogLocationType =('Grandstand')) AND (fld.LogType = 1)
GROUP BY fld.Grandstand,log13h.LogHour


UNION

SELECT DISTINCT fld.Grandstand,log14h.LogHour,Count(log14h.TicketNo) AS TotalOccupancy
FROM (
SELECT DISTINCT TicketNo, logDay,14 as Loghour, MAX(LogDateTime) AS LastLog
       FROM          dbo.viewF1LogDetail
        WHERE LogDay = 14 AND LogHour < = 14
       GROUP BY TicketNo, logDay
) AS log14h 
INNER JOIN dbo.viewF1LogDetail AS fld ON fld.TicketNo = log14h.TicketNo 
                            AND fld.LogDateTime = log14h.LastLog
WHERE (fld.ScanningLogLocationType =('Grandstand')) AND (fld.LogType = 1)
GROUP BY fld.Grandstand,log14h.LogHour

UNION

SELECT DISTINCT fld.Grandstand,log15h.LogHour,Count(log15h.TicketNo) AS TotalOccupancy
FROM (
SELECT DISTINCT TicketNo, logDay,15 as Loghour, MAX(LogDateTime) AS LastLog
       FROM          dbo.viewF1LogDetail
        WHERE LogDay = 14 AND LogHour < = 15
       GROUP BY TicketNo, logDay
) AS log15h 
INNER JOIN dbo.viewF1LogDetail AS fld ON fld.TicketNo = log15h.TicketNo 
                            AND fld.LogDateTime = log15h.LastLog
WHERE (fld.ScanningLogLocationType =('Grandstand')) AND (fld.LogType = 1)
GROUP BY fld.Grandstand,log15h.LogHour

ORDER BY Grandstand,Loghour

示例数据:

Grandstand  LogHour TotalOccupancy
Main    11  11
Main    12  15
Main    13  12
Main    14  14
Main    15  22
Main    16  25
Main    17  31
Main    18  22
Main    19  11
West    10  2
West    11  22
West    12  23
West    13  24
West    14  55
West    15  56
West    16  57
West    17  22
West    18  23
West    19  11
South   10  22
South   11  21
South   12  26
South   13  55
South   14  56
South   15  78
South   16  99
South   17  22
South   18  11
South   19  1

不是一个令人信服的查询吗?提前感谢您的推荐。

1 个答案:

答案 0 :(得分:1)

如果没有看到一些示例行和预期结果,那么理解这个问题就有点困难了。这会有用吗?

SELECT      Grandstand,
            LogHour,
            COUNT(TicketNo) AS TotalOccupancy
FROM        dbo.viewF1LogDetail
WHERE       LogDay = 14
            AND ScanningLogLocationType = 'Grandstand'
            AND LogType = 1
            AND LogHour >= 9
            AND LogHour <= 15
GROUP BY    Grandstand,
            LogHour;

如果这不起作用,对原因的解释可能会揭示查询的真实意图。

更新:

我想我现在明白了一点。试试这个:

WITH hourRows AS
(   /* Get a base set of hours in the day */
    SELECT  TOP (24) 
            ROW_NUMBER() OVER (ORDER BY name) hr
    FROM    sys.objects
), ticketInfo AS (
    /* Return the check in log event */
    SELECT      ld1.Grandstand,
                ld1.LogHour AS CheckInHour,
                checkout.LogHour AS CheckOutHour,
                ld1.TicketNo
    FROM        viewF1LogDetail ld1
                CROSS APPLY ( /* Apply the check out time to the set */
                    SELECT      ld2.LogHour
                    FROM        viewF1LogDetail ld2
                    WHERE       ld2.LogDay = 14
                                AND ld2.ScanningLogLocationType = 'Grandstand'
                                AND ld2.LogType = 0
                                AND ld2.LogHour >= 9
                                AND ld2.LogHour <= 15
                                AND ld1.Grandstand = ld2.Grandstand
                                AND ld1.TicketNo = ld2.TicketNo
                ) checkout
    WHERE       ld1.LogDay = 14
                AND ld1.ScanningLogLocationType = 'Grandstand'
                AND ld1.LogType = 1
                AND ld1.LogHour >= 9
                AND ld1.LogHour <= 15
)
SELECT      ci.GrandStand,
            hr.hr AS LogHour,
            COUNT(ci.TicketNo) AS TotalOccupancy
FROM        hourRows hr
            INNER JOIN ticketInfo ci ON    hr.hr >= ci.CheckInHour 
                                                AND hr.hr <= ci.CheckOutHour 
GROUP BY    ci.GrandStand,
            hr.hr
ORDER BY    ci.Grandstand;

请注意,您应该使用实数Numbers表替换hourRows CTE中的sys.objects。