ChatGPT解决这个技术问题 Extra ChatGPT

如何在 MYSQL 中选择具有 MAX(列值)和 PARTITION 的行?

我有一张球员表现表:

CREATE TABLE TopTen (
  id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  home INT UNSIGNED NOT NULL,
  `datetime`DATETIME NOT NULL,
  player VARCHAR(6) NOT NULL,
  resource INT NOT NULL
);

什么查询将返回每个不同的 home 的行,其最大值为 datetime?换句话说,如何按最大 datetime(按 home 分组)进行过滤,并在结果中仍然包含其他未分组的非聚合列(例如 player)?

对于此示例数据:

INSERT INTO TopTen
  (id, home, `datetime`, player, resource)
VALUES
  (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)
;

结果应该是:

id home datetime player 资源 1 10 04/03/2009 约翰 399 2 11 04/03/2009 juliet 244 5 12 04/03/2009 borat 555 8 13 01/01/2009 borat 700

我尝试了一个子查询来获取每个 home 的最大值 datetime

-- 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

然后我尝试加入一个子查询,该子查询为每行 id 获取最大值 datetime

-- 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`

没有。给出所有记录。

我尝试了各种奇特的查询,每一个都有不同的结果,但没有什么能让我更接近解决这个问题。


A
Andreas Rejbrand

你是如此接近!您需要做的就是同时选择住宅及其最大日期时间,然后在 BOTH 字段中加入 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

测试它是否不同,如果两个相等的最大日期时间在同一个家中(与不同的玩家)
我认为执行此操作的经典方法是使用自然连接:“SELECT tt.* FROM topten tt NATURAL JOIN (SELECT home, MAX(datetime) AS datetime FROM topten GROUP BY home) mostrecent;”完全相同的查询,但可以说更具可读性
如果有两行具有相同的“home”和“datetime”字段值怎么办?
@Young 您的查询的问题是它可能会返回给定家庭的非最大行的 idplayerresource,即对于 home = 10,您可能会得到:3 | 10 | 04/03/2009 | john | 300 换句话说,它不会t 保证结果集中一行的所有列都属于给定主页的 max(datetime)。
关于上面@KemalDuran 的评论,如果有两行具有相同的 home 和 datetime 字段,您需要做的是采用 Michael La Voie 的解决方案并将 MAX(id) AS MaxID 添加到内部 SELECT 语句然后去在末尾添加另一行 AND tt.id = groupedtt.MaxID
f
fedorqui

最快的 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 中的所有行都出现在结果集中。那些在表 b 中没有匹配项的将有 b 列的 NULL

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 子句只保留 b 列中具有 NULL 的对(它们在上表中用 * 标记);这意味着,由于 JOIN 子句的第二个条件,从 m 中选择的行在 datetime 列中具有最大值。

阅读 SQL Antipatterns: Avoiding the Pitfalls of Database Programming 书以了解其他 SQL 技巧。


使用 SQLite,当匹配列(即“home”)上没有索引时,第一个比 La Voie 的版本慢得多。 (用 24k 行测试得到 13k 行)
这是最好的答案,如果你显示执行计划,你会看到这个查询少了一步
如果 2 行具有相同的 homedatetime 并且 datetime 是该特定 home 的最大值,会发生什么?
@AjaxLeung 列 homedatetime 的索引。作为一般规则,如果索引包含在 ONWHEREORDER BY 子句中使用的列,则索引会有所帮助。但是,这取决于列的使用方式。如果在表达式中使用列,则索引是无用的。将 EXPLAIN 放在对 find out what indexes are used (and how) 的查询前面。
这个想法对我有用。它有助于简化我的子查询
M
Maksym Gontar

这里是 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

EDIT
不幸的是,MySQL 中没有 RANK() OVER 函数。
但可以模拟,参见Emulating Analytic (AKA Ranking) Functions with MySQL
所以这是 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

@MaxGontar,你的 mysql 解决方案很不错,谢谢。如果在您的 @_TestTable 中删除 row#1>: SELECT 1, 10, '2009-03-04', 'john', 399 怎么办,也就是说,如果给定的房屋价值只有一行怎么办?谢谢。
BUG:将“RANK()”替换为“ROW_NUMBER()”。如果您有平局(由重复的日期值引起),您将有两条记录,其中 N 为“1”。
Q
Quassnoi

即使每个 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

在表中添加了盖子字段,不好
这个没有在 PHPMyAdmin 上执行。页面刷新但没有结果也没有错误..?
WHERE ti.home = t1.home - 你能解释一下语法吗?
@IstiaqueAhmed:你到底不明白什么?这是一个相关查询,你提到的表达式是一个相关条件。
@Quassnoi,具有行 WHERE ti.home = t1.homeselect 查询不需要定义 t1FROM 子句。那么它是如何使用的呢?
s
sactiw

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

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

但是如果您还需要其他列,只需与原始表进行联接(检查 Michael La Voie 答案)

此致。


他还需要其他列。
ID, 家, 日期时间, 播放器, 资源
M
MJB

由于人们似乎不断地遇到这个线程(评论日期范围从 1.5 年开始)并没有这么简单:

SELECT * FROM (SELECT * FROM topten ORDER BY datetime DESC) tmp GROUP BY home

不需要聚合函数...

干杯。


这似乎不起作用。错误消息:选择列表中的“x”列无效,因为它既不包含在聚合函数中,也不包含在 GROUP BY 子句中。
这绝对不适用于 SQL Server 或 Oracle,尽管它看起来可能适用于 MySQL。
这真的很漂亮!这是如何运作的?通过使用 DESC 和默认组返回列?因此,如果我将其更改为 datetime ASC,它会返回每个家庭的最早行吗?
如果您有非聚合列(在 MySQL 中),则此方法不起作用。
S
Shiva

你也可以试试这个,对于大表的查询性能会更好。当每个家庭的记录不超过两个并且它们的日期不同时,它就会起作用。更好的通用 MySQL 查询来自上面的 Michael La Voie。

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

这个答案正确吗?我尝试使用它,但它似乎不会为“家”选择日期最新的记录,而只会删除日期最旧的记录。这是一个示例:SQLfiddle
@kidOfDeath - 用上下文和 Postgres 查询更新了我的回复
使用 SQLite,当匹配列(即“home”)上没有索引时,第一个比 La Voie 的版本慢得多。
Q
Quassnoi
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

F
FerranB

这适用于甲骨文:

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

这如何选择最大日期时间?他要求按家分组,并选择最大日期时间。我不明白这是怎么做到的。
S
SysDragon

在 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

J
Jason Heo

这是 MySQL 版本,它只打印一个条目,其中一组中有重复的 MAX(datetime)。

你可以在这里测试http://www.sqlfiddle.com/#!2/0a4ae/1

样本数据

mysql> SELECT * from topten;
+------+------+---------------------+--------+----------+
| id   | home | datetime            | player | resource |
+------+------+---------------------+--------+----------+
|    1 |   10 | 2009-04-03 00:00:00 | john   |      399 |
|    2 |   11 | 2009-04-03 00:00:00 | juliet |      244 |
|    3 |   10 | 2009-03-03 00:00:00 | john   |      300 |
|    4 |   11 | 2009-03-03 00:00:00 | juliet |      200 |
|    5 |   12 | 2009-04-03 00:00:00 | borat  |      555 |
|    6 |   12 | 2009-03-03 00:00:00 | borat  |      500 |
|    7 |   13 | 2008-12-24 00:00:00 | borat  |      600 |
|    8 |   13 | 2009-01-01 00:00:00 | borat  |      700 |
|    9 |   10 | 2009-04-03 00:00:00 | borat  |      700 |
|   10 |   11 | 2009-04-03 00:00:00 | borat  |      700 |
|   12 |   12 | 2009-04-03 00:00:00 | borat  |      700 |
+------+------+---------------------+--------+----------+

带有用户变量的 MySQL 版本

SELECT *
FROM (
    SELECT ord.*,
        IF (@prev_home = ord.home, 0, 1) AS is_first_appear,
        @prev_home := ord.home
    FROM (
        SELECT t1.id, t1.home, t1.player, t1.resource
        FROM topten t1
        INNER JOIN (
            SELECT home, MAX(datetime) AS mx_dt
            FROM topten
            GROUP BY home
          ) x ON t1.home = x.home AND t1.datetime = x.mx_dt
        ORDER BY home
    ) ord, (SELECT @prev_home := 0, @seq := 0) init
) y
WHERE is_first_appear = 1;
+------+------+--------+----------+-----------------+------------------------+
| id   | home | player | resource | is_first_appear | @prev_home := ord.home |
+------+------+--------+----------+-----------------+------------------------+
|    9 |   10 | borat  |      700 |               1 |                     10 |
|   10 |   11 | borat  |      700 |               1 |                     11 |
|   12 |   12 | borat  |      700 |               1 |                     12 |
|    8 |   13 | borat  |      700 |               1 |                     13 |
+------+------+--------+----------+-----------------+------------------------+
4 rows in set (0.00 sec)

已接受答案的输出

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
+------+------+---------------------+--------+----------+
| id   | home | datetime            | player | resource |
+------+------+---------------------+--------+----------+
|    1 |   10 | 2009-04-03 00:00:00 | john   |      399 |
|    2 |   11 | 2009-04-03 00:00:00 | juliet |      244 |
|    5 |   12 | 2009-04-03 00:00:00 | borat  |      555 |
|    8 |   13 | 2009-01-01 00:00:00 | borat  |      700 |
|    9 |   10 | 2009-04-03 00:00:00 | borat  |      700 |
|   10 |   11 | 2009-04-03 00:00:00 | borat  |      700 |
|   12 |   12 | 2009-04-03 00:00:00 | borat  |      700 |
+------+------+---------------------+--------+----------+
7 rows in set (0.00 sec)

尽管我喜欢这个答案,因为这对我帮助很大,我必须指出一个主要缺陷,它依赖于使用的 mysql 系统。基本上,这个解决方案依赖于子选择中的 ORDER BY 子句。这可能或可能不适用于各种 mysql 环境。我没有在纯 MySQL 上尝试过,但可以肯定的是,这在 MariaDB 10.1 上不能可靠地工作,如此处所述 stackoverflow.com/questions/26372511/… 但完全相同的代码在 Percona Server 上工作正常。准确地说,您可能会或可能不会得到相同的结果,具体取决于 t1 列的数量。
此语句的示例是,当我使用 t1 表中的 5 列时,它在 MariaDB 10.1 上有效。一旦我添加了第六列,显然会弄乱原始表中的“自然”数据排序,它就停止了工作。原因是,子选择中的数据变得无序,因此我多次遇到“is_first_appear = 1”条件。相同的代码,相同的数据,在 Percona 上运行正常。
W
Woot4Moo
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)

M
M Khalid Junaid

另一种使用子查询 gt 每组最近行的方法,该子查询基本上计算每组每行的排名,然后过滤掉最近的行,如 rank = 1

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

DEMO

这是每行的排名第 visual demo,以便更好地理解

通过阅读一些评论,如果有两行具有相同的 '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

DEMO

上面的查询将在相同的 datetime 值中选择具有最高 id 的行

visual demo 表示每一行的排名


R
Roland

为什么不使用: SELECT home, MAX(datetime) AS MaxDateTime,player,resource FROM topten GROUP BY home 我错过了什么吗?


这仅对 MySQL 有效,并且仅对 5.7(?)之前或 5.7 之后禁用 ONLY_FULL_GROUP_BY 的版本有效,因为它正在选择尚未聚合/分组的列(播放器,资源),这意味着 MySQL 将为这些提供随机选择的值两个结果字段。玩家列不会有问题,因为它与主列相关,但资源列与主列或日期时间列不相关,您无法保证您会收到哪个资源值。
+1 用于解释,但在提出的问题上,此查询不会在 MySQL 5.6 和 before 中返回 expected 输出,我非常怀疑它在 MySQL 5.7 和 after 中的行为是否不同。
@simpleuser,`播放器列不会有问题,因为它与主列相关`-您能解释更多吗?
@IstiaqueAhmed 我再看一遍,那句话是不正确的。我原以为每个玩家总是有相同的房屋价值,但我现在发现他们没有,所以该列也会出现相同的随机选择问题
K
Kazi Mohammad Ali Nur

在 MySQL 8.0 中,这可以通过使用带有公共表表达式的 row_number() 窗口函数来有效地实现。

(这里的 row_number() 基本上为每个玩家从资源的降序顺序为 1 开始为每一行生成唯一的序列。因此,对于每个序列号为 1 的玩家行将具有最高的资源值。现在我们需要做的就是选择行每个玩家的序列号为 1。可以通过围绕该查询编写外部查询来完成。但我们使用公共表表达式代替,因为它更具可读性。)

架构:

 create  TABLE TestTable(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

询问:

 with cte as 
 (
     select id, home, date , player, resource, 
     Row_Number()Over(Partition by home order by date desc) rownumber from TestTable
 )
 select id, home, date , player, resource from cte where rownumber=1

输出:

id home date player 资源 1 10 2009-03-04 00:00:00 约翰 399 2 11 2009-03-04 00:00:00 juliet 244 5 12 2009-03-04 00:00:00 borat 555 8 13 2009 -01-01 00:00:00 波拉特 700

db<>小提琴here


M
Manoj Kargeti

@Michae 接受的答案在大多数情况下都可以正常工作,但对于以下情况却失败了。

如果有 2 行 HomeID 和 Datetime 相同,则查询将返回两行,而不是根据需要返回不同的 HomeID,以便在查询中添加 Distinct,如下所示。

SELECT DISTINCT tt.home  , tt.MaxDateTime
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

结果显示 - “#1054 - '字段列表'中的未知列 'tt.MaxDateTime'”
@IstiaqueAhmed 你有 MaxDatetime 归档,即任何这样的列名..?
不,OP 中的表没有任何这样的列。
错误也说同样的请..你到底想做什么?您可以发送表结构和您的查询吗?
K
Khb

尝试这个

select * from mytable a join
(select home, max(datetime) datetime
from mytable
group by home) b
 on a.home = b.home and a.datetime = b.datetime

问候 K


测试它是否不同,如果两个相等的最大日期时间在同一个家中(与不同的玩家)
max(datetime) 的别名是 datetime。不会有什么问题吗?
最高的 datetime 是如何选择的?
S
Simon

这是您需要的查询:

 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;

你能解释一下你的答案吗?
ס
סטנלי גרונן

希望下面的查询将给出所需的输出:

Select id, home,datetime,player,resource, row_number() over (Partition by home ORDER by datetime desc) as rownum from tablename where rownum=1

M
Moradnejad

(注意:Michael 的答案非常适合目标列 datetime 对于每个不同的 home 不能有重复值的情况。)

如果您的表有 homexdatetime 的重复行,并且您只需为每个不同的 home 列选择一行,我的解决方案如下:

您的表需要一个唯一的列(例如 id)。如果没有,请创建一个视图并向其中添加一个随机列。

使用此查询为每个唯一的 home 值选择一行。在重复 datetime 的情况下选择最低的 id

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

J
Jeka Developer

如果有 2 条具有相同日期和家庭的记录,则接受的答案对我不起作用。加入后将返回 2 条记录。虽然我需要选择其中的任何一个(随机)。此查询用作连接子查询,因此无法仅限制 1。这是我达到预期结果的方式。但是不知道性能。

select SUBSTRING_INDEX(GROUP_CONCAT(id order by datetime desc separator ','),',',1) as id, home, MAX(datetime) as 'datetime'
 from topten
 group by (home)

N
Neon Tetra

因为这还没有发布——这在 SQLServer 中有效,并且是我见过的唯一不需要子查询或 CTE 的解决方案——我认为这是解决这类问题的最优雅的方法

  SELECT TOP 1 WITH TIES *
    FROM TopTen
ORDER BY ROW_NUMBER() OVER (PARTITION BY home
                                ORDER BY [datetime] DESC)

关于其工作原理的一些说明 - Order By 子句中的窗口函数将计数器应用于每组 home 值,以便具有最高 [datetime] 值的那个接收 1

通过 SELECTing TOP 1 WITH TIES ,您将选择具有第一个 ROW_NUMBER 值(即 1)的记录,以及具有相同“绑定”ROW_NUMBER 值为 1 的所有其他记录

因此,您检索每个排名第一的记录的所有数据。