SQL テーブルに次のデータがあります。
欠落している「 familyid 」のリストを従業員ごとに取得できるように、データを照会する必要があります。
たとえば、シーケンスに欠落している従業員 1021 については ID 2 と 5 を取得し、従業員 1027 については欠落している番号 1 と 6 を取得する必要があります。
それを照会する方法の手がかりはありますか?
どんな助けにも感謝します。
SQL テーブルに次のデータがあります。
欠落している「 familyid 」のリストを従業員ごとに取得できるように、データを照会する必要があります。
たとえば、シーケンスに欠落している従業員 1021 については ID 2 と 5 を取得し、従業員 1027 については欠落している番号 1 と 6 を取得する必要があります。
それを照会する方法の手がかりはありますか?
どんな助けにも感謝します。
ここに 1 つのアプローチがあります。各従業員の家族 ID の最大値を計算します。次に、これを最大家族 ID までの番号のリストに結合します。結果には、各従業員と予想される家族 ID ごとに 1 つの行があります。
left outer join
これを元のデータに戻しfamilyid
、番号を付けます。何も一致しない場合、それらは欠損値です。
with nums as (
select 1 as n
union all
select n+1
from nums
where n < 20
)
select en.employee, n.n as MissingFamilyId
from (select employee, min(familyid) as minfi, max(familyid) as maxfi
from t
group by employee
) en join
nums n
on n.n <= maxfi left outer join
t
on t.employee = en.employee and
t.familyid = n.n
where t.employee_number is null;
familyid
行方不明がシーケンスの最後の番号である場合、これは機能しないことに注意してください。しかし、データ構造でできる最善の方法かもしれません。
また、上記のクエリは、最大 20 人の家族がいると想定しています。
最初の欠損値を見つける
ROW_NUMBER
ウィンドウ関数を使用して、「正しい」シーケンス ID 番号を割り当てます。従業員 ID が変更されるたびにシーケンス ID が再開すると仮定すると、次のようになります。
SELECT
e.id,
e.name,
e.employee_number,
e.relation,
e.familyid,
ROW_NUMBER() OVER(PARTITION BY e.employeeid ORDER BY familyid) - 1 AS sequenceid
FROM employee_members e
次に、結果セットをフィルタリングして、シーケンス ID が一致しない行のみを含めます。
SELECT *
FROM (
SELECT
e.id,
e.name,
e.employee_number,
e.relation,
e.familyid,
ROW_NUMBER() OVER(PARTITION BY e.employeeid ORDER BY familyid) - 1 AS sequenceid
FROM employee_members e
) a
WHERE a.familyid <> a.sequenceid
次に、簡単にグループ化してemployee_number
、各従業員の最初に欠落しているシーケンス ID を見つける必要があります。
SELECT
a.employee_number,
MIN(a.sequence_id) AS first_missing
FROM (
SELECT
e.id,
e.name,
e.employee_number,
e.relation,
e.familyid,
ROW_NUMBER() OVER(PARTITION BY e.employeeid ORDER BY familyid) - 1 AS sequenceid
FROM employee_members e
) a
WHERE a.familyid <> a.sequenceid
GROUP BY a.employee_number
すべての欠損値を見つける
familyid
前のクエリを拡張すると、との差がsequenceid
変化するたびに欠損値を検出できます。
-- Warning: this is totally untested :-/
SELECT
b.employee_number,
MIN(b.sequence_id) AS missing
FROM (
SELECT
a.*,
a.familyid - a.sequenceid AS displacement
SELECT
e.*,
ROW_NUMBER() OVER(PARTITION BY e.employeeid ORDER BY familyid) - 1 AS sequenceid
FROM employee_members e
) a
) b
WHERE b.displacement <> 0
GROUP BY
b.employee_number,
b.displacement
これは機能します。すべての「依存関係」を選択し、前の行に結合を残します。その行がない場合は、結果を表示します。
SELECT 'Missing Prior', t1.*
FROM employee_members t1
LEFT JOIN employee_members t2 ON t1.employee_number = t2.employee_number
AND (t1.familyid-1) = t2.familyid
WHERE t2.employee_number is null and t1.relation == 'Dependent'
不足している番号を示す別のバージョン:
SELECT t1.employee_number, t1.familyid-1 as Missing_Member
FROM employee_members t1
LEFT JOIN employee_members t2 ON t1.employee_number = t2.employee_number
AND (t1.familyid-1) = t2.familyid
WHERE t2.employee_number is null and t1.relation == 'Dependent'
別の解決策: シーケンスから考えられるすべての値を含むテーブルを作成します (このための ID で遊ぶことができます)。次に、ソース テーブルが null であるテーブルで左結合します。
DECLARE @Seq TABLE (id INT IDENTITY(1, 1))
DECLARE @iter INT = 1
WHILE @iter <= (
SELECT MAX([your ID column])
FROM [Offending Table]
)
BEGIN
INSERT @Seq DEFAULT
VALUES
SET @iter = @iter + 1
END
SELECT id
FROM @seq s
LEFT JOIN [Offending Table] ot ON s.id = ot.[your ID column]
WHERE ot.[your ID column] IS NULL