SQL如何选择行正上方的行的内容,并将两者移动到新表中

SQL如何选择行正上方的行的内容,并将两者移动到新表中,sql,sql-server,tsql,Sql,Sql Server,Tsql,我正在尝试写一些东西来自动清理一些旅行数据。将这些视为航班: 航班: ID DocType Name Travel Date Fare Paid 1 INV Mrs G 13/03/2017 37.6 2 INV Mrs G 13/03/2017 200 3 INV Mr H 14/03/2017 60 4 INV

我正在尝试写一些东西来自动清理一些旅行数据。将这些视为航班:

航班:

ID      DocType     Name        Travel Date     Fare Paid
1       INV     Mrs G       13/03/2017      37.6
2       INV     Mrs G       13/03/2017      200
3       INV     Mr H        14/03/2017      60
4       INV     Mr H        15/03/2017      126
5       CRN     Mr H        15/03/2017      126
6       INV     Mr H        20/03/2017      126
7       INV     Mrs S       29/03/2017      110
8       INV     Mr J        26/03/2017      54
9       INV     Mr R        13/03/2017      200
10      INV     Miss C      27/03/2017      78.98
有时人们买了一个航班,然后得到退款。这在数据中显示为两个相同的条目,但退款是DocType“CRN”。我需要能够将预订和退款线从数据集中取出

我可以为CRN标记的行执行此操作。但是,如何才能拉出CRN行正上方的行?相关INV行的ID将始终具有直接顺序低于CRN行的ID

我成功了

INSERT INTO TRAVEL.REFUNDS (ID, DocType, Name, [Travel Date], [Fare Paid])
SELECT ID, DocType, Name, [Travel Date], [Fare Paid]
FROM TRAVEL.FLIGHTS
WHERE [DocType] = 'CRN';
GO

提前谢谢你

这是为了
选择
的目的,不确定你是想要它还是
插入
删除
,但希望它可以很容易地重新编写,而且在修改之前检查一下也很好,对吗

我正在做的是,我正在使用/添加一个新列,它主要是其他行列的副本,尽管它向上或向下移动了一行。这样,每一行都将包含决定如何处理它所需的所有内容,这将在针对较低查询结果的较高查询中完成

-- Making an MCVE, first time I know its name though.
DECLARE @Flights TABLE (ID int, DocType char(3))
INSERT INTO @Flights VALUES
    ( 1, 'INV')
  , ( 2, 'INV')
  , ( 3, 'INV') -- Should not show up.
  , ( 4, 'CRN') -- Should not show up.
  , ( 5, 'INV')
  , ( 6, 'INV')
  , ( 7, 'INV')
  , ( 8, 'INV')
  , ( 9, 'INV')
  , (10, 'INV') -- Should not show up.
  , (11, 'CRN') -- Should not show up.

-- Querying via LEAD(), with 1 level nesting (or subquerying, I dunno which is which).
SELECT *
FROM (
    SELECT ID
         , DocType AS DocTypeThis
         , LEAD(DocType) OVER(ORDER BY ID ASC) AS DocTypeOther -- Seems like the choice of ASC/DESC reverses LAG/LEAD behaviours into each other, although not sure.
    FROM @Flights
) AS T
WHERE (DocTypeOther IS NULL AND DocTypeThis = 'INV') -- Special treatment for last row (for other implementations, might be first row).
   OR DocTypeThis = DocTypeOther -- This is the core of filtering, this fails only when the row is a 'CRN', or is superceded directly by a 'CRN'.
ORDER BY ID ASC

这是为了
SELECT
的目的,不确定您是否需要它,或者
INSERT
或者
DELETE
,但是希望它可以很容易地重新编写,而且在修改之前检查一下也很好,对吗

我正在做的是,我正在使用/添加一个新列,它主要是其他行列的副本,尽管它向上或向下移动了一行。这样,每一行都将包含决定如何处理它所需的所有内容,这将在针对较低查询结果的较高查询中完成

-- Making an MCVE, first time I know its name though.
DECLARE @Flights TABLE (ID int, DocType char(3))
INSERT INTO @Flights VALUES
    ( 1, 'INV')
  , ( 2, 'INV')
  , ( 3, 'INV') -- Should not show up.
  , ( 4, 'CRN') -- Should not show up.
  , ( 5, 'INV')
  , ( 6, 'INV')
  , ( 7, 'INV')
  , ( 8, 'INV')
  , ( 9, 'INV')
  , (10, 'INV') -- Should not show up.
  , (11, 'CRN') -- Should not show up.

