SQL如何在行的正上方选择行的内容,并将它们移动到新表

时间:2017-05-23 10:30:03

标签: 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     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

提前谢谢

2 个答案:

答案 0 :(得分:0)

这是SELECT目的,不确定您是想要它还是INSERTDELETE,但希望它很容易对那些人加以改变,再加上它们修改前要好好检查一下,对吧?

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

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

答案 1 :(得分:0)

使用exists()

select *
from t 
where DocType = 'CRN' 
   or exists (
    select 1
    from t i
    where i.DocType='CRN'
      and i.id-1 = t.id
)

left join

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

rextester演示:rextester.com/MSGGX10058

返回:

+----+---------+--------+------------+----------+
| ID | DocType |  Name  | TravelDate | FarePaid |
+----+---------+--------+------------+----------+
|  4 | INV     | Mr H   | 15.03.2017 | 126.00   |
|  5 | CRN     | Mr H   | 15.03.2017 | 126.00   |
+----+---------+--------+------------+----------+

使用not exists()作为相反的结果集:

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 |
+----+---------+--------+------------+----------+
|  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    |
+----+---------+--------+------------+----------+