如何选择最大值(column value)的行,与sql中的另一列不同?

xbp102n0  于 2021-06-25  发布在  Mysql
关注(0)|答案(19)|浏览(514)

我的table是:

id  home  datetime     player   resource
---|-----|------------|--------|---------
1  | 10  | 04/03/2009 | john   | 399 
2  | 11  | 04/03/2009 | juliet | 244
5  | 12  | 04/03/2009 | borat  | 555
3  | 10  | 03/03/2009 | john   | 300
4  | 11  | 03/03/2009 | juliet | 200
6  | 12  | 03/03/2009 | borat  | 500
7  | 13  | 24/12/2008 | borat  | 600
8  | 13  | 01/01/2009 | borat  | 700

我需要选择每个不同的 home 保持最大值 datetime .
结果是:

id  home  datetime     player   resource 
---|-----|------------|--------|---------
1  | 10  | 04/03/2009 | john   | 399
2  | 11  | 04/03/2009 | juliet | 244
5  | 12  | 04/03/2009 | borat  | 555
8  | 13  | 01/01/2009 | borat  | 700

我试过:

-- 1 ..by the MySQL manual: 

SELECT DISTINCT
  home,
  id,
  datetime AS dt,
  player,
  resource
FROM topten t1
WHERE datetime = (SELECT
  MAX(t2.datetime)
FROM topten t2
GROUP BY home)
GROUP BY datetime
ORDER BY datetime DESC

不起作用。结果集有130行,但数据库有187行。结果包括的一些副本 home .

-- 2 ..join

SELECT
  s1.id,
  s1.home,
  s1.datetime,
  s1.player,
  s1.resource
FROM topten s1
JOIN (SELECT
  id,
  MAX(datetime) AS dt
FROM topten
GROUP BY id) AS s2
  ON s1.id = s2.id
ORDER BY datetime

不。提供所有记录。

-- 3 ..something exotic:

结果各不相同。

rvpgvaaj

rvpgvaaj1#

即使每个行有两行或更多行,也可以这样做 home 具有相等的 DATETIME 的:

SELECT id, home, datetime, player, resource
FROM   (
       SELECT (
              SELECT  id
              FROM    topten ti
              WHERE   ti.home = t1.home
              ORDER BY
                      ti.datetime DESC
              LIMIT 1
              ) lid
       FROM   (
              SELECT  DISTINCT home
              FROM    topten
              ) t1
       ) ro, topten t2
WHERE  t2.id = ro.lid
sg3maiej

sg3maiej2#

SELECT c1, c2, c3, c4, c5 FROM table1 WHERE c3 = (select max(c3) from table)

SELECT * FROM table1 WHERE c3 = (select max(c3) from table1)
eit6fx6z

eit6fx6z3#

另一种方法是使用子查询对每个组最近的行进行gt,子查询基本上为每个组的每一行计算一个秩,然后过滤出最近的行,如秩=1

select a.*
from topten a
where (
  select count(*)
  from topten b
  where a.home = b.home
  and a.`datetime` < b.`datetime`
) +1 = 1

演示
为了更好地理解,下面是每一行的rank no的可视化演示
通过阅读一些注解,如果有两行具有相同的“home”和“datetime”字段值,该怎么办?
对于上述情况,上述查询将失败并返回超过1行。为了掩盖这种情况,需要另一个标准/参数/列来决定应该采取哪一行哪一行属于上述情况。通过查看示例数据集,我假设有一个主键列 id 应该设置为自动递增。因此,我们可以使用此列通过在 CASE 陈述式

select a.*
from topten a
where (
  select count(*)
  from topten b
  where a.home = b.home
  and  case 
       when a.`datetime` = b.`datetime`
       then a.id < b.id
       else a.`datetime` < b.`datetime`
       end
) + 1 = 1

演示
上面的查询将在同一行中选取id最高的行 datetime 价值观
每行排名的视觉演示

1cklez4t

1cklez4t4#

既然人们似乎一直在碰到这样的主题(评论日期从1.5年开始),那就不是这么简单了: SELECT * FROM (SELECT * FROM topten ORDER BY datetime DESC) tmp GROUP BY home 不需要聚合函数。。。
干杯。

