Sql 从每个嵌套的分组记录中选择第一个记录

Sql 从每个嵌套的分组记录中选择第一个记录,sql,oracle,group-by,Sql,Oracle,Group By,我已经构建了一个查询(在Oracle中),从重复的行中选择任何具有最大日期的行。我的查询基于显示的查询,该查询使用嵌套分组: SELECT * FROM ( SELECT Train, MAX(Time) as MaxTime FROM TrainTable GROUP BY Train ) r INNER JOIN TrainTable t ON t.Train = r.Train AND t.Time = r.MaxTime 现在,由于该查询不考虑Tim

我已经构建了一个查询(在Oracle中),从重复的行中选择任何具有最大日期的行。我的查询基于显示的查询,该查询使用嵌套分组:

SELECT *
FROM (
      SELECT Train, MAX(Time) as MaxTime
      FROM TrainTable
      GROUP BY Train
) r
INNER JOIN TrainTable t
ON t.Train = r.Train AND t.Time = r.MaxTime
现在,由于该查询不考虑
Time
(如注释所示)中的重复值,因此我希望从每个“重复”分组记录中取出第一个记录,并且仍然能够使用
选择*

我怎么做

(另一方面,我尝试使用另一种解决方案(使用
覆盖(分区…
),但它不起作用,我需要找出答案)

使用
行编号()

当存在匹配的
时间的关联时,此操作将返回任意行。SQL表表示无序的集合,因此没有“第一”行,除非另一列指定该排序。如果是这样,那么您可以将该列包括在
order by
子句中。

使用
行号()

CREATE TABLE TrainTable(
    train varchar(10),
    Time  date
);
INSERT INTO TrainTable values ('A',to_date('2017-01-01','YYYY-MM-DD'));
INSERT INTO TrainTable values ('A',to_date('2018-01-01','YYYY-MM-DD'));
INSERT INTO TrainTable values ('B',to_date('2017-05-01','YYYY-MM-DD'));
INSERT INTO TrainTable values ('B',to_date('2017-05-05','YYYY-MM-DD'));
INSERT INTO TrainTable values ('C',to_date('2017-01-01','YYYY-MM-DD'));

当存在匹配的
时间的关联时,此操作将返回任意行。SQL表表示无序的集合,因此没有“第一”行,除非另一列指定该排序。如果是这样,那么您可以将该列包括在
order by
子句中。

如果表(
TrainTable
)中有
PK
,那么您可以使用
fetch first
子句和
子查询

select t.*
from traintable t
where t.pk = (select t1.pk
              from traintable t1
              where t1.train = t.train 
              order by t1.time desc
              fetch first 1 rows only
             );
CREATE TABLE TrainTable(
    train varchar(10),
    Time  date
);
INSERT INTO TrainTable values ('A',to_date('2017-01-01','YYYY-MM-DD'));
INSERT INTO TrainTable values ('A',to_date('2018-01-01','YYYY-MM-DD'));
INSERT INTO TrainTable values ('B',to_date('2017-05-01','YYYY-MM-DD'));
INSERT INTO TrainTable values ('B',to_date('2017-05-05','YYYY-MM-DD'));
INSERT INTO TrainTable values ('C',to_date('2017-01-01','YYYY-MM-DD'));

如果表(
TrainTable
)中有
PK
,则可以将
fetchfirst
子句与
子查询一起使用:

select t.*
from traintable t
where t.pk = (select t1.pk
              from traintable t1
              where t1.train = t.train 
              order by t1.time desc
              fetch first 1 rows only
             );

这里是另一种不用窗口功能的方法

您可以尝试在
select
中使用子查询,以获取
COUNT
be行号,并在子查询
where
子句中设置
按列划分

CREATE TABLE TrainTable(
    train varchar(10),
    Time  date
);
INSERT INTO TrainTable values ('A',to_date('2017-01-01','YYYY-MM-DD'));
INSERT INTO TrainTable values ('A',to_date('2018-01-01','YYYY-MM-DD'));
INSERT INTO TrainTable values ('B',to_date('2017-05-01','YYYY-MM-DD'));
INSERT INTO TrainTable values ('B',to_date('2017-05-05','YYYY-MM-DD'));
INSERT INTO TrainTable values ('C',to_date('2017-01-01','YYYY-MM-DD'));
查询1

SELECT *
FROM 
(
    SELECT t.*,(SELECT 
                COUNT(*) FROM TrainTable t1 
                WHERE t1.Time >= t.Time AND 
                      t1.train = t.train
               ) rn
    FROM TrainTable t
    ORDER BY t.Time DESC
) t
where t.rn = 1
| TRAIN |                 TIME | RN |
|-------|----------------------|----|
|     A | 2018-01-01T00:00:00Z |  1 |
|     B | 2017-05-05T00:00:00Z |  1 |
|     C | 2017-01-01T00:00:00Z |  1 |

SELECT *
FROM 
(
    SELECT t.*,(SELECT 
                COUNT(*) FROM TrainTable t1 
                WHERE t1.Time >= t.Time AND 
                      t1.train = t.train
               ) rn
    FROM TrainTable t
    ORDER BY t.Time DESC
) t
where t.rn = 1
| TRAIN |                 TIME | RN |
|-------|----------------------|----|
|     A | 2018-01-01T00:00:00Z |  1 |
|     B | 2017-05-05T00:00:00Z |  1 |
|     C | 2017-01-01T00:00:00Z |  1 |

这里是另一种不用窗口功能的方法

您可以尝试在
select
中使用子查询,以获取
COUNT
be行号,并在子查询
where
子句中设置
按列划分

CREATE TABLE TrainTable(
    train varchar(10),
    Time  date
);
INSERT INTO TrainTable values ('A',to_date('2017-01-01','YYYY-MM-DD'));
INSERT INTO TrainTable values ('A',to_date('2018-01-01','YYYY-MM-DD'));
INSERT INTO TrainTable values ('B',to_date('2017-05-01','YYYY-MM-DD'));
INSERT INTO TrainTable values ('B',to_date('2017-05-05','YYYY-MM-DD'));
INSERT INTO TrainTable values ('C',to_date('2017-01-01','YYYY-MM-DD'));
查询1

SELECT *
FROM 
(
    SELECT t.*,(SELECT 
                COUNT(*) FROM TrainTable t1 
                WHERE t1.Time >= t.Time AND 
                      t1.train = t.train
               ) rn
    FROM TrainTable t
    ORDER BY t.Time DESC
) t
where t.rn = 1
| TRAIN |                 TIME | RN |
|-------|----------------------|----|
|     A | 2018-01-01T00:00:00Z |  1 |
|     B | 2017-05-05T00:00:00Z |  1 |
|     C | 2017-01-01T00:00:00Z |  1 |

SELECT *
FROM 
(
    SELECT t.*,(SELECT 
                COUNT(*) FROM TrainTable t1 
                WHERE t1.Time >= t.Time AND 
                      t1.train = t.train
               ) rn
    FROM TrainTable t
    ORDER BY t.Time DESC
) t
where t.rn = 1
| TRAIN |                 TIME | RN |
|-------|----------------------|----|
|     A | 2018-01-01T00:00:00Z |  1 |
|     B | 2017-05-05T00:00:00Z |  1 |
|     C | 2017-01-01T00:00:00Z |  1 |

如果您坚持在回答中使用此示例,您可以将当前查询合并到WITH块中,然后选择DISTINCT,如下所示:

WITH query AS (
  SELECT r.*
  FROM (
    SELECT train, MAX(trainTime) as MaxTime
    FROM trainTimes
    GROUP BY train
  ) r
  INNER JOIN trainTimes t
  ON t.train = r.train AND t.trainTime = r.MaxTime
)
SELECT DISTINCT *
FROM query;
下面是这项工作的SQL版本:

但是


这是低效的,虽然它适用于当前示例,但在真实的DB中可能会变得混乱。如果Gordon的答案为您提供了所需的输出,那么这是一个更好的解决方案。

如果您坚持在答案中使用此示例,您可以将当前查询合并到WITH块中,然后选择DISTINCT,如下所示:

WITH query AS (
  SELECT r.*
  FROM (
    SELECT train, MAX(trainTime) as MaxTime
    FROM trainTimes
    GROUP BY train
  ) r
  INNER JOIN trainTimes t
  ON t.train = r.train AND t.trainTime = r.MaxTime
)
SELECT DISTINCT *
FROM query;
下面是这项工作的SQL版本:

但是


这是低效的,虽然它适用于当前示例,但在真实的DB中可能会变得混乱。如果Gordon的答案提供了所需的输出,那么这是一个更好的解决方案。

那么基本上,您希望能够使用“SELECT*FROM”和Group By子句?老实说,即使您得到了满意的答案,它也不如学习和理解“其他解决方案”对分区的作用。理解起来更复杂,但很值得您花费时间。@Barrypicanni,我当然会这么做,但我也想知道如何使用这种查询:)所以基本上,您希望能够使用“SELECT*FROM”和Group By子句?老实说,即使您得到了满意的答案,它也不如学习和理解“其他解决方案”对分区的作用。理解起来更复杂,但也很值得你花时间。@Barrypicanni,我当然会这么做,但我也想知道如何使用这种查询:)如果不使用
分区
,似乎没有足够简单和高效的方法来做,所以尽管这个答案没有使用原始查询,我会接受的。如果不使用
分区
,似乎没有足够简单和高效的方法来完成它,所以尽管这个答案不使用原始查询,我还是会接受它。