指定された範囲から未割り当ての範囲を取得したい。たとえば、ID 43のレコードを取得することが親レコードであり、次の画像のように未割り当てのレコードを取得したい。ID44および45のレコードはID43のレコードの子です。
質問する
330 次
1 に答える
1
割り当てられた範囲が重複しないと仮定しました。
SQL フィドル
基本的には 4 つのクエリで構成されます。
Batch_number_from
First Query は、指定された親の Start 番号とBatch_number_from
によって並べ替えられた最初の子レコードのStart番号の間の未割り当ての番号の範囲を検索しBatch_number_from
ます。- 2 番目のクエリは、親の子レコード間にある未割り当ての番号の範囲を検索します。
Batch_number_to
3 番目のクエリは、指定された親の End 番号とBatch_number_to
によって並べ替えられた最後の子レコードのEnd番号の間の未割り当ての番号の範囲を検索しBatch_number_from
ます。- そして最後に、4 番目は、対応する子レコードを持たず、したがって番号が割り当てられていない親レコードを見つけます。
4 つのクエリはすべて、UNION
最初の 3 つのクエリ内には、繰り返される 2 つのサブクエリがあり、一時テーブルに移動できます。これらには と のラベルが付いChildRnk
てNextStart
います。
ChildRnk
によって並べ替えられたすべての子レコードをランク付けしBatch_number_from
ます。
NextStart
特定の子に割り当てられた番号の次のバッチの開始番号を返しますBatch_number_from
(その特定の親レコードに対して別の子がリストされている場合)。
お役に立てれば
MSSQL の場合:
SELECT
ChildRnk.Parent,
Batch_Number_From AS START,
(START-1) AS [End]
FROM
(SELECT
a.Id AS Id,
a.parent_fk AS Parent,
a.Batch_Number_From AS START,
a.Batch_Number_To AS 'End',
RANK() OVER
(PARTITION BY a.parent_fk ORDER BY a.Batch_Number_From ASC) AS Rnk1
FROM
VOUCHER_BATCH_ALLOCATION AS a
WHERE
a.channel_from_fk = 2) ChildRnk
LEFT JOIN
(SELECT
c.Parent,
c.START AS NextStart,
(Rnk1-1) AS Rnk2
FROM
(SELECT
b.Id AS Id,
b.parent_fk AS Parent,
b.Batch_Number_From AS START,
b.Batch_Number_To AS 'End',
RANK()
OVER (PARTITION BY b.parent_fk ORDER BY b.Batch_Number_From ASC) AS Rnk1
FROM
VOUCHER_BATCH_ALLOCATION AS b
WHERE
b.channel_from_fk = 2) c
WHERE
Rnk1 != 1) NextStart
ON
ChildRnk.Parent = NextStart.Parent
AND Rnk1 = Rnk2
LEFT JOIN
VOUCHER_BATCH_ALLOCATION
ON
VOUCHER_BATCH_ALLOCATION.Id = ChildRnk.Parent
AND Rnk1 = 1
WHERE
Batch_Number_From IS NOT NULL
AND Batch_Number_From < START
UNION
SELECT
ChildRnk.Parent,
([End]+1) AS START,
(NextStart-1) AS [End]
FROM
(SELECT
a.Id AS Id,
a.parent_fk AS Parent,
a.Batch_Number_From AS START,
a.Batch_Number_To AS 'End',
RANK()
OVER (PARTITION BY a.parent_fk ORDER BY a.Batch_Number_From ASC) AS Rnk1
FROM
VOUCHER_BATCH_ALLOCATION AS a
WHERE
a.channel_from_fk = 2) ChildRnk
LEFT JOIN
(SELECT
c.Parent,
c.START AS NextStart,
(Rnk1-1) AS Rnk2
FROM
(SELECT
b.Id AS Id,
b.parent_fk AS Parent,
b.Batch_Number_From AS START,
b.Batch_Number_To AS 'End',
RANK() OVER
(PARTITION BY b.parent_fk ORDER BY b.Batch_Number_From ASC) AS Rnk1
FROM
VOUCHER_BATCH_ALLOCATION AS b
WHERE
b.channel_from_fk = 2) c
WHERE
Rnk1 != 1) NextStart
ON
ChildRnk.Parent = NextStart.Parent
AND Rnk1 = Rnk2
LEFT JOIN
VOUCHER_BATCH_ALLOCATION
ON
VOUCHER_BATCH_ALLOCATION.Id = ChildRnk.Parent
AND Rnk1 = 1
WHERE
NextStart IS NOT NULL
AND [End] < NextStart
UNION
SELECT
ChildRnk.Parent,
([End]+1) AS START,
EndLimit.VeryEnd AS [End]
FROM
(SELECT
a.Id AS Id,
a.parent_fk AS Parent,
a.Batch_Number_From AS START,
a.Batch_Number_To AS 'End',
RANK() OVER
(PARTITION BY a.parent_fk ORDER BY a.Batch_Number_From ASC) AS Rnk1
FROM
VOUCHER_BATCH_ALLOCATION AS a
WHERE
a.channel_from_fk = 2) ChildRnk
LEFT JOIN
(SELECT
c.Parent,
c.START AS NextStart,
(Rnk1-1) AS Rnk2
FROM
(SELECT
b.Id AS Id,
b.parent_fk AS Parent,
b.Batch_Number_From AS START,
b.Batch_Number_To AS 'End',
RANK() OVER
(PARTITION BY b.parent_fk ORDER BY b.Batch_Number_From ASC) AS Rnk1
FROM
VOUCHER_BATCH_ALLOCATION AS b
WHERE
b.channel_from_fk = 2) c
WHERE
Rnk1 != 1) NextStart
ON
ChildRnk.Parent = NextStart.Parent
AND Rnk1 = Rnk2
LEFT JOIN
(SELECT
a.Id,
a.Batch_Number_To AS VeryEnd,
Rnk2
FROM
VOUCHER_BATCH_ALLOCATION a
LEFT JOIN
(SELECT
max(ChildRnk.Parent) AS MaxParent,
max(ChildRnk.Rnk1) AS Rnk2
FROM
(SELECT
a.Id AS Id,
a.parent_fk AS Parent,
a.Batch_Number_From AS START,
a.Batch_Number_To AS 'End',
RANK() OVER
(PARTITION BY a.parent_fk ORDER BY a.Batch_Number_From ASC) AS Rnk1
FROM
VOUCHER_BATCH_ALLOCATION AS a
WHERE
a.channel_from_fk = 2) ChildRnk
GROUP BY
ChildRnk.Parent) c
ON
c.MaxParent = a.id
WHERE
a.channel_from_fk = 1) EndLimit
ON
EndLimit.Id = ChildRnk.Parent
AND EndLimit.Rnk2 = Rnk1
WHERE
EndLimit.VeryEnd IS NOT NULL
AND [End] < EndLimit.VeryEnd
UNION
SELECT
a.id AS Parent,
a.Batch_Number_From AS START,
a.Batch_Number_To AS [End]
FROM
VOUCHER_BATCH_ALLOCATION a
WHERE
a.Channel_From_Fk = 1
And a.id not in
(SELECT
Parent_Fk
FROM
VOUCHER_BATCH_ALLOCATION
WHERE
Channel_From_Fk=2)
編集:以下のMySql用に書き直されたスクリプト
SQL フィドル
MySQLの場合、残念ながら、 Rank()は MySQL でサポートされていないため、 Rank()関数を同じ結果を達成する SubQueryに置き換える必要がありました。
SELECT
ChildRnk.Parent,
Batch_Number_From AS START,
(START-1) AS TheEnd
FROM
(SELECT
a.Id AS Id,
a.parent_fk AS Parent,
a.Batch_Number_From AS START,
a.Batch_Number_To AS TheEnd,
Rnk.Rank AS Rnk1
FROM
VOUCHER_BATCH_ALLOCATION AS a
LEFT JOIN
(SELECT
g1.id,
g1.Parent_Fk,
COUNT(*) AS rank
FROM
VOUCHER_BATCH_ALLOCATION AS g1
JOIN
VOUCHER_BATCH_ALLOCATION AS g2
ON
(g2.Batch_Number_From, g2.id) <= (g1.Batch_Number_From, g1.id)
AND g1.Parent_Fk = g2.Parent_Fk
GROUP BY
g1.Parent_Fk,
g1.Batch_Number_From
ORDER BY
g1.Parent_Fk,
rank) Rnk
ON
Rnk.id = a.Id
WHERE
a.channel_from_fk = 2) ChildRnk
LEFT JOIN
(SELECT
c.Parent,
c.START AS NextStart,
(Rnk1-1) AS Rnk2
FROM
(SELECT
b.Id AS Id,
b.parent_fk AS Parent,
b.Batch_Number_From AS START,
b.Batch_Number_To AS TheEnd,
Rnk.Rank AS Rnk1
FROM
VOUCHER_BATCH_ALLOCATION AS b
LEFT JOIN
(SELECT
g1.id,
g1.Parent_Fk,
COUNT(*) AS rank
FROM
VOUCHER_BATCH_ALLOCATION AS g1
JOIN
VOUCHER_BATCH_ALLOCATION AS g2
ON
(g2.Batch_Number_From, g2.id) <= (g1.Batch_Number_From, g1.id)
AND g1.Parent_Fk = g2.Parent_Fk
GROUP BY
g1.Parent_Fk,
g1.Batch_Number_From
ORDER BY
g1.Parent_Fk,
rank) Rnk
ON
Rnk.id = b.Id
WHERE
b.channel_from_fk = 2) c
WHERE Rnk1 != 1) NextStart
ON
ChildRnk.Parent = NextStart.Parent
AND Rnk1 = Rnk2
LEFT JOIN
VOUCHER_BATCH_ALLOCATION
ON
VOUCHER_BATCH_ALLOCATION.Id = ChildRnk.Parent
AND Rnk1 = 1
WHERE
Batch_Number_From IS NOT NULL
AND Batch_Number_From < START
UNION
SELECT
ChildRnk.Parent,
(TheEnd+1) AS START,
(NextStart-1) AS TheEnd
FROM
(SELECT
a.Id AS Id,
a.parent_fk AS Parent,
a.Batch_Number_From AS START,
a.Batch_Number_To AS TheEnd,
Rnk.rank AS Rnk1
FROM
VOUCHER_BATCH_ALLOCATION AS a
LEFT JOIN
(SELECT
g1.id,
g1.Parent_Fk,
COUNT(*) AS rank
FROM
VOUCHER_BATCH_ALLOCATION AS g1
JOIN
VOUCHER_BATCH_ALLOCATION AS g2
ON
(g2.Batch_Number_From, g2.id) <= (g1.Batch_Number_From, g1.id)
AND g1.Parent_Fk = g2.Parent_Fk
GROUP BY
g1.Parent_Fk,
g1.Batch_Number_From
ORDER BY
g1.Parent_Fk,
rank) Rnk
ON
Rnk.id = a.Id
WHERE
a.channel_from_fk = 2) ChildRnk
LEFT JOIN
(SELECT
c.Parent,
c.START AS NextStart,
(Rnk1-1) AS Rnk2
FROM
(SELECT
b.Id AS Id,
b.parent_fk AS Parent,
b.Batch_Number_From AS START,
b.Batch_Number_To AS TheEnd,
Rnk.rank AS Rnk1
FROM
VOUCHER_BATCH_ALLOCATION AS b
LEFT JOIN
(SELECT
g1.id,
g1.Parent_Fk,
COUNT(*) AS rank
FROM
VOUCHER_BATCH_ALLOCATION AS g1
JOIN
VOUCHER_BATCH_ALLOCATION AS g2
ON
(g2.Batch_Number_From, g2.id) <= (g1.Batch_Number_From, g1.id)
AND g1.Parent_Fk = g2.Parent_Fk
GROUP BY
g1.Parent_Fk,
g1.Batch_Number_From
ORDER BY
g1.Parent_Fk,
rank) Rnk
ON
Rnk.id = b.Id
WHERE
b.channel_from_fk = 2) c
WHERE
Rnk1 != 1) NextStart
ON
ChildRnk.Parent = NextStart.Parent
AND Rnk1 = Rnk2
LEFT JOIN
VOUCHER_BATCH_ALLOCATION
ON
VOUCHER_BATCH_ALLOCATION.Id = ChildRnk.Parent
AND Rnk1 = 1
WHERE
NextStart IS NOT NULL
AND TheEnd < NextStart
UNION
SELECT
ChildRnk.Parent,
(TheEnd+1) AS START,
EndLimit.VeryEnd AS TheEnd
FROM
(SELECT
a.Id AS Id,
a.parent_fk AS Parent,
a.Batch_Number_From AS START,
a.Batch_Number_To AS TheEnd,
Rnk.Rank AS Rnk1
FROM
VOUCHER_BATCH_ALLOCATION AS a
LEFT JOIN
(SELECT
g1.id,
g1.Parent_Fk,
COUNT(*) AS rank
FROM
VOUCHER_BATCH_ALLOCATION AS g1
JOIN
VOUCHER_BATCH_ALLOCATION AS g2
ON
(g2.Batch_Number_From, g2.id) <= (g1.Batch_Number_From, g1.id)
AND g1.Parent_Fk = g2.Parent_Fk
GROUP BY
g1.Parent_Fk,
g1.Batch_Number_From
ORDER BY
g1.Parent_Fk,
rank) Rnk
ON
Rnk.id = a.Id
WHERE
a.channel_from_fk = 2) ChildRnk
LEFT JOIN
(SELECT
c.Parent,
c.START AS NextStart,
(Rnk1-1) AS Rnk2
FROM
(SELECT
b.Id AS Id,
b.parent_fk AS Parent,
b.Batch_Number_From AS START,
b.Batch_Number_To AS TheEnd,
Rnk.Rank AS Rnk1
FROM
VOUCHER_BATCH_ALLOCATION AS b
LEFT JOIN
(SELECT
g1.id,
g1.Parent_Fk,
COUNT(*) AS rank
FROM
VOUCHER_BATCH_ALLOCATION AS g1
JOIN
VOUCHER_BATCH_ALLOCATION AS g2
ON
(g2.Batch_Number_From, g2.id) <= (g1.Batch_Number_From, g1.id)
AND g1.Parent_Fk = g2.Parent_Fk
GROUP BY
g1.Parent_Fk,
g1.Batch_Number_From
ORDER BY
g1.Parent_Fk,
rank) Rnk
ON
Rnk.id = b.Id
WHERE
b.channel_from_fk = 2) c
WHERE
Rnk1 != 1) NextStart
ON
ChildRnk.Parent = NextStart.Parent
AND Rnk1 = Rnk2
LEFT JOIN
(SELECT
a.Id,
a.Batch_Number_To AS VeryEnd,
Rnk2
FROM
VOUCHER_BATCH_ALLOCATION a
LEFT JOIN
(SELECT
max(ChildRnk.Parent) AS MaxParent,
max(ChildRnk.Rnk1) AS Rnk2
FROM
(SELECT
a.Id AS Id,
a.parent_fk AS Parent,
a.Batch_Number_From AS START,
a.Batch_Number_To AS TheEnd,
Rnk.Rank AS Rnk1
FROM
VOUCHER_BATCH_ALLOCATION AS a
LEFT JOIN
(SELECT
g1.id,
g1.Parent_Fk,
COUNT(*) AS rank
FROM
VOUCHER_BATCH_ALLOCATION AS g1
JOIN
VOUCHER_BATCH_ALLOCATION AS g2
ON
(g2.Batch_Number_From, g2.id) <= (g1.Batch_Number_From, g1.id)
AND g1.Parent_Fk = g2.Parent_Fk
GROUP BY
g1.Parent_Fk,
g1.Batch_Number_From
ORDER BY
g1.Parent_Fk,
rank) Rnk
ON
Rnk.id = a.Id
WHERE
a.channel_from_fk = 2) ChildRnk
GROUP BY
ChildRnk.Parent) c
ON
c.MaxParent = a.id
WHERE
a.channel_from_fk = 1) EndLimit
ON
EndLimit.Id = ChildRnk.Parent
AND EndLimit.Rnk2 = Rnk1
WHERE
EndLimit.VeryEnd IS NOT NULL
AND TheEnd < EndLimit.VeryEnd
UNION
SELECT
a.id AS Parent,
a.Batch_Number_From AS START,
a.Batch_Number_To AS TheEnd
FROM
VOUCHER_BATCH_ALLOCATION a
WHERE
a.Channel_From_Fk = 1
AND a.id NOT IN (SELECT Parent_Fk FROM VOUCHER_BATCH_ALLOCATION WHERE Channel_From_Fk=2)
お役に立てれば
于 2012-11-22T23:50:04.953 に答える