62lalag4

62lalag45#

对于sql server,请尝试以下操作:

WITH cte AS (
   SELECT home, MAX(year) AS year FROM Table1 GROUP BY home
)
SELECT * FROM Table1 a INNER JOIN cte ON a.home = cte.home AND a.year = cte.year
yh2wf1be

yh2wf1be6#

这是您需要的查询:

SELECT b.id, a.home,b.[datetime],b.player,a.resource FROM
 (SELECT home,MAX(resource) AS resource FROM tbl_1 GROUP BY home) AS a

 LEFT JOIN

 (SELECT id,home,[datetime],player,resource FROM tbl_1) AS b
 ON  a.resource = b.resource WHERE a.home =b.home;
laximzn5

laximzn57#

最快的 MySQL 解决方案,没有内部查询和 GROUP BY :

SELECT m.*                    -- get the row that contains the max value
FROM topten m                 -- "m" from "max"
    LEFT JOIN topten b        -- "b" from "bigger"
        ON m.home = b.home    -- match "max" row with "bigger" row by `home`
        AND m.datetime < b.datetime           -- want "bigger" than "max"
WHERE b.datetime IS NULL      -- keep only if there is no bigger than max

说明:
使用 home 列。使用 LEFT JOIN 确保表中的所有行 m 出现在结果集中。那些table上没有匹配的 b 会有 NULL s代表 b .
另一个条件是 JOIN 要求只匹配中的行 b 在市场上有更大的价值 datetime 列中的行 m .
根据问题中公布的数据 LEFT JOIN 将产生这对:

+------------------------------------------+--------------------------------+
|              the row from `m`            |    the matching row from `b`   |
|------------------------------------------|--------------------------------|
| id  home  datetime     player   resource | id    home   datetime      ... |
|----|-----|------------|--------|---------|------|------|------------|-----|
| 1  | 10  | 04/03/2009 | john   | 399     | NULL | NULL | NULL       | ... | *
| 2  | 11  | 04/03/2009 | juliet | 244     | NULL | NULL | NULL       | ... | *
| 5  | 12  | 04/03/2009 | borat  | 555     | NULL | NULL | NULL       | ... | *
| 3  | 10  | 03/03/2009 | john   | 300     | 1    | 10   | 04/03/2009 | ... |
| 4  | 11  | 03/03/2009 | juliet | 200     | 2    | 11   | 04/03/2009 | ... |
| 6  | 12  | 03/03/2009 | borat  | 500     | 5    | 12   | 04/03/2009 | ... |
| 7  | 13  | 24/12/2008 | borat  | 600     | 8    | 13   | 01/01/2009 | ... |
| 8  | 13  | 01/01/2009 | borat  | 700     | NULL | NULL | NULL       | ... | *
+------------------------------------------+--------------------------------+