-- Querying via LEAD(), with 1 level nesting (or subquerying, I dunno which is which).
SELECT *
FROM (
    SELECT ID
         , DocType AS DocTypeThis
         , LEAD(DocType) OVER(ORDER BY ID ASC) AS DocTypeOther -- Seems like the choice of ASC/DESC reverses LAG/LEAD behaviours into each other, although not sure.
    FROM @Flights
) AS T
WHERE (DocTypeOther IS NULL AND DocTypeThis = 'INV') -- Special treatment for last row (for other implementations, might be first row).
   OR DocTypeThis = DocTypeOther -- This is the core of filtering, this fails only when the row is a 'CRN', or is superceded directly by a 'CRN'.
ORDER BY ID ASC
使用
exists()

左连接

select t.*
from t
  left join t i
    on i.id-1 = t.id 
where t.DocType = 'CRN' 
   or i.DocType = 'CRN'
rextester演示:

返回:

+----+---------+--------+------------+----------+
| ID | DocType |  Name  | TravelDate | FarePaid |
+----+---------+--------+------------+----------+
|  4 | INV     | Mr H   | 15.03.2017 | 126.00   |
|  5 | CRN     | Mr H   | 15.03.2017 | 126.00   |
+----+---------+--------+------------+----------+
+----+---------+--------+------------+----------+
| ID | DocType |  Name  | TravelDate | FarePaid |
+----+---------+--------+------------+----------+
|  1 | INV     | Mrs G  | 13.03.2017 | 37.60    |
|  2 | INV     | Mrs G  | 13.03.2017 | 200.00   |
|  3 | INV     | Mr H   | 14.03.2017 | 60.00    |
|  6 | INV     | Mr H   | 20.03.2017 | 126.00   |
|  7 | INV     | Mrs S  | 29.03.2017 | 110.00   |
|  8 | INV     | Mr J   | 26.03.2017 | 54.00    |
|  9 | INV     | Mr R   | 13.03.2017 | 200.00   |
| 10 | INV     | Miss C | 27.03.2017 | 78.98    |
+----+---------+--------+------------+----------+

对相反的结果集使用
notexists()

select *
from t
where DocType = 'INV'
  and not exists (
    select 1
    from t i
    where i.DocType='CRN'
      and i.id-1 = t.id
)
返回:

+----+---------+--------+------------+----------+
| ID | DocType |  Name  | TravelDate | FarePaid |
+----+---------+--------+------------+----------+
|  4 | INV     | Mr H   | 15.03.2017 | 126.00   |
|  5 | CRN     | Mr H   | 15.03.2017 | 126.00   |
+----+---------+--------+------------+----------+
+----+---------+--------+------------+----------+
| ID | DocType |  Name  | TravelDate | FarePaid |
+----+---------+--------+------------+----------+
|  1 | INV     | Mrs G  | 13.03.2017 | 37.60    |
|  2 | INV     | Mrs G  | 13.03.2017 | 200.00   |
|  3 | INV     | Mr H   | 14.03.2017 | 60.00    |
|  6 | INV     | Mr H   | 20.03.2017 | 126.00   |
|  7 | INV     | Mrs S  | 29.03.2017 | 110.00   |
|  8 | INV     | Mr J   | 26.03.2017 | 54.00    |
|  9 | INV     | Mr R   | 13.03.2017 | 200.00   |
| 10 | INV     | Miss C | 27.03.2017 | 78.98    |
+----+---------+--------+------------+----------+
使用
exists()

左连接

select t.*
from t
  left join t i
    on i.id-1 = t.id 
where t.DocType = 'CRN' 
   or i.DocType = 'CRN'
rextester演示:

返回:

