如何分组并从特定行获取值

时间:2018-05-01 08:23:52

标签: sql sql-server

我有这张原始表:

type  startDate   endDate   eatingDate
1     2011        2012       1979
1     2012        2013       1980
1     2013        2014       NULL
2     2014        2015       1982 
3     2015        2016       1983
1     2016        2017       1984
1     2017        2018       1985

这是我想要的结果:

type  startDate   endDate   eatingDate
1     2011        2014       NULL
2     2014        2015       1982 
3     2015        2016       1983
1     2016        2018       1985

我想解决的另一个案例是,在eatDate原始表格的第3行中,值为1981,结果将是:

type  startDate   endDate   eatingDate
1     2011        2014       1981
2     2014        2015       1982 
3     2015        2016       1983
1     2016        2018       1985

注意:具有相同类型的行数未知。

2 个答案:

答案 0 :(得分:1)

我会分三步完成。

使用"隔离岛屿"方法,分配"组标识符"到每个连续的行组。

使用分析功能挑选出您感兴趣的EatingDate。

然后将每个组的所有内容聚合为一行。

WITH
  grouped
AS
(
  SELECT
    ROW_NUMBER() OVER (ORDER BY startDate)
    -
    ROW_NUMBER() OVER (PARTITION BY type ORDER BY startDate)   AS groupID,
    *
  FROM
    eating
),
  analysed
AS
(
  SELECT
    *,
    FIRST_VALUE(eatingDate) OVER (PARTITION BY type, groupID ORDER BY startDate DESC)   AS lastEatingDate
  FROM
    grouped
)
SELECT
  type,
  MIN(startDate     )   AS startDate,
  MAX(endDate       )   AS endDate,
  MAX(lastEatingDate)   AS lastEatingDate
FROM
  analysed
GROUP BY
  type,
  groupID
ORDER BY
  MIN(startDate)

http://sqlfiddle.com/#!18/3cc52/6

<强> 编辑:

通过使用EXISTS代替(降低总体费用),修订了@ GordonLinoff的答案,不需要LEFT JOINLAG

此版本并不假设一行的endDate始终等于后续行的startDate

SELECT DISTINCT
  type, 
  MIN(startDate         ) OVER (PARTITION BY grp                        )   AS startDate,
  MAX(endDate           ) OVER (PARTITION BY grp                        )   AS endDate,
  FIRST_VALUE(eatingDate) OVER (PARTITION BY grp ORDER BY startDate DESC)   AS last_eatingdate
FROM
(
  SELECT
    e.*,
    SUM(isStart) OVER (ORDER BY startDate DESC) as grp
  FROM
  (
    SELECT
      *,
      CASE WHEN LAG(type) OVER (ORDER BY startDate DESC) = type THEN 0 ELSE 1 END   AS isStart
    FROM
      eating
  ) e
) e
ORDER BY
  startDate;

http://sqlfiddle.com/#!18/3cc52/31

答案 1 :(得分:1)

这是一个差距和岛屿问题 - 但有开始和结束日期。我会通过识别岛屿的起点(使用left joinexists)然后累积总和和聚合来做到这一点:

select distinct type, 
       min(startDate) over (partition by type, grp) as startDate,
       max(endDate) over (partition by type, grp) as endDate,
       first_value(eatingDate) over (partition by type, grp order by startDate desc) as last_eatingdate
from (select e.*,
             sum(isStart) over (partition by type order by startDate) as grp
      from (select e.*,
                   (case when e2.type is null then 1 else 0 end) as isStart
            from eating e left join
                 eating e2
                 on e.startdate = e2.enddate and e.type = e2.type
           ) e
     ) e
order by type, startDate;

Here是SQL小提琴。