2009-08-25 17 views
2

テニスコートの予約情報をSQLデータベースから簡単な結果テーブルに抽出して、裁判所の使用法の図を作成するのに役立ちます。それは1時間以上続く予約の場合を除いて、かなり簡単です。値に基づく単一または複数のINSERT

現時点では、各予約は結果表に1行ずつ表示されます。各行には、開始時間、期間、裁判所の番号が含まれています。この表をスプレッドシートまたはピボットテーブルに直接マップして、裁判所の裁判所の数と1日の時間帯を確認することができます。私たちの問題、すなわち、2、3時間以上の期間の予約が唯一の結果テーブルに1行を持っているということです

INSERT INTO Results (year, month, day, hour, duration, court) 
SELECT DATEPART (yy, b.StartDateTime), 
     DATEPART (mm, b.StartDateTime), 
     DATEPART (dd, b.StartDateTime), 
     DATEPART (hh, b.StartDateTime), 
     a.Duration, 
     a.Court 
FROM Bookings b 
INNER JOIN Activities a 
ON b.ActivityID = a.ID 

は現在、私たちのSQLクエリは次のようになります。予約の最初の1時間。これは、予約の長さが期間データに取り込まれるためです。私たちは目的を達成するためにデータに対していくつかの後処理を行うことができますが、これがSQLクエリで可能だった場合は簡単になります。

期間(1、2、3、...時間など)に応じて、適切な数の行が結果表に挿入され、期間1したがって、9時からの3時間の予約では、結果表に3行、1つは午前9時に、1つは午前10時に、1つは午前11時に、1時間ごとに実行されます。

だからではなく、結果表に次の行を:これは、はるかに簡単にスプレッドシートに結果テーブルをマッピングするだろう

Year, Month, Day, Hour, Duration, Court 
2009, 08, 25, 09,  1,  1 
2009, 08, 25, 10,  1,  1 
2009, 08, 25, 11,  1,  1 

Year, Month, Day, Hour, Duration, Court 
2009, 08, 25, 09,  3,  1 

我々は、次の行を取得。

UPDATE 2009-08-25:もちろん、最初の2つの回答が示すとおり、1つのクエリである必要はありません。セットは大丈夫です。

UPDATE 2009-08-26:サイドトラックされており、まだ提案された解決策を試す機会がありませんでした。すぐにそうすることを希望し、結果に基づいて回答を選択します。

UPDATE 2009-08-27:最後に解決策を試す機会を得ました。整数の表と解を生成するための結合は目が離せないものでした。特にクロスジョインを使用してそのようなテーブルを作成する。これはおそらく、よりクリーンなSQLのやり方です。

しかし、結局のところ、私はフラグと単純なアルゴリズムを含むAaronのソリューションに行きました。アルゴリズムをwhileループでラップして、その継続時間が1を超えないようにするために、繰り返し処理を続けることで、この問題を改善しました。これは迅速かつ簡単に実装できました。また、私たちは約10時間の予約をしていたので、ここでは制限をハードコードする必要はありませんでした。

私は、duration> 1のアイテムを数えるという独自の考え方ではなく、whileループカウンターにmax durationのアイデアを取り入れたことに注意してください。

+0

どのバージョンのSQL Serverですか? –

+0

SQL Server 2000.それは違いをもたらすでしょうか? – dave

+0

SQL 2005以降には、このようなクエリを簡単にする機能がいくつかあります。 –

答えて

0

些細なことではありません。

INSERT INTO Results (year, month, day, hour, duration, court, Flag) 
SELECT DATEPART (yy, b.StartDateTime), 
     DATEPART (mm, b.StartDateTime), 
     DATEPART (dd, b.StartDateTime), 
     DATEPART (hh, b.StartDateTime), 
     a.Duration, 
     a.Court, 
     0 
FROM Bookings b 
INNER JOIN Activities a 
ON b.ActivityID = a.ID 

あなたはこれらのクエリを複数回実行する必要があります:

-- Copy all rows with duration > 1 and set the flag to 1 
insert into results(year, month, day, hour, duration, court, Flag) 
select year, month, day, hour+1, duration-1, court, 1 
from result 
where duration > 1 
; 
-- Set the duration of all copied rows to 1 
update result 
set duration = 1 
where flag = 0 and duration > 1 
; 
-- Prepare the copies for the next round 
update result 
set flag = 0 
where flag = 1 

これは、各duration > 1用の追加エントリを作成します。まず、あなたは別の列0である「旗」が必要です。私の推測では、あなたは8時間以上裁判所を割り当てることができないので、これらの3つを8回実行してすべてを修正するだけです。

+0

私はこれに従うと思います。しかし、2番目のクエリで期間を1減らす必要はありませんが、正確に1に設定しないでください。 – dave

+0

@dave:いいえ、期間を1に設定すると、すべてのプロセスクエリをピクチャから取り除きます。 "flag = 1"のすべての結果に新しい "duration-1"が含まれます。だから私はフラグを必要としています( "削除"する時間を知るために) –

+0

@Aaron、私は今それを取得します。私の頭の中で一例を始めたら、それは明らかでした。私は "反復"が "親"の行に基づいていると仮定していました。継続時間が1より大きい元の行。ただし、反復処理を行う子行が作成されます。これはかなり賢いです。おそらく、whileループ内にすべてをラップして、継続時間> 1の行があるかどうかを調べます。このようにして、予約可能な最大時間や無駄な繰り返しを心配する必要はありません。 – dave

1

編集が整数Nためのn行を持つ単一列の一時テーブルを作成します欠落している時間の計算

を修正するために - (私は最大の予約時間は8時間であると仮定してきました)。

create table #t 
(id int 
,addHour int 
) 

insert #t 
select 1,0 
union all select 2,0 
union all select 2,1 
union all select 3,0 
union all select 3,1 
union all select 3,2 
union all select 4,0 
union all select 4,1 
union all select 4,2 
union all select 4,3 
union all select 5,0 
union all select 5,1 
union all select 5,2 
union all select 5,3 
union all select 5,4 
union all select 6,0 
union all select 6,1 
union all select 6,2 
union all select 6,3 
union all select 6,4 
union all select 6,5 
union all select 7,0 
union all select 7,1 
union all select 7,2 
union all select 7,3 
union all select 7,4 
union all select 7,5 
union all select 7,6 
union all select 8,0 
union all select 8,1 
union all select 8,2 
union all select 8,3 
union all select 8,4 
union all select 8,5 
union all select 8,6 
union all select 8,7 
あなたは、一時テーブルには、次のクエリで行の正確な数を持っていることを検証することができ

select id, count(1) 
from #t 
group by id 
order by id 

一時テーブルに参加含まれるようにクエリを改正:

INSERT INTO Results (year, month, day, hour, duration, court) 
SELECT DATEPART (yy, b.StartDateTime), 
     DATEPART (mm, b.StartDateTime), 
     DATEPART (dd, b.StartDateTime), 
     DATEPART (hh, b.StartDateTime) + addHour, 
     1 AS Duration, 
     a.Court 
FROM Bookings b 
INNER JOIN Activities a 
ON b.ActivityID = a.ID 
INNER JOIN #t AS t 
ON t.id = a.Duration 

編集 - この仕組みの説明

表を結合すると、結合条件を満たすソース表内の結合行の各組合せに対して、行に出力が生成されます。

私は一時テーブルを使用して、予約とアクティビティの元の結果セットを、予約期間の締め切り時間で「累積」します。これは予約が数時間で行われる場合にのみ有効です。

あなたはセット、より明確にこれを見る各行を一意に識別するば#tするために、第2の列を追加し、出力結果に含めたい場合:これは、結果にその各行を明確にすべき

create table #t 
(id int 
,unique_id int identity 
) 

INSERT #t (id) 
select 1 
union all select 2 
... etc 

SELECT DATEPART (yy, b.StartDateTime), 
     DATEPART (mm, b.StartDateTime), 
     DATEPART (dd, b.StartDateTime), 
     DATEPART (hh, b.StartDateTime) + addHour, 
     1 AS Duration, 
     a.Court, 
     t.unique_id 
FROM Bookings b 
INNER JOIN Activities a 
ON b.ActivityID = a.ID 
INNER JOIN #t AS t 
ON t.id = a.Duration 

セットは、Bookings、Activities、および#tの1つの有効な組み合わせから生成されます。

+0

これはどのように動作するのか少し説明できますか?私は一時テーブルの作成を理解しますが、#tの結合がどのように望ましい結果を生み出すかは分かりません。 – dave

+0

これは結果に正しい時間を与えません。 –

+0

@Aaron - 良い点。私はこれを処理するためにクエリを修正しました。 –

0

INSTEAD OF INSERTトリガーを1時間以上の予約ごとに複数の行を挿入するテーブル「結果」に配置することを検討することがあります。これは複雑さを増しますが、これは大量のOLTPシステムのようには聞こえないので、合理的なアプローチかもしれません。

1

あなたの元で十分にわずかな変更、あなたはシリーズの発電機として機能するようにintegersテーブル(またはVIEW)を導入場合:

INSERT INTO Results (year, month, day, hour, duration, court) 
SELECT DATEPART (yy, b.StartDateTime), 
     DATEPART (mm, b.StartDateTime), 
     DATEPART (dd, b.StartDateTime), 
     DATEPART (hh, b.StartDateTime) + (a.Duration - i.iii - 1) 
     1, 
     a.Court 
FROM Bookings b 
INNER JOIN Activities a 
    ON b.ActivityID = a.ID 
INNER JOIN Integers999 i  -- N.B.: Integers999 (iii INT), all numbers 0 .. 999 
    ON a.Duration > i.iii;  -- So, a true Duration of 1 appears once, of 2 twice ... 
+0

開始時刻を修正するのを忘れました。 –

+0

@アロン、だから、ありがとう、ありがとう。一定。 – pilcrow

0

私はこれをデバッグする機会を持っていましたが、何かしていませんこれはあなたのためにそれを行う必要があります:

DECLARE @maxDuration INTEGER 
DECLARE @curDuration INTEGER 

SELECT @MaxDuration = SELECT MAX(Duration) FROM Activities 
SET @curDuration = 1 

WHILE @curDuration <= @MaxDuration 
BEGIN 
    INSERT INTO Results (year, month, day, hour, duration, court) 
    SELECT DATEPART (yy, b.StartDateTime), 
      DATEPART (mm, b.StartDateTime), 
      DATEPART (dd, b.StartDateTime), 
      DATEPART (hh, b.StartDateTime) + @curDuration - 1, 
      a.Duration, 
      a.Court 
    FROM Bookings b 
    INNER JOIN Activities a 
    ON b.ActivityID = a.ID 
    WHERE a.Duration <= @MaxDuration 

    SET @curDuration = @curDuration + 1 
END 
関連する問題