在SELECT中包含一个属性,而不必将其包含在GROUP BY中

时间:2013-12-16 15:33:49

标签: sql postgresql select group-by

到目前为止,我列出了本赛季击败大满贯的球员名单。

___________________________________________________
| Player Name | dateOfGrandSlam | distance | home |
---------------------------------------------------
|  Griffin    |    9-14-2013   |    413   | true |
|  Griffin    |    10-1-2013   |    371   | false|
|  Simpson    |    5-15-2013   |    413   | true |
|   Reid      |    7-1-2013    |    362   | true |
|   Reid      |    7-4-2013    |    363   | true |
|   Reid      |    9-28-2013   |    388   | true |
|  Peavis     |    8-14-2013   |    466   | false|

我想得到一份最近的grandslam在家的球员名单。如果他们最近的grandslam不在家,我不希望他们出现在我的名单上。 这意味着,我需要通过播放器选择播放器和组,并从该组中选择最大日期。在该列表中,我还必须包含家/外信息,以便我可以选择那些不在家的信息。

但是我遇到了问题。因为要选择属性home,我还需要在home子句中包含GROUP BY。 例如:

SELECT playerName, MAX(date), distance, home 
FROM grandslams 
GROUP BY playerName, distance, home

问题是这会返回一张表格,其中包含最近的房屋和最近的房屋。


| Player Name | dateOfGrandSlam | distance | home |
---------------------------------------------------
|  Griffin    |    9-14-2013   |    413   | true |
|  Griffin    |    10-1-2013   |    371   | false|
|  Simpson    |    5-15-2013   |    413   | true |
|   Reid      |    9-28-2013   |    388   | true |

这不是我想要的 - 如果最近没有远处的grandslams,我只想要最近的家庭grandslams。

我想要这个结果:

___________________________________________________
| Player Name | dateOfGrandSlam | distance | home |
---------------------------------------------------
|  Simpson    |    5-15-2013   |    413   | true |
|   Reid      |    9-28-2013   |    388   | true |

基本上我需要一种方法来执行查询,这个查询只会让我获得每位玩家最近的grandslam,对home属性进行处理(不必分组,所以我不知道得到他最近的房子和他最近的房子)然后可以在外部查询中轻松过滤。

换句话说,我需要从

获得结果
SELECT playerName, MAX(date), distance
FROM grandSlams
GROUP BY playerName, distance

并将home属性附加到其中。

4 个答案:

答案 0 :(得分:3)

您可以使用row_number()功能查找每位玩家的最新大满贯,并按日期降序排列。要选择最新的,请选择值为1的那个。然后在家中的大满贯中添加条件:

select gs.*
from (select gs.*,
             row_number() over (partition by PlayerName
                                order by dateOfGrandSlam desc) as seqnum
      from GrandSlams gs
     ) gs
where seqnum = 1 and home = true;

答案 1 :(得分:0)

您可以先找到所有最后的本垒打,然后将它们连接到原始表格。

SELECT g.* from (SELECT playerName, MAX(date) date
FROM grandslams 
GROUP BY playerName) a
NATURAL JOIN grandslams g
WHERE g.home = true;

如果您不是自然加入的粉丝(为了ansi的缘故),您可以随时使用

JOIN grandslams g on g.playerName = a.playerName and g.date = a.date

而不是自然连接。 这将使查询ansi。

答案 2 :(得分:0)

解决问题。

1)建立一个查询,让你找到最后一击在家的球员。即,他们最近的家庭大满贯是他们最近的大满贯。

SELECT
  playerName,
  MAX(dateOfGrandSlam) mostRecentGrandSlam
FROM grandSlams
GROUP BY playerName
HAVING MAX(CASE home WHEN 'true' THEN dateOfGrandSlam END) = MAX(dateOfGrandSlam)

2)使用该查询将原始表格过滤为您想要的行:

SELECT a.playerName, a.dateOfGrandSlam, a.distance, a.home
FROM grandSlams a
INNER JOIN (
  SELECT
    playerName,
    MAX(dateOfGrandSlam) mostRecentGrandSlam
  FROM grandSlams
  GROUP BY playerName
  HAVING MAX(CASE home WHEN 'true' THEN dateOfGrandSlam END) = MAX(dateOfGrandSlam)
) b ON (a.playerName = b.playerName AND a.dateOfGrandSlam = b.mostRecentGrandSlam)

答案 3 :(得分:0)

基本查询最简单 DISTINCT ON ,这是SQL标准的 Postgres特定扩展名{ {1}}:

DISTINCT

将效果与EXPLAIN ANALYZE进行比较。本相关答案的详细说明:
Select first row in each GROUP BY group?

使用子查询来消除最近的grandslam不在家的案例:

SELECT DISTINCT ON (playername)
       playername, dateofgrandslam, distance, home 
FROM   grandslams 
GROUP  BY playername, dateofgrandslamDESC;

性能王冠的另一个热门竞争者(取决于你需要的确切),以及纯粹的标准SQL NOT EXISTS反半连接。也比听起来简单:

SELECT * FROM (
    SELECT DISTINCT ON (playername)
           playername, dateofgrandslam, distance, home 
    FROM   grandslams 
    GROUP  BY playername, dateofgrandslam DESC
   ) sub
WHERE  home;

除此之外:使用SELECT playername, dateofgrandslam, distance, home FROM grandslams g WHERE home AND NOT EXISTS ( SELECT 1 FROM grandslams g1 WHERE g1.playername = g.playername AND g1.dateofgrandslam > g.dateofgrandslam ); 的小写字母,因为在Postgres中无论如何都会将不带引号的标识符强制转换为小写。