簡単に言うと、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 またはそれらの行に沿って何かをインクリメントすることです。
どんな助けや提案も大歓迎です。