查找两行之间关系的记录

时间:2015-01-30 05:29:02

标签: sql sql-server

我必须在关联表中的2个记录之间找到一些记录。我无法修改表格,因为它是SAP的表格。

实施例: 表A

DocEntry   LineSeq   AftLine  lineText
1          0         -1       text-before-item        
1          0         1        text-item 1-1
1          1         1        text-item 1-2
1          0         2        text-item 2-1
1          1         2        text-item 2-2
1          0         3        text-item 2-3
1          0         4        text-item 2-4

表B

DocEntry   LineNum    ItemCode
1          1          item 1
1          2          item 2
1          5          item 3

现在,我需要像这样加入两个表:

DocEntry   LineSeq   AftLine  LineNum  ItemCode lineText
1          0         -1                         text-before-item
1          0         1        1        item 1   text-item 1-1
1          1         1        1        item 1   text-item 1-2
1          0         2        2        item 2   text-item 2-1
1          1         2        2        item 2   text-item 2-2
1          0         3        2        item 2   text-item 2-3
1          0         4        2        item 2   text-item 2-4
1                             5        item 3

如何使用"在行之间加入2个表"参数?数字不是连续的。所以,请不要使用LineNum - 1。 Aftline始终大于对应的订单项,但低于下一个订单项,先按AftLine排序,然后按LineSeq排序。

这就是我想出来的,但最终得到的所有项目都在LineNum以下

SELECT i1.ItemCode, i1.LineNum, AftLineNum, LineText FROM B i1 
FULL OUTER JOIN A i10 on i10.DocEntry = i1.DocEntry 
AND i10.AftLineNum >= i1.LineNum 
AND i10.AftLineNum < (
    SELECT TOP 1 LineNum FROM B WHERE DocEntry = i1.DocEntry 
        AND B.LineNum > i1.LineNum
        ORDER BY LineNum DESC
)
where i1.DocEntry = 1030

谢谢。

2 个答案:

答案 0 :(得分:0)

选择低于某个AftLine值的最高lineNum:

SELECT A.*,(SELECT TOP 1 ItemCode FROM B WHERE B.LineNum < A.AftLine ORDER BY B.LineNum DESC) FROM A 

最后一行必须单独使用并UNIONed到结果集:

UNION 
SELECT (NULL, NULL, NULL, NULL, NULL, (SELECT TOP 1 ItemCode FROM B ORDER BY B.LineNum DESC) FROM B

一如既往未经测试,但我想您可以为自己解决小的语法错误......

答案 1 :(得分:0)

制作包含样本数据的表格:

DECLARE @A TABLE (DocEntry int, LineSeq int, AftLine int, lineText varchar(255));

INSERT INTO @A (DocEntry, LineSeq, AftLine, lineText) VALUES (1, 0, -1, 'text-before-item');
INSERT INTO @A (DocEntry, LineSeq, AftLine, lineText) VALUES (1, 0, 1 , 'text-item 1-1');
INSERT INTO @A (DocEntry, LineSeq, AftLine, lineText) VALUES (1, 1, 1 , 'text-item 1-2');
INSERT INTO @A (DocEntry, LineSeq, AftLine, lineText) VALUES (1, 0, 2 , 'text-item 2-1');
INSERT INTO @A (DocEntry, LineSeq, AftLine, lineText) VALUES (1, 1, 2 , 'text-item 2-2');
INSERT INTO @A (DocEntry, LineSeq, AftLine, lineText) VALUES (1, 0, 3 , 'text-item 2-3');
INSERT INTO @A (DocEntry, LineSeq, AftLine, lineText) VALUES (1, 0, 4 , 'text-item 2-4');

DECLARE @B TABLE (DocEntry int, LineNum int, ItemCode varchar(255));

INSERT INTO @B (DocEntry, LineNum, ItemCode) VALUES (1, 1, 'item 1');
INSERT INTO @B (DocEntry, LineNum, ItemCode) VALUES (1, 2, 'item 2');
INSERT INTO @B (DocEntry, LineNum, ItemCode) VALUES (1, 5, 'item 3');

对于表A中的每一行,使用OUTER APPLY从表B中找到合适的行。

SELECT *
FROM
    @A AS TableA
    OUTER APPLY
    (
        SELECT TOP(1) TableB.LineNum, TableB.ItemCode
        FROM @B AS TableB
        WHERE
            TableB.DocEntry = TableA.DocEntry
            AND TableB.LineNum <= TableA.AftLine
        ORDER BY TableB.LineNum DESC
    ) AS B
ORDER BY DocEntry, AftLine, LineSeq;

结果集:

DocEntry    LineSeq    AftLine    lineText            LineNum    ItemCode
1           0          -1         text-before-item    NULL       NULL
1           0          1          text-item 1-1       1          item 1
1           1          1          text-item 1-2       1          item 1
1           0          2          text-item 2-1       2          item 2
1           1          2          text-item 2-2       2          item 2
1           0          3          text-item 2-3       2          item 2
1           0          4          text-item 2-4       2          item 2

如您所见,此处不会返回B中不匹配的行。 很可能您在表B中有一些唯一的ID列,因此将其包含在此中间结果集中,然后将UNION表B中的那些行包含在此中间结果集中。

不使用ID,它可能如下所示:

WITH
CTE
AS
(
    SELECT
        TableA.DocEntry
        ,TableA.LineSeq
        ,TableA.AftLine
        ,TableA.lineText
        ,B.LineNum
        ,B.ItemCode
    FROM
        @A AS TableA
        OUTER APPLY
        (
            SELECT TOP(1) TableB.LineNum, TableB.ItemCode
            FROM @B AS TableB
            WHERE
                TableB.DocEntry = TableA.DocEntry
                AND TableB.LineNum <= TableA.AftLine
            ORDER BY TableB.LineNum DESC
        ) AS B
)
SELECT
    DocEntry
    ,LineSeq
    ,AftLine
    ,lineText
    ,LineNum
    ,ItemCode
FROM CTE

UNION ALL

SELECT
    TableB.DocEntry
    ,NULL AS LineSeq
    ,NULL AS AftLine
    ,NULL AS lineText
    ,TableB.LineNum
    ,TableB.ItemCode
FROM
    @B AS TableB
    LEFT JOIN CTE ON
        TableB.DocEntry = CTE.DocEntry
        AND TableB.LineNum = CTE.LineNum
WHERE
    CTE.DocEntry IS NULL
    AND CTE.LineNum IS NULL
ORDER BY DocEntry, AftLine, LineSeq;

结果集:

DocEntry    LineSeq    AftLine    lineText            LineNum    ItemCode
1           NULL       NULL       NULL                5          item 3
1           0          -1         text-before-item    NULL       NULL
1           0          1          text-item 1-1       1          item 1
1           1          1          text-item 1-2       1          item 1
1           0          2          text-item 2-1       2          item 2
1           1          2          text-item 2-2       2          item 2
1           0          3          text-item 2-3       2          item 2
1           0          4          text-item 2-4       2          item 2