如何根据条件获取上一行和下一行

时间:2019-01-19 12:39:51

标签: sql-server

我正在尝试获取有关获取选定行的上一行和下一行的语句。

Declare @OderDetail table
(
    Id int primary key,
    OrderId int,
    ItemId int,
    OrderDate DateTime2,
    Lookup varchar(15)
)

INSERT INTO @OderDetail 
VALUES  
(1, 10, 1, '2018-06-11', 'A'), 
(2, 10, 2, '2018-06-11', 'BE'), --this
(3, 2, 1, '2018-06-04', 'DR'),
(4, 2, 2, '2018-06-04', 'D'),  --this
(5, 3, 2, '2018-06-14', 'DD'), --this
(6, 4, 2, '2018-06-14', 'R');


DECLARE 
    @ItemId int = 2,
    @orderid int = 10

必填输出:

enter image description here

该过程的输入是订单ID = 10且项目ID = 2,我需要检查item-2是否处于其他任何顺序,即根据订单日期仅匹配记录/订单的上一项和下一项

4 个答案:

答案 0 :(得分:1)

这是你的后代吗?

Declare @OderDetail table
     (Id int primary key,OrderId int,ItemId INT,Lookup varchar(15))

Insert @OderDetail values (1,1, 1,'A')
Insert @OderDetail values (2,1, 2,'BE')
Insert @OderDetail values (3,2, 1,'DR')
Insert @OderDetail values (4,2,2, 'D')
Insert @OderDetail values (5,3,2, 'DD')
Insert @OderDetail values (6,4,2, 'R');

declare @ItemId  int=2 , @orderid int = 2;

查询

With cte As
(
Select ROW_NUMBER() OVER(ORDER BY OrderDate) AS RecN,
* 
From @OderDetail Where ItemId=@ItemId
) 
Select * From cte Where 
RecN Between ((Select Top 1 RecN From cte Where OrderId = @orderid) -1) And
((Select Top 1 RecN From cte Where  OrderId = @orderid) +1) 
Order by id

结果:

RecN    Id  OrderId ItemId  Lookup
1       2   1       2       BE
2       4   2       2       D
3       5   3       2       DD

答案 1 :(得分:1)

根据给定的数据集进行更新:我看到了您要进行的操作。请注意,在某些情况下,给定的行之前没有行-因此它仅返回2而不是3。在这里,我更新了CTE版本。取消注释其他行以查看3而不是2,因为在具有该Itemid的所选行之前有一个。

添加了一个变量来演示如何更好地允许您在更改该数字(即传递参数)之前和之后获得1或在之前/之后获得2-如果行数更少,或者在获得之前或之后没有行在该限制范围内尽可能多。

所有版本的数据设置:

Declare @OderDetail table
(
    Id int primary key,
    OrderId int,
    ItemId int,
    OrderDate DateTime2,
    Lookup varchar(15)
)

INSERT INTO @OderDetail 
VALUES  
(1, 10, 1, '2018-06-11', 'A'), 
(2, 10, 2, '2018-06-11', 'BE'), --this
(3, 2, 1, '2018-06-04', 'DR'),
(4, 2, 2, '2018-06-04', 'D'),  --this
(5, 3, 2, '2018-06-14', 'DD'), --this
(9, 4, 2, '2018-06-14', 'DD'), 
(6, 4, 2, '2018-06-14', 'R'),
--(10, 10, 2, '2018-06-02', 'BE'), -- un-comment to see one before
(23, 4, 2, '2018-06-14', 'R');

DECLARE 
    @ItemId int = 2,
    @orderid int = 2;

CTE更新版本:

DECLARE @rowsBeforeAndAfter INT = 1;
;WITH cte AS (
    SELECT 
        Id,
        OrderId,
        ItemId,
        OrderDate,
        [Lookup],
        ROW_NUMBER() OVER (ORDER BY OrderDate,Id) AS RowNumber
    FROM @OderDetail
    WHERE 
        ItemId = @itemId -- all matches of this
),
myrow AS (
    SELECT TOP 1
        Id,
        OrderId,
        ItemId,
        OrderDate,
        [Lookup],
        RowNumber
    FROM cte
    WHERE 
        ItemId = @itemId 
        AND OrderId = @orderid
)
SELECT 
    cte.Id,
    cte.OrderId,
    cte.ItemId,
    cte.OrderDate,
    cte.[Lookup],
    cte.RowNumber
FROM ctE
INNER JOIN myrow
    ON ABS(cte.RowNumber - myrow.RowNumber) <= @rowsBeforeAndAfter
