如何根据列的出现顺序提取行

时间:2018-12-19 17:20:53

标签: sql sql-server

我需要使用日期列提取与在“ Out”之前出现的type列中具有“ In”的ID关联的所有行。在提供的数据中,只有ID 1和2会通过测试。 测试数据如下:

CREATE TABLE #Table (
id INT,
[type] varchar(25),
[Dates] Date)

INSERT INTO #Table
VALUES (1, 'In', '2018-10-01'),
 (1, 'In', '2018-11-01'),
 (1, 'Out', '2018-12-01'),
 (2, 'In', '2018-10-01'),
 (2, 'Out', '2018-11-01'),
 (2, 'In', '2018-12-01'),
 (3, 'Out', '2018-10-01'),
 (3, 'In', '2018-11-01')

输出应如下所示:

+----+------+------------+
| id | type |    date    |
+----+------+------------+
|  1 | In   | 2018-10-01 |
|  1 | In   | 2018-11-01 |
|  1 | Out  | 2018-12-01 |
|  2 | In   | 2018-10-01 |
|  2 | Out  | 2018-11-01 |
|  2 | In   | 2018-12-01 |
+----+------+------------+

老实说,我迷失了查询此问题的能力。 我从

开始
SELECT #Table.*, MIN(CASE WHEN #Table.[type] = 'In' THEN #Table.Dates ELSE NULL END) As A
    ,MIN(CASE WHEN #Table.[type] = 'Out' THEN #Table.Dates ELSE NULL END) As B
FROM #Table
GROUP BY #Table.id, #Table.[type], #Table.Dates

不确定从那里做什么...

4 个答案:

答案 0 :(得分:3)

如果我理解正确,聚合和having可以解决问题:

select t.id
from #Table t
group by t.id
having min(case when type = 'In' then dates end) < max(case when type = 'Out' then dates end);

这会选择id最早的“入”在最近的“出”之前。

如果需要匹配的行,则可以使用窗口功能inexistsjoin

select t.*
from #table t
where t.id in (select t2.id
               from #Table t2
               group by t2.id
               having min(case when t2.type = 'In' then t2.dates end) < max(case when t2.type = 'Out' then t2.dates end)
              );

答案 1 :(得分:2)

这是使用 Windowed Aggregates 应用于查询的戈登逻辑:

with cte as 
 (
    SELECT #Table.*
        ,MIN(CASE WHEN #Table.[type] = 'In' THEN #Table.Dates ELSE NULL END)
         OVER(PARTITION BY id) As A -- min IN date per id
        ,MAX(CASE WHEN #Table.[type] = 'Out' THEN #Table.Dates ELSE NULL END)
         OVER(PARTITION BY id) As B -- max OUT date per id
    FROM #Table
 )
select *
from cte
where a < b

当然也可以使用子查询:

select *
from #Table
where id in 
 ( Gordon's Select )

答案 2 :(得分:2)

您可以使用内部联接尝试以下操作,如下所示。

SELECT Cust_No, 
       Account_No,  
       Product_H_f, 
       Product_H_L,
       -- returns YES when any row for a customer has 'Training'
       MAX(CASE WHEN Product_H_L='Training' THEN 'Yes' else 'No' end)
       OVER (PARTITION BY Cust_No) as 'Cust_has_Training'
FROM TABLE 

您可以根据需要看到以下输出

CREATE TABLE #Table (
id INT,
[type] varchar(25),
[Dates] Date)

INSERT INTO #Table
VALUES (1, 'In', '2018-10-01'),
 (1, 'In', '2018-11-01'),
 (1, 'Out', '2018-12-01'),
 (2, 'In', '2018-10-01'),
 (2, 'Out', '2018-11-01'),
 (2, 'In', '2018-12-01'),
 (3, 'Out', '2018-10-01'),
 (3, 'In', '2018-11-01')

 SELECT DISTINCT #Table.* FROM(
SELECT  * FROM #Table
)a inner join (
SELECT * FROM #Table
)b on a.id = b.id and a.Dates < b.Dates and a.[type] = 'In' and b.[type] = 'Out'
inner join #Table on a.id = #Table.id

答案 3 :(得分:1)

这可能对您有用:

With CTE As
 (
   Select Id,[Type], [Dates], ROW_NUMBER() OVER(Partition By Id Order By Dates) As rn From #Tbl
 )
 Select * From cte
 Where cte.Id In (Select Distinct Id From CTE Where rn = 1 And [Type] = 'In')