2

我试图找到一种方法来增强我的 SQL 查询。有人可以推荐我优化此查询的最佳方法。简而言之,我想让它更快。此查询用于计算每小时内当前看台内的人数。我必须在该小时之前获取每张票的最大 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

不是一个令人信服的查询,对吧?提前感谢您的建议。

4

1 回答 1

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;

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

于 2013-10-18T20:15:08.080 回答