最后是 WHERE 子句只保留具有 NULL 在…的列中 b (它们标有 * (见上表);这意味着,由于 JOIN 子句中选择的行 m 列中的值最大 datetime .
阅读《sql反模式:避免数据库编程的陷阱》一书中的其他sql技巧。

v09wglhw

v09wglhw8#

您也可以尝试这个方法,对于大型表,查询性能会更好。当每个家庭的记录不超过两个,并且日期不同时,它就起作用了。更好的通用mysql查询来自上面的michaellavoie。

SELECT t1.id, t1.home, t1.date, t1.player, t1.resource
FROM   t_scores_1 t1 
INNER JOIN t_scores_1 t2
   ON t1.home = t2.home
WHERE t1.date > t2.date

如果是postgres或那些提供分析功能的数据库,请尝试

SELECT t.* FROM 
(SELECT t1.id, t1.home, t1.date, t1.player, t1.resource
  , row_number() over (partition by t1.home order by t1.date desc) rw
 FROM   topten t1 
 INNER JOIN topten t2
   ON t1.home = t2.home
 WHERE t1.date > t2.date 
) t
WHERE t.rw = 1
8tntrjer

8tntrjer9#

(注:对于目标列 datetime 每个不同的值不能有重复的值 home .)
如果表中有重复的行 homedatetime 您只需要为每个不同的行选择一行 home 专栏,下面是我的解决方案:
您的表需要一个唯一的列(如 id ). 如果没有,则创建一个视图并向其中添加一个随机列。
使用此查询为每个唯一项选择一行 home 价值观。选择最低的 id 如有重复 datetime .

SELECT tt.*
FROM topten tt
INNER JOIN
    (
    SELECT min(id) as min_id, home from topten tt2
    INNER JOIN 
        (
        SELECT home, MAX(datetime) AS MaxDateTime
        FROM topten
        GROUP BY home) groupedtt2
    ON tt2.home = groupedtt2.home
    ) as groupedtt
ON tt.id = groupedtt.id
des4xlb0

des4xlb010#

SELECT  tt.*
FROM    TestTable tt 
INNER JOIN 
        (
        SELECT  coord, MAX(datetime) AS MaxDateTime 
        FROM    rapsa 
        GROUP BY
                krd 
        ) groupedtt
ON      tt.coord = groupedtt.coord
        AND tt.datetime = groupedtt.MaxDateTime
sc4hvdpw

sc4hvdpw11#

这适用于oracle:

with table_max as(
  select id
       , home
       , datetime
       , player
       , resource
       , max(home) over (partition by home) maxhome
    from table  
)
select id
     , home
     , datetime
     , player
     , resource
  from table_max
 where home = maxhome
0tdrvxhp

0tdrvxhp12#

为什么不使用:选择home,max(datetime)作为maxdatetime,player,resource from topten group by home我错过什么了吗?

mqkwyuun

mqkwyuun13#

你太接近了!你所需要做的就是选择家和它的最大日期时间,然后加入回到 topten 两个字段上的表:

SELECT tt.*
FROM topten tt
INNER JOIN
    (SELECT home, MAX(datetime) AS MaxDateTime
    FROM topten
    GROUP BY home) groupedtt 
ON tt.home = groupedtt.home 
AND tt.datetime = groupedtt.MaxDateTime
zvokhttg

zvokhttg14#

t-sql版本如下:

-- Test data
DECLARE @TestTable TABLE (id INT, home INT, date DATETIME, 
  player VARCHAR(20), resource INT)
INSERT INTO @TestTable
SELECT 1, 10, '2009-03-04', 'john', 399 UNION
SELECT 2, 11, '2009-03-04', 'juliet', 244 UNION
SELECT 5, 12, '2009-03-04', 'borat', 555 UNION
SELECT 3, 10, '2009-03-03', 'john', 300 UNION
SELECT 4, 11, '2009-03-03', 'juliet', 200 UNION
SELECT 6, 12, '2009-03-03', 'borat', 500 UNION
SELECT 7, 13, '2008-12-24', 'borat', 600 UNION
SELECT 8, 13, '2009-01-01', 'borat', 700

-- Answer
SELECT id, home, date, player, resource 
FROM (SELECT id, home, date, player, resource, 
    RANK() OVER (PARTITION BY home ORDER BY date DESC) N
    FROM @TestTable
)M WHERE N = 1

-- and if you really want only home with max date
SELECT T.id, T.home, T.date, T.player, T.resource 
    FROM @TestTable T
INNER JOIN 
(   SELECT TI.id, TI.home, TI.date, 
        RANK() OVER (PARTITION BY TI.home ORDER BY TI.date) N
    FROM @TestTable TI
    WHERE TI.date IN (SELECT MAX(TM.date) FROM @TestTable TM)
)TJ ON TJ.N = 1 AND T.id = TJ.id

编辑
不幸的是,mysql中没有rank()over函数。
但是它可以被模拟,请参阅用mysql模拟分析(aka ranking)函数。
这是mysql版本:

SELECT id, home, date, player, resource 
FROM TestTable AS t1 
WHERE 
    (SELECT COUNT(*) 
            FROM TestTable AS t2 
            WHERE t2.home = t1.home AND t2.date > t1.date
    ) = 0
evrscar2

evrscar215#

我想这会给你想要的结果:

SELECT   home, MAX(datetime)
FROM     my_table
GROUP BY home

但是如果您还需要其他列,只需与原始表建立一个连接(检查 Michael La Voie 答案)
致以最诚挚的问候。

相关问题