我想从指定范围中获取未分配的范围,例如以 id 43 的记录是父记录,我想获得如下图所示的未分配记录,id 为 44 和 45 的记录是 id 为 43 的记录的子记录
问问题
330 次
1 回答
1
我假设分配的范围不重叠。
SQL 小提琴
基本上它由四个查询组成。
- 第一个查询查找父项指定
Batch_number_from
的起始编号和按Batch_number_from
排序的第一个子记录的起始编号之间的任何未分配编号范围Batch_number_from
。 - 第二个查询查找位于父项的子记录之间的任何未分配数字范围。
- 第三个查询查找父项指定
Batch_number_to
的 End 编号和按Batch_number_to
排序的最后一个子记录的 End 编号之间的任何未分配编号范围Batch_number_from
。 - 最后,Fourth 查找没有相应子记录并因此没有分配编号的任何父记录。
所有四个查询都使用UNION
在前三个查询中有两个重复的子查询,因此可以移动到临时表中。这些标记为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,我不得不用 SubQuery 替换Rank()函数,这将达到相同的结果,因为MySQL 不支持不幸的Rank() 。
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 回答