1

簡単に言うと、Ticketmaster.com の "Find Best Available Seats" のようなコンサート タイプの会場で利用可能な最適な座席を見つけるのに役立つクエリを作成したいと考えています。要件は、ステージに最も近い要求された座席数を見つけることです。座席は順番どおりでなければなりません。

この例のテーブルを考えると:

DECLARE @Seats TABLE
(
    SectionId   INT         NOT NULL,
    RowId       VARCHAR(2)  NOT NULL,
    SeatId      INT         NOT NULL,
    Priority    INT         NOT NULL, /* Used to determine closeness to the stage and/or order to search in */
    StatusCd    CHAR(1)     NOT NULL, /* A for Available, H for Held, P for Purchased, etc. */
    Cost        MONEY       NOT NULL
)

そして、このスクリプトを使用してテーブルにデータを入力すると、次のようになります。

DECLARE @SectionCounter INT
DECLARE @RowCounter INT
DECLARE @SeatCounter INT

SET     @SectionCounter = 1
SET     @RowCounter = 1

WHILE   @SectionCounter <= 10
BEGIN

    WHILE   @RowCounter <= 26
    BEGIN

        SET @SeatCounter = 1

        WHILE @SeatCounter <= 26
        BEGIN       

            INSERT INTO @Seats
            ( SectionId ,
              RowId ,
              SeatId ,
              Priority ,
              StatusCd ,
              Cost
            )
            VALUES 
            ( @SectionCounter ,
              CHAR(64 + @RowCounter) ,
              @SeatCounter ,
              1 ,
              (
                /* Randomly setting certain seats as purchased */
                SELECT  CASE
                        WHEN @SeatCounter IN 
                        (
                            1,2,9,10,
                            (ROUND(((26 - 1 -1) * RAND() + 1), 0)),
                            (ROUND(((26 - 1 -1) * RAND() + 1), 0)),
                            (ROUND(((26 - 1 -1) * RAND() + 1), 0)),
                            (ROUND(((26 - 1 -1) * RAND() + 1), 0)),
                            (ROUND(((26 - 1 -1) * RAND() + 1), 0)),
                            (ROUND(((26 - 1 -1) * RAND() + 1), 0)),
                            (ROUND(((26 - 1 -1) * RAND() + 1), 0))
                        )
                        THEN 'P' ELSE 'A' END) ,
              (
                SELECT  CASE
                        WHEN @SectionCounter IN (1,2)
                        THEN 75.00 ELSE 25.00 END
              )
            )

            SET @SeatCounter = @SeatCounter + 1

        END

        SET @RowCounter = @RowCounter + 1

    END

    SET     @RowCounter = 1
    SET @SectionCounter = @SectionCounter + 1

END

シーケンシャル/連続した座席の x 数を見つけるための最適なクエリは何ですか?

以下は私の現在のソリューションです。これには、アプリケーションで少なくとも 3 つのクエリが必要です。

たとえば、顧客が次に良い空席を 8 つリクエストした場合、次のクエリを実行します。

/* Get each sections available seat count */
SELECT  SectionId,
        Priority,
        COUNT(SeatId) AS 'Seat Count'
FROM    @Seats
WHERE   StatusCd = 'A' /* A = Available. */
GROUP BY SectionId, Priority
ORDER BY Priority

次のような結果セットが生成されます。

| SectionId | Priority | SeatCount |
|-----------|----------|-----------|
| 1         | 1        | 544       |
| 2         | 2        | 554       |
| 3         | 3        | 552       |

アプリケーションは、「優先順位 1 で利用可能な座席は 8 つありますか?」と言うでしょう。上記の結果セットでは、答えは「はい」なので、対応するセクション (セクション 1) で使用可能な行数を取得しましょう。これに対するクエリは次のとおりです。

SELECT  RowId,
        COUNT(SeatId) AS 'Seat Count'
FROM    @Seats
WHERE   SectionId = 1
        AND StatusCd = 'A'
GROUP BY RowId

次のような結果セットが生成されます。

| RowId | SeatCount |
|-------|-----------|
| A     | 21        |
| B     | 18        |
| C     | 22        |

アプリケーションはこれらの結果を見て、最初の行から同じ質問をします。「行 A には 8 席ありますか?」上記の結果では、答えはイエスであるため、その時点で、アプリケーションは次のクエリで行 A のすべての座席をクエリします。

SELECT  *
FROM    @Seats
WHERE   SectionId = 1
AND     RowId = 'A'

次のような結果セットが生成されます。

| SectionId | RowId | SeatId | Priority | StatusCd | Cost  |
|-----------|-------|--------|----------|----------|-------|
| 1         | A     | 1      | 1        | P        | 75.00 |
| 1         | A     | 2      | 1        | P        | 75.00 |
| 1         | A     | 3      | 1        | A        | 75.00 |
| 1         | A     | 4      | 1        | A        | 75.00 |
| 1         | A     | 5      | 1        | A        | 75.00 |

その時点で、アプリケーションは結果を反復処理して、利用可能な StatusCd が「A」の 8 席を連続して見つけようとします。

行全体をロードしてコードで実行することなく、データベース内の順次レコードを照会するはるかに効率的な方法があると確信しています。

最適な解決策についての私の最善の推測は、テーブルで自己結合を行い、SeatId またはそれらの行に沿って何かをインクリメントすることです。

どんな助けや提案も大歓迎です。

4

1 に答える 1

1

これで始められるはずです。あなたは、自己が参加する限り、正しい道を歩んでいました。

これにより、同じ優先度、セクション、列で利用可能な最初の 8 席が、優先度、セクション、列の優先順で「A」のステータスで表示されます。私が何か誤解した場合は、私を修正してください。

DECLARE @number_seats AS INTEGER = 8;

WITH T1 AS (
    SELECT S.*,
           SeatId - ROW_NUMBER() OVER(PARTITION BY Priority, SectionId, RowId, StatusCd ORDER BY SeatId) AS grp
    FROM #seats AS S
),

T2 AS (
SELECT Priority    AS Priority,
       SectionId   AS Section,
       RowId       AS RowId,
       StatusCd    AS StatusCd, 
       MIN(SeatId) AS StartingSeat,
       MAX(SeatId) AS EndingSeat,
       COUNT(*)    AS Seats       
FROM T1
GROUP BY Priority, SectionId, RowId, StatusCd, grp
),

T3 AS (
    SELECT TOP 1 *
    FROM T2
    WHERE T2.Seats >= @number_seats and StatusCd = 'A'
    ORDER BY Priority, Section, RowId, StartingSeat
)
SELECT S.*
FROM T3 JOIN #seats AS S ON 
(
    T3.Priority = S.Priority AND
    T3.Section  = S.SectionId AND
    T3.RowId    = S.RowId AND
    S.SeatId BETWEEN T3.StartingSeat AND T3.StartingSeat + @number_seats - 1
)
ORDER BY Priority, Section, RowId, StartingSeat

結果:

SectionId   RowId SeatId      Priority    StatusCd Cost
----------- ----- ----------- ----------- -------- ---------------------
1           A     11          1           A        75.00
1           A     12          1           A        75.00
1           A     13          1           A        75.00
1           A     14          1           A        75.00
1           A     15          1           A        75.00
1           A     16          1           A        75.00
1           A     17          1           A        75.00
1           A     18          1           A        75.00
于 2012-02-23T23:35:07.713 に答える