ORDER BY OrderDate, OrderId;

您可能希望使用CTE方法(请参阅本文的结尾

只需指出,这将获得正确的结果,但可能并非您所追求的,因为它取决于行顺序,并且项id并非具有这两个值的实际行:

SELECT TOP  3
    a.Id,
    a.OrderId,
    a.ItemId,
    a.Lookup
FROM @OderDetail AS a
WHERE 
     a.ItemId = @ItemId

要解决此问题,您可以将ORDER BYTOP 1UNION一起使用,有点难看。 (已使用日期排序和ID上的!=更新。)

SELECT 
        u.Id,
        u.OrderId,
        u.OrderDate,
        u.ItemId,
        u.Lookup
FROM (
    SELECT 
        a.Id,
        a.OrderId,
        a.OrderDate,
        a.ItemId,
        a.Lookup
    FROM @OderDetail AS a
    WHERE 
         a.ItemId = @ItemId
         AND a.OrderId = @orderid
    UNION 
    SELECT top 1
        b.Id,
        b.OrderId,
        b.OrderDate,
        b.ItemId,
        b.Lookup
    FROM @OderDetail AS b
    WHERE 
         b.ItemId = @ItemId
         AND b.OrderId != @orderid
    ORDER BY b.OrderDate desc, b.OrderId
    UNION 
    SELECT top 1
        b.Id,
        b.OrderId,
        b.OrderDate,
        b.ItemId,
        b.Lookup
    FROM @OderDetail AS b
    WHERE 
         b.ItemId = @ItemId
        AND b.OrderId != @orderid
    ORDER BY b.OrderDate asc, b.OrderId 
) AS u
ORDER BY u.OrderDate asc, u.OrderId 

答案 2 :(得分:1)

另一种可能的方法是使用$('input[type=file]').on('change', function(e){.... LAG()函数,它们从前一行和后一行返回的数据形成相同的结果集。

LEAD()

输出:

-- Table
DECLARE @OrderDetail TABLE (
    Id int primary key,
    OrderId int,
    ItemId int,
    OrderDate DateTime2,
    Lookup varchar(15)
)
INSERT INTO @OrderDetail 
VALUES  
   (1, 10, 1, '2018-06-11', 'A'), 
   (2, 10, 2, '2018-06-11', 'BE'), --this
   (3, 2, 1, '2018-06-04', 'DR'),
   (4, 2, 2, '2018-06-04', 'D'),  --this
   (5, 3, 2, '2018-06-14', 'DD'), --this
   (6, 4, 2, '2018-06-14', 'R');

-- Item and order
DECLARE 
    @ItemId int = 2,
    @orderid int = 10

-- Statement    
-- Get previois and next ID for every order, grouped by ItemId, ordered by OrderDate
;WITH cte AS (
   SELECT
      Id,
      LAG(Id, 1) OVER (PARTITION BY ItemId ORDER BY OrderDate) previousId,
      LEAD(Id, 1) OVER (PARTITION BY ItemId ORDER BY OrderDate) nextId,
      ItemId,
      OrderId,
      Lookup
   FROM @OrderDetail   
)
-- Select current, previous and next order
SELECT od.*
FROM cte
CROSS APPLY (SELECT * FROM @OrderDetail WHERE Id = cte.Id) od
WHERE (cte.OrderId = @orderId) AND (cte.ItemId = @ItemId)
UNION ALL
SELECT od.*
FROM cte
CROSS APPLY (SELECT * FROM @OrderDetail WHERE Id = cte.previousId) od
WHERE (cte.OrderId = @orderId) AND (cte.ItemId = @ItemId)
UNION ALL
SELECT od.*
FROM cte
CROSS APPLY (SELECT * FROM @OrderDetail WHERE Id = cte.nextId) od
WHERE (cte.OrderId = @orderId) AND (cte.ItemId = @ItemId)

答案 3 :(得分:0)

我认为它很简单,您可以使用左侧外部连接或外部应用来检查min(Id)和Max(id)

喜欢

Declare @ItemID int = 2
Select * From @OderDetail A
Outer Apply (
    Select MIN(A2.Id) minID, MAX(A2.Id) maxID From @OderDetail A2
    Where A2.ItemId =@ItemID
) I05
Outer Apply(
    Select * From @OderDetail Where Id=minID-1
    Union All
    Select * From @OderDetail Where Id=maxID+1
    ) I052
Where A.ItemId =@ItemID Order By A.Id

让我知道这对您有帮助还是您遇到任何问题...

此致