1

在此处输入图像描述

我想从指定范围中获取未分配的范围,例如以 id 43 的记录是父记录,我想获得如下图所示的未分配记录,id 为 44 和 45 的记录是 id 为 43 的记录的子记录

在此处输入图像描述

4

1 回答 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

在前三个查询中有两个重复的子查询,因此可以移动到临时表中。这些标记为ChildRnkNextStart

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 回答