2

SQL クエリを強化する方法を見つけようとしています。このクエリを最適化するための最良の方法を教えてください。要するに早くしたい。このクエリは、現在グランドスタンド内にいる人の数を、最大でこの HOUR単位でカウントするために使用されます。その時間まで各チケットの最大 LogDatetimeを取得し、それをベース ビューに結合して、ログ情報 (ログの場所とログの種類) を取得できるようにする必要があります。LogType = 1 はチェックイン チケット、0 = チェックアウトです。

これはクエリです:

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 を実際の Numbers テーブルに置き換える必要があることに注意してください。

于 2013-10-18T20:15:08.080 に答える