無関係なデータを除外する
複雑なクエリでは、アートの一部としてクエリを1つずつ作成し、テストを進めていきます。
テーブル名はPatientMovementsであり、次のようになっていると思います。
ID={6,7}とID={8,9}のような行のペアが与えられた場合、患者(アカウント番号)、ユニット、および退院日がnullの入院日がある行は無視されると言うのは正しいです。また、同じ患者、ユニット、および入院日であるが、ヌルではない退院日についての記録。
したがって、ステップ1は、データベースに記録されているテーブルから無関係なデータを除外して、作業する必要のある行を生成することです。これは、2つのデータセットの和集合です。
- null以外の除隊日を持つ行。
- 退院日がヌルであるが、同じアカウント、ユニット、および入場日の行がない行。
明らかに、UNIONの最初の部分は次のとおりです。
SELECT * FROM PatientMovements WHERE DischargeDate IS NOT NULL
それほど明白ではありませんが、UNIONの2番目の部分は次のとおりです。
SELECT *
FROM PatientMovements AS p1
WHERE DischargeDate IS NULL
AND NOT EXISTS
(SELECT *
FROM PatientMovements AS P2
WHERE P1.Account = P2.Account
AND P1.Unit = P2.Unit
AND P1.AdmitDate = P2.AdmitDate
AND P2.DischargeDate IS NOT NULL
)
これで、これらを1つの結果セットに組み合わせることができます。
SELECT *
FROM PatientMovements
WHERE DischargeDate IS NOT NULL
UNION
SELECT *
FROM PatientMovements AS p1
WHERE DischargeDate IS NULL
AND NOT EXISTS
(SELECT *
FROM PatientMovements AS P2
WHERE P1.Account = P2.Account
AND P1.Unit = P2.Unit
AND P1.AdmitDate = P2.AdmitDate
AND P2.DischargeDate IS NOT NULL
)
上記のクエリは、IDが1..5、7、および9の行を返すことを確認することで確認できます。
警告:テストされていないコード。この回答のSQLはいずれもDBMSの近くにないため、テストされていません。
以前に学んだ教訓を適用する
次に、他の質問からの学習を適用して、データの順序付けや日付の違いの計算などを行うことができます。唯一の問題は、クエリを2回書き出す必要があることです。これは、面倒です(MS Access2003が「WITH」をサポートしていない場合)。句または共通テーブル式)。
しかし、この必要な出力を取得するための単一のクエリはありませんか?
もちろん、UNIONは単一のクエリです。私はあなたがただ書くことができると思います:
SELECT *
FROM PatientMovements
WHERE (DischargeDate IS NOT NULL)
OR (DischargeDate IS NULL
AND NOT EXISTS
(SELECT *
FROM PatientMovements AS P2
WHERE P1.Account = P2.Account
AND P1.Unit = P2.Unit
AND P1.AdmitDate = P2.AdmitDate
AND P2.DischargeDate IS NOT NULL
)
)
クエリを実行するためのよりコンパクトな方法をすぐに考えることはできません。
UNIONを「その他の答え」に組み込む
他の質問に対する受け入れられた回答には、2つの可能な解決策があります(コメントによって修正され、再フォーマットされています)。
SELECT T1.ID, T1.AccountNumber, T1.Date,
MIN(T2.Date) AS NextDate,
DATEDIFF("D", T1.Date, MIN(T2.Date)) AS DaysDiff
FROM YourTable T1
JOIN YourTable T2
ON T1.AccountNumber = T2.AccountNumber AND T2.Date > T1.Date
または:
SELECT ID, AccountNumber, Date, NextDate,
DATEDIFF("D", Date, NextDate) AS DaysDiff
FROM (SELECT ID, AccountNumber, Date,
(SELECT MIN(Date)
FROM YourTable T2
WHERE T2.AccountNumber = T1.AccountNumber
AND T2.Date > T1.Date
) AS NextDate
FROM YourTable T1
) AS T
コメントに記載されているように、質問にテーブル名がない場合、回答に異なるテーブル名が表示されます。私がPatientMovementsと呼んだものは、この回答ではYourTableと呼ばれていました。もう1つの違いは、元の質問のデータにUnit列またはDischargeDate列が含まれていなかったことです。ただし、私が提供したUNIONクエリは、これらのクエリを実行するための関連データを提供するため、あとはYourTableの代わりに他の回答にUNIONクエリを書き込むだけです。これはにつながります:
SELECT T1.ID, T1.AccountNumber, T1.Date,
MIN(T2.Date) AS NextDate,
DATEDIFF("D", T1.Date, MIN(T2.Date)) AS DaysDiff
FROM (SELECT *
FROM PatientMovements
WHERE (DischargeDate IS NOT NULL)
OR (DischargeDate IS NULL
AND NOT EXISTS
(SELECT *
FROM PatientMovements AS P2
WHERE P1.Account = P2.Account
AND P1.Unit = P2.Unit
AND P1.AdmitDate = P2.AdmitDate
AND P2.DischargeDate IS NOT NULL
)
)
) AS T1
JOIN (SELECT *
FROM PatientMovements
WHERE (DischargeDate IS NOT NULL)
OR (DischargeDate IS NULL
AND NOT EXISTS
(SELECT *
FROM PatientMovements AS P2
WHERE P1.Account = P2.Account
AND P1.Unit = P2.Unit
AND P1.AdmitDate = P2.AdmitDate
AND P2.DischargeDate IS NOT NULL
)
)
) AS T2
ON T1.AccountNumber = T2.Accountnumber AND T2.Date > T1.Date
または:
SELECT ID, AccountNumber, Date, NextDate,
DATEDIFF("D", Date, NextDate) AS DaysDiff
FROM (SELECT ID, AccountNumber, Date,
(SELECT MIN(Date)
FROM (SELECT *
FROM PatientMovements
WHERE (DischargeDate IS NOT NULL)
OR (DischargeDate IS NULL
AND NOT EXISTS
(SELECT *
FROM PatientMovements AS P2
WHERE P1.Account = P2.Account
AND P1.Unit = P2.Unit
AND P1.AdmitDate = P2.AdmitDate
AND P2.DischargeDate IS NOT NULL
)
)
) AS T2
WHERE T2.Accountnumber = T1.AccountNumber
AND T2.Date > T1.Date
) AS NextDate
FROM (SELECT *
FROM PatientMovements
WHERE (DischargeDate IS NOT NULL)
OR (DischargeDate IS NULL
AND NOT EXISTS
(SELECT *
FROM PatientMovements AS P2
WHERE P1.Account = P2.Account
AND P1.Unit = P2.Unit
AND P1.AdmitDate = P2.AdmitDate
AND P2.DischargeDate IS NOT NULL
)
)
) AS T1
) AS T
したがって、注意深く、クエリをフラグメントで開発し、それらを一貫して組み合わせる限り、最も見栄えの悪いクエリを飼いならすことができます。
一般的なテーブル式
SQL標準には「共通テーブル式」(CTE)、別名「WITH句」があり、これにより作業がさらに簡単になることに注意してください。
WITH YourTable AS
(SELECT *
FROM PatientMovements
WHERE (DischargeDate IS NOT NULL)
OR (DischargeDate IS NULL
AND NOT EXISTS
(SELECT *
FROM PatientMovements AS P2
WHERE P1.Account = P2.Account
AND P1.Unit = P2.Unit
AND P1.AdmitDate = P2.AdmitDate
AND P2.DischargeDate IS NOT NULL
)
)
)
SELECT T1.ID, T1.AccountNumber, T1.Date,
MIN(T2.Date) AS NextDate,
DATEDIFF("D", T1.Date, MIN(T2.Date)) AS DaysDiff
FROM YourTable T1
JOIN YourTable T2
ON T1.AccountNumber = T2.AccountNumber AND T2.Date > T1.Date
または:
WITH YourTable AS
(SELECT *
FROM PatientMovements
WHERE (DischargeDate IS NOT NULL)
OR (DischargeDate IS NULL
AND NOT EXISTS
(SELECT *
FROM PatientMovements AS P2
WHERE P1.Account = P2.Account
AND P1.Unit = P2.Unit
AND P1.AdmitDate = P2.AdmitDate
AND P2.DischargeDate IS NOT NULL
)
)
)
SELECT ID, AccountNumber, Date, NextDate,
DATEDIFF("D", Date, NextDate) AS DaysDiff
FROM (SELECT ID, AccountNumber, Date,
(SELECT MIN(Date)
FROM YourTable T2
WHERE T2.AccountNumber = T1.AccountNumber
AND T2.Date > T1.Date
) AS NextDate
FROM YourTable T1
) AS T
CTEを使用する主な利点の1つは、オプティマイザーが使用されるすべての場所でテーブル式が同じであると明示的に通知されるのに対し、何度か書き出されると、その共通性を見つけられない可能性があることです。さらに、クエリを数回書き出すと、編集エラーのために2つのクエリが実際にはわずかに異なる可能性があります。その可能性はCTEによって排除されています。現在の状況における他の利点は、CTEを他の質問の解決策と組み合わせることが子供の遊びであったことでした。
残念ながら、MSAccess2003がCTEをサポートしている可能性はほとんどありません。私はあなたの痛みを共有します。私が使用しているDBMSも主にそうではありません。