+----+---------+--------+------------+----------+
| ID | DocType |  Name  | TravelDate | FarePaid |
+----+---------+--------+------------+----------+
|  4 | INV     | Mr H   | 15.03.2017 | 126.00   |
|  5 | CRN     | Mr H   | 15.03.2017 | 126.00   |
+----+---------+--------+------------+----------+
+----+---------+--------+------------+----------+
| ID | DocType |  Name  | TravelDate | FarePaid |
+----+---------+--------+------------+----------+
|  1 | INV     | Mrs G  | 13.03.2017 | 37.60    |
|  2 | INV     | Mrs G  | 13.03.2017 | 200.00   |
|  3 | INV     | Mr H   | 14.03.2017 | 60.00    |
|  6 | INV     | Mr H   | 20.03.2017 | 126.00   |
|  7 | INV     | Mrs S  | 29.03.2017 | 110.00   |
|  8 | INV     | Mr J   | 26.03.2017 | 54.00    |
|  9 | INV     | Mr R   | 13.03.2017 | 200.00   |
| 10 | INV     | Miss C | 27.03.2017 | 78.98    |
+----+---------+--------+------------+----------+

对相反的结果集使用
notexists()

select *
from t
where DocType = 'INV'
  and not exists (
    select 1
    from t i
    where i.DocType='CRN'
      and i.id-1 = t.id
)
返回:

+----+---------+--------+------------+----------+
| ID | DocType |  Name  | TravelDate | FarePaid |
+----+---------+--------+------------+----------+
|  4 | INV     | Mr H   | 15.03.2017 | 126.00   |
|  5 | CRN     | Mr H   | 15.03.2017 | 126.00   |
+----+---------+--------+------------+----------+
+----+---------+--------+------------+----------+
| ID | DocType |  Name  | TravelDate | FarePaid |
+----+---------+--------+------------+----------+
|  1 | INV     | Mrs G  | 13.03.2017 | 37.60    |
|  2 | INV     | Mrs G  | 13.03.2017 | 200.00   |
|  3 | INV     | Mr H   | 14.03.2017 | 60.00    |
|  6 | INV     | Mr H   | 20.03.2017 | 126.00   |
|  7 | INV     | Mrs S  | 29.03.2017 | 110.00   |
|  8 | INV     | Mr J   | 26.03.2017 | 54.00    |
|  9 | INV     | Mr R   | 13.03.2017 | 200.00   |
| 10 | INV     | Miss C | 27.03.2017 | 78.98    |
+----+---------+--------+------------+----------+

每个CRN行是否总是在其正上方有其相关的INV?如果情况并非总是如此,则“拉出CRN行正上方的行”将无济于事。如果它总是出现在正上方。。。是否因此而产生了订单条款?如果是的话,你点什么?谢谢你的回复。作为回应,我把数据集弄得更清楚了。相关INV始终位于CRN行的正上方,因为这是提供数据的方式。我立即上传到SQL中,并分配一个ID(主键),它现在位于数据集中。我曾考虑过order by,但无法解决如何在INSERT INTO指令中进行通信。鉴于RDBMS中的行表示无序集,请定义“以上”。请看:相关的INV有一个ID,它是顺序的,并且直接地,在CRN行ID之前(‘上面’)(我在文章中已经清楚地说明了这一点)。欢迎您不要提供任何东西。谢谢您的光临。每个CRN行都会在其正上方有其相关的INV吗?如果情况并非总是如此,则“拉出CRN行正上方的行”将无济于事。如果它总是出现在正上方。。。是否因此而产生了订单条款?如果是的话,你点什么?谢谢你的回复。作为回应,我把数据集弄得更清楚了。相关INV始终位于CRN行的正上方,因为这是提供数据的方式。我立即上传到SQL中,并分配一个ID(主键),它现在位于数据集中。我曾考虑过order by,但无法解决如何在INSERT INTO指令中进行通信。鉴于RDBMS中的行表示无序集,请定义“以上”。请看:相关的INV有一个ID,它是顺序的,并且直接地,在CRN行ID之前(‘上面’)(我在文章中已经清楚地说明了这一点)。欢迎您不要提供任何东西。谢谢你的来访。非常感谢你抽出时间。我已经测试过了,效果很好。@JER很乐意帮忙!非常感谢您抽出时间。我已经测试过了,效果很好。@JER很乐意帮忙!我真的很感谢你的解释。我还没能为我的桌子翻译这个,但我会继续尝试,因为我从来没有使用过LAG,我想掌握这个窍门it@JER,不客气,仅供参考,代码和文本中有一些错误,我更正了这些错误并重新措辞,这些都在编辑历史记录的第4项下。我非常感谢您的解释。我还没能为我的桌子翻译这个,但我会继续尝试,因为我从来没有使用过LAG,我想掌握这个窍门it@JER,不客气,仅供参考,代码和文本中有一些错误,我更正了这些错误并重新措辞,这些都在编辑历史记录中的第4项下。