MySQLのスケジュールの競合
質問
ねえ、私は、イベントがMySQLのテーブルに重複するための解決策を探して、このサイトにつまずきました。私はいくつかのより多くの助けを得ることができれば、私は見るだろうと思って(すでに役立っている)溶液でSO感銘を受けました...
わかりましたので、ジョーはさんは仕事で誰かにシフトを交換したいと思います。彼は裁判所の日付を持っています。彼は、シフトスワップフォームに行くと、それは(または何それの左です)今週のスケジュールを引き上げます。これは、DBクエリを使用して行われます。汗かいていない。彼は、シフトを選びます。この時点から、それがチクチクなっています。
そこで、まず、フォームは、変速開始を通過し、スクリプトに端をシフトします。これは、このシフトと重なるシフトを持っている人のためのクエリを実行します。彼らはので、このクエリからすべてのユーザーIDがブラックリストに入れられ、一度に2つのシフトを動作することはできません。このクエリは次のようになります:
SELECT DISTINCT user_id FROM shifts
WHERE
FROM_UNIXTIME('$swap_shift_start') < shiftend
AND FROM_UNIXTIME('$swap_shift_end') > shiftstart
次に、私たちはa)は、同じ長さ(会社の方針)にあるすべてのシフトのためのクエリを実行し、そしてb)ジョーが取り組んでいる他のシフトと重複しない。
このような何か私が現在持っているます:
SELECT *
FROM shifts
AND shiftstart BETWEEN FROM_UNIXTIME('$startday') AND FROM_UNIXTIME('$endday')
AND user_id NOT IN ($busy_users)
AND (TIME_TO_SEC(TIMEDIFF(shiftend,shiftstart)) = '$swap_shift_length')
$conflict_dates
ORDER BY shiftstart, lastname
さて、あなたはおそらく "$ conflict_datesは何か???" 不思議に思っている。
ジョーはスワップシフトを送信したとき、彼は別のシフトの可能性をチェックアウトすることを決定した場合には、まあ、それは一週間のために彼のシフトをリロードします。それは最初のクエリを実行したときにスクリプトがをループして彼の選択を出力している間そう、それはまたの種類などに見える文字列を構築しています:
AND NOT(
'joe_shift1_start' < shiftend
AND 'joe_shift1_end' > shiftstart)
AND NOT(
'joe_shift2_start' < shiftend
AND 'joe_shift2_end' > shiftstart)
...etc
データベースの線に沿って、かなり長いクエリを取得するように、
SELECT *
FROM shifts
AND shiftstart BETWEEN FROM_UNIXTIME('$startday') AND FROM_UNIXTIME('$endday')
AND user_id NOT IN ('blacklisteduser1', 'blacklisteduser2',...etc)
AND (TIME_TO_SEC(TIMEDIFF(shiftend,shiftstart)) = '$swap_shift_length')
AND NOT(
'joe_shift1_start' < shiftend
AND 'joe_shift1_end' > shiftstart)
AND NOT(
'joe_shift2_start' < shiftend
AND 'joe_shift2_end' > shiftstart)
AND NOT(
'joe_shift3_start' < shiftend
AND 'joe_shift3_end' > shiftstart)
AND NOT(
'joe_shift4_start' < shiftend
AND 'joe_shift4_end' > shiftstart)
...etc
ORDER BY shiftstart, lastname
だから、私の希望は、いずれかのSQLは、簡単な方法でこれを扱う一部の天才の道を持っていること、または誰かがずっと賢く方法で、潜在的な競合を占めて幻想的論理元本を指摘することができるということです。 (の使用に注意してください「<私はビトウィーンズを使用していたことが判明し、両端から外れ分を減算しなければならなかったの前に、スタート>終了し、最後開始」。)
ありがとうございます。
A
解決
私のようなもの、あなたが代わりに生成された文字列の内側の選択を使用してJoeの他のシフトを排除することができるはずだと思います
SELECT *
FROM shifts s1
AND shiftstart BETWEEN FROM_UNIXTIME('$startday') AND FROM_UNIXTIME('$endday')
AND user_id NOT IN ($busy_users)
AND (TIME_TO_SEC(TIMEDIFF(shiftend,shiftstart)) = '$swap_shift_length')
AND (SELECT COUNT(1) FROM shifts s2
WHERE s2.user_id = $joes_user_id
AND s1.shiftstart < s2.shiftend
AND s2.shiftstart < s1.shiftend) = 0
ORDER BY shiftstart, lastname
基本的に、それぞれの行が重複ジョーのシフトのカウントのために内側のクエリを有しており、それはゼロだことを確認します。このように、ジョーの既存のシフトのいずれかと重複しない行のみが返されます。
他のヒント
あなたはTEMPORARYテーブルにjoe_shift{1,2,3}
値をロードし、それに対して参加するクエリを実行、外側のいずれにも一致していないだけでシフトを見つけるために、ジョインを使用できます:
CREATE TEMPORARY TABLE joes_shifts (
shiftstart DATETIME
shiftend DATETIME
);
INSERT INTO joes_shifts (shiftstart, shiftend) VALUES
('$joe_shift1_start', '$joe_shift1_end'),
('$joe_shift2_start', '$joe_shift2_end'),
('$joe_shift3_start', '$joe_shift3_end'),
('$joe_shift4_start', '$joe_shift4_end');
-- make sure you have validated these variables to prevent SQL injection
SELECT s.*
FROM shifts s
LEFT OUTER JOIN joes_shifts j
ON (j.shiftstart < s.shiftend OR j.shiftend > s.shiftstart)
WHERE j.shiftstart IS NULL
AND s.shiftstart BETWEEN FROM_UNIXTIME('$startday') AND FROM_UNIXTIME('$endday')
AND s.user_id NOT IN ('blacklisteduser1', 'blacklisteduser2',...etc)
AND (TIME_TO_SEC(TIMEDIFF(s.shiftend,s.shiftstart)) = '$swap_shift_length');
ためLEFT OUTERのはjoes_shifts
に一致する行が存在しない場合、列がNULLである、JOIN