1194

messages以下に示すようなデータを含むテーブルがあります。

Id   Name   Other_Columns
-------------------------
1    A       A_data_1
2    A       A_data_2
3    A       A_data_3
4    B       B_data_1
5    B       B_data_2
6    C       C_data_1

query を実行するselect * from messages group by nameと、結果は次のようになります。

1    A       A_data_1
4    B       B_data_1
6    C       C_data_1

次の結果を返すクエリはどれですか?

3    A       A_data_3
5    B       B_data_2
6    C       C_data_1

つまり、各グループの最後のレコードが返されます。

現在、これは私が使用するクエリです。

SELECT
  *
FROM (SELECT
  *
FROM messages
ORDER BY id DESC) AS x
GROUP BY name

しかし、これは非常に非効率に見えます。同じ結果を達成する他の方法はありますか?

4

32 に答える 32

1216

MySQL 8.0 は、ほとんどすべての一般的な SQL 実装と同様に、ウィンドウ関数をサポートするようになりました。この標準的な構文を使用すると、グループあたり最大 n クエリを作成できます。

WITH ranked_messages AS (
  SELECT m.*, ROW_NUMBER() OVER (PARTITION BY name ORDER BY id DESC) AS rn
  FROM messages AS m
)
SELECT * FROM ranked_messages WHERE rn = 1;

以下は、2009 年にこの質問に対して私が書いた元の回答です。


私はこのように解決策を書きます:

SELECT m1.*
FROM messages m1 LEFT JOIN messages m2
 ON (m1.name = m2.name AND m1.id < m2.id)
WHERE m2.id IS NULL;

パフォーマンスに関しては、データの性質に応じて、どちらかのソリューションの方が優れている場合があります。したがって、両方のクエリをテストし、データベースのパフォーマンスが優れている方を使用する必要があります。

たとえば、StackOverflow August data dumpのコピーがあります。それをベンチマークに使用します。テーブルには 1,114,357 行ありPostsます。これは、私の Macbook Pro 2.40GHz のMySQL 5.0.75 で実行されています。

特定のユーザー ID (私のもの) の最新の投稿を検索するクエリを作成します。

最初にサブクエリで@Eric によって示された手法を使用します。GROUP BY

SELECT p1.postid
FROM Posts p1
INNER JOIN (SELECT pi.owneruserid, MAX(pi.postid) AS maxpostid
            FROM Posts pi GROUP BY pi.owneruserid) p2
  ON (p1.postid = p2.maxpostid)
WHERE p1.owneruserid = 20860;

1 row in set (1 min 17.89 sec)

EXPLAIN分析にも16 秒以上かかります。

+----+-------------+------------+--------+----------------------------+-------------+---------+--------------+---------+-------------+
| id | select_type | table      | type   | possible_keys              | key         | key_len | ref          | rows    | Extra       |
+----+-------------+------------+--------+----------------------------+-------------+---------+--------------+---------+-------------+
|  1 | PRIMARY     | <derived2> | ALL    | NULL                       | NULL        | NULL    | NULL         |   76756 |             | 
|  1 | PRIMARY     | p1         | eq_ref | PRIMARY,PostId,OwnerUserId | PRIMARY     | 8       | p2.maxpostid |       1 | Using where | 
|  2 | DERIVED     | pi         | index  | NULL                       | OwnerUserId | 8       | NULL         | 1151268 | Using index | 
+----+-------------+------------+--------+----------------------------+-------------+---------+--------------+---------+-------------+
3 rows in set (16.09 sec)

次の手法を使用して、同じクエリ結果を生成しますLEFT JOIN

SELECT p1.postid
FROM Posts p1 LEFT JOIN posts p2
  ON (p1.owneruserid = p2.owneruserid AND p1.postid < p2.postid)
WHERE p2.postid IS NULL AND p1.owneruserid = 20860;

1 row in set (0.28 sec)

分析は、両方のEXPLAINテーブルがインデックスを使用できることを示しています。

+----+-------------+-------+------+----------------------------+-------------+---------+-------+------+--------------------------------------+
| id | select_type | table | type | possible_keys              | key         | key_len | ref   | rows | Extra                                |
+----+-------------+-------+------+----------------------------+-------------+---------+-------+------+--------------------------------------+
|  1 | SIMPLE      | p1    | ref  | OwnerUserId                | OwnerUserId | 8       | const | 1384 | Using index                          | 
|  1 | SIMPLE      | p2    | ref  | PRIMARY,PostId,OwnerUserId | OwnerUserId | 8       | const | 1384 | Using where; Using index; Not exists | 
+----+-------------+-------+------+----------------------------+-------------+---------+-------+------+--------------------------------------+
2 rows in set (0.00 sec)

私のPostsテーブルのDDLは次のとおりです。

CREATE TABLE `posts` (
  `PostId` bigint(20) unsigned NOT NULL auto_increment,
  `PostTypeId` bigint(20) unsigned NOT NULL,
  `AcceptedAnswerId` bigint(20) unsigned default NULL,
  `ParentId` bigint(20) unsigned default NULL,
  `CreationDate` datetime NOT NULL,
  `Score` int(11) NOT NULL default '0',
  `ViewCount` int(11) NOT NULL default '0',
  `Body` text NOT NULL,
  `OwnerUserId` bigint(20) unsigned NOT NULL,
  `OwnerDisplayName` varchar(40) default NULL,
  `LastEditorUserId` bigint(20) unsigned default NULL,
  `LastEditDate` datetime default NULL,
  `LastActivityDate` datetime default NULL,
  `Title` varchar(250) NOT NULL default '',
  `Tags` varchar(150) NOT NULL default '',
  `AnswerCount` int(11) NOT NULL default '0',
  `CommentCount` int(11) NOT NULL default '0',
  `FavoriteCount` int(11) NOT NULL default '0',
  `ClosedDate` datetime default NULL,
  PRIMARY KEY  (`PostId`),
  UNIQUE KEY `PostId` (`PostId`),
  KEY `PostTypeId` (`PostTypeId`),
  KEY `AcceptedAnswerId` (`AcceptedAnswerId`),
  KEY `OwnerUserId` (`OwnerUserId`),
  KEY `LastEditorUserId` (`LastEditorUserId`),
  KEY `ParentId` (`ParentId`),
  CONSTRAINT `posts_ibfk_1` FOREIGN KEY (`PostTypeId`) REFERENCES `posttypes` (`PostTypeId`)
) ENGINE=InnoDB;

コメント者への注意: MySQL の異なるバージョン、異なるデータセット、または異なるテーブル設計で別のベンチマークが必要な場合は、自由に自分で行ってください。上記のテクニックを紹介しました。スタック オーバーフローは、ソフトウェア開発作業を行う方法を示すためのものであり、すべての作業を行うためのものではありません。

于 2009-08-21T17:39:46.603 に答える
171

UPD: 2017-03-31、MySQL のバージョン5.7.5では、デフォルトで ONLY_FULL_GROUP_BY スイッチが有効になりました (したがって、非決定論的な GROUP BY クエリは無効になりました)。さらに、GROUP BY の実装が更新されたため、スイッチが無効になっていても、ソリューションが期待どおりに機能しなくなる可能性があります。確認する必要があります。

上記の Bill Karwin のソリューションは、グループ内の項目数がかなり少ない場合は問題なく機能しますが、グループがかなり大きい場合はクエリのパフォーマンスが低下しn*n/2 + n/2ますIS NULL

グループ18684446を持つ行の InnoDB テーブルでテストを行いました。1182このテーブルには、機能テストのテスト結果が含まれて(test_id, request_id)おり、主キーとして があります。したがって、はグループであり、それぞれtest_idの最後を探していました。request_idtest_id

Bill のソリューションは、dell e4310 ですでに数時間実行されており、カバレッジ インデックスで動作していても、いつ終了するかわかりません (したがってusing index、EXPLAIN で)。

同じアイデアに基づいた他のソリューションがいくつかあります。

  • 基になるインデックスが BTREE インデックスの場合 (通常はそうです)、最大の(group_id, item_value)ペアは each 内の最後の値です。これは、インデックスを降順でウォークスルーする場合group_id、それぞれの最初の値です。group_id
  • インデックスによってカバーされる値を読み取る場合、値はインデックスの順序で読み取られます。
  • 各インデックスには、それに追加された主キー列が暗黙的に含まれます (つまり、主キーはカバレッジ インデックスにあります)。以下のソリューションでは、主キーを直接操作します。この場合、結果に主キー列を追加するだけで済みます。
  • 多くの場合、サブクエリで必要な行 ID を必要な順序で収集し、その ID でサブクエリの結果を結合する方が安価です。サブクエリ結果の各行に対して、MySQL は主キーに基づいて単一のフェッチを必要とするため、サブクエリが結合の最初に配置され、行はサブクエリの ID の順序で出力されます (明示的な ORDER BY を省略した場合)参加のため)

MySQL がインデックスを使用する 3 つの方法は、いくつかの詳細を理解するための優れた記事です。

解決策 1

これは信じられないほど高速で、18M 以上の行で約 0.8 秒かかります。

SELECT test_id, MAX(request_id) AS request_id
FROM testresults
GROUP BY test_id DESC;

順序を ASC に変更する場合は、それをサブクエリに入れ、ID のみを返し、それをサブクエリとして使用して残りの列に結合します。

SELECT test_id, request_id
FROM (
    SELECT test_id, MAX(request_id) AS request_id
    FROM testresults
    GROUP BY test_id DESC) as ids
ORDER BY test_id;

これには、私のデータで約 1.2 秒かかります。

解決策 2

これは、私のテーブルで約 19 秒かかる別の解決策です。

SELECT test_id, request_id
FROM testresults, (SELECT @group:=NULL) as init
WHERE IF(IFNULL(@group, -1)=@group:=test_id, 0, 1)
ORDER BY test_id DESC, request_id DESC

テストも降順で返します。完全なインデックス スキャンを実行するため、はるかに遅くなりますが、ここでは、グループごとに最大 N 行を出力する方法について説明します。

クエリの欠点は、その結果をクエリ キャッシュでキャッシュできないことです。

于 2012-01-06T11:21:09.380 に答える
81

各グループ内の最後の投稿の ID を取得し、最初のクエリの結果をWHERE x INコンストラクトの引数として使用してメッセージ テーブルから選択するという別の解決策にたどり着きました。

SELECT id, name, other_columns
FROM messages
WHERE id IN (
    SELECT MAX(id)
    FROM messages
    GROUP BY name
);

これが他のいくつかのソリューションと比較してどのように機能するかはわかりませんが、300 万行以上のテーブルで見事に機能しました。(1200 以上の結果で 4 秒の実行)

これは、MySQL と SQL Server の両方で機能するはずです。

于 2012-02-20T21:46:38.020 に答える
49

サブクエリフィドルリンクによる解決

select * from messages where id in
(select max(id) from messages group by Name)

結合条件フィドルリンクによる解決策

select m1.* from messages m1 
left outer join messages m2 
on ( m1.id<m2.id and m1.name=m2.name )
where m2.id is null

この投稿の理由は、フィドル リンクのみを提供することです。同じSQLが他の回答ですでに提供されています。

于 2013-12-25T08:36:42.567 に答える
10

ここに 2 つの提案があります。まず、mysql が ROW_NUMBER() をサポートしている場合、それは非常に簡単です。

WITH Ranked AS (
  SELECT Id, Name, OtherColumns,
    ROW_NUMBER() OVER (
      PARTITION BY Name
      ORDER BY Id DESC
    ) AS rk
  FROM messages
)
  SELECT Id, Name, OtherColumns
  FROM messages
  WHERE rk = 1;

「最後」とは、ID順で最後を意味すると仮定しています。そうでない場合は、それに応じて ROW_NUMBER() ウィンドウの ORDER BY 句を変更します。ROW_NUMBER() が利用できない場合、これは別の解決策です:

第二に、そうでない場合、これは多くの場合、続行するための良い方法です。

SELECT
  Id, Name, OtherColumns
FROM messages
WHERE NOT EXISTS (
  SELECT * FROM messages as M2
  WHERE M2.Name = messages.Name
  AND M2.Id > messages.Id
)

つまり、同じ名前の later-Id メッセージがないメッセージを選択します。

于 2009-08-21T17:26:12.357 に答える
7

明らかに、同じ結果を得るにはさまざまな方法があります。あなたの質問は、MySQL の各グループで最後の結果を得る効率的な方法のようです。膨大な量のデータを扱っていて、最新バージョンの MySQL (5.7.21 や 8.0.4-rc など) でも InnoDB を使用していると想定している場合、これを行う効率的な方法がない可能性があります。

6000 万行を超えるテーブルでこれを行う必要がある場合があります。

これらの例では、クエリでデータ内のすべてのグループの結果を見つける必要がある約 150 万行のデータを使用します。実際のケースでは、多くの場合、約 2,000 のグループからデータを返す必要があります (これは、データの大部分を調べる必要がないという仮説に基づいています)。

次の表を使用します。

CREATE TABLE temperature(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT, 
  groupID INT UNSIGNED NOT NULL, 
  recordedTimestamp TIMESTAMP NOT NULL, 
  recordedValue INT NOT NULL,
  INDEX groupIndex(groupID, recordedTimestamp), 
  PRIMARY KEY (id)
);

CREATE TEMPORARY TABLE selected_group(id INT UNSIGNED NOT NULL, PRIMARY KEY(id)); 

温度テーブルには、約 150 万のランダム レコードと 100 の異なるグループが入力されます。selected_group には、これらの 100 個のグループが取り込まれます (この場合、これは通常、すべてのグループで 20% 未満です)。

このデータはランダムであるため、複数の行が同じrecordedTimestampsを持つ可能性があることを意味します。必要なのは、選択したすべてのグループのリストを groupID の順に取得し、各グループの最後のrecordedTimestamp を取得することです。同じグループにそのような一致する行が複数ある場合は、それらの行の最後に一致する id を取得します。

仮説として、MySQL に特別な ORDER BY 句の最後の行から値を返す last() 関数がある場合、次のように簡単に実行できます。

SELECT 
  last(t1.id) AS id, 
  t1.groupID, 
  last(t1.recordedTimestamp) AS recordedTimestamp, 
  last(t1.recordedValue) AS recordedValue
FROM selected_group g
INNER JOIN temperature t1 ON t1.groupID = g.id
ORDER BY t1.recordedTimestamp, t1.id
GROUP BY t1.groupID;

この場合、通常の GROUP BY 関数を使用しないため、数 100 行を調べるだけで済みます。これは 0 秒で実行されるため、非常に効率的です。通常、MySQL では GROUP BY 句の後に ORDER BY 句が表示されますが、この ORDER BY 句は last() 関数の ORDER を決定するために使用されます。GROUP BY の後であれば、GROUPS の順序付けになります。GROUP BY 句が存在しない場合、最後の値は返されるすべての行で同じになります。

ただし、MySQL にはこれがありません。そのため、MySQL にあるさまざまなアイデアを見て、どれも効率的でないことを証明しましょう。

例 1

SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM selected_group g
INNER JOIN temperature t1 ON t1.id = (
  SELECT t2.id
  FROM temperature t2 
  WHERE t2.groupID = g.id
  ORDER BY t2.recordedTimestamp DESC, t2.id DESC
  LIMIT 1
);

これは 3,009,254 行を検査し、5.7.21 では約 0.859 秒、8.0.4-rc ではわずかに長くかかりました。

例 2

SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue 
FROM temperature t1
INNER JOIN ( 
  SELECT max(t2.id) AS id   
  FROM temperature t2
  INNER JOIN (
    SELECT t3.groupID, max(t3.recordedTimestamp) AS recordedTimestamp
    FROM selected_group g
    INNER JOIN temperature t3 ON t3.groupID = g.id
    GROUP BY t3.groupID
  ) t4 ON t4.groupID = t2.groupID AND t4.recordedTimestamp = t2.recordedTimestamp
  GROUP BY t2.groupID
) t5 ON t5.id = t1.id;

これは 1,505,331 行を検査し、5.7.21 では約 1.25 秒、8.0.4-rc ではわずかに長くかかりました。

例 3

SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue 
FROM temperature t1
WHERE t1.id IN ( 
  SELECT max(t2.id) AS id   
  FROM temperature t2
  INNER JOIN (
    SELECT t3.groupID, max(t3.recordedTimestamp) AS recordedTimestamp
    FROM selected_group g
    INNER JOIN temperature t3 ON t3.groupID = g.id
    GROUP BY t3.groupID
  ) t4 ON t4.groupID = t2.groupID AND t4.recordedTimestamp = t2.recordedTimestamp
  GROUP BY t2.groupID
)
ORDER BY t1.groupID;

これは 3,009,685 行を検査し、5.7.21 では約 1.95 秒、8.0.4-rc ではわずかに長くかかりました。

例 4

SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM selected_group g
INNER JOIN temperature t1 ON t1.id = (
  SELECT max(t2.id)
  FROM temperature t2 
  WHERE t2.groupID = g.id AND t2.recordedTimestamp = (
      SELECT max(t3.recordedTimestamp)
      FROM temperature t3 
      WHERE t3.groupID = g.id
    )
);

これは 6,137,810 行を検査し、5.7.21 では約 2.2 秒、8.0.4-rc ではわずかに長くかかりました。

例 5

SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM (
  SELECT 
    t2.id, 
    t2.groupID, 
    t2.recordedTimestamp, 
    t2.recordedValue, 
    row_number() OVER (
      PARTITION BY t2.groupID ORDER BY t2.recordedTimestamp DESC, t2.id DESC
    ) AS rowNumber
  FROM selected_group g 
  INNER JOIN temperature t2 ON t2.groupID = g.id
) t1 WHERE t1.rowNumber = 1;

これは 6,017,808 行を検査し、8.0.4-rc で約 4.2 秒かかりました

例 6

SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue 
FROM (
  SELECT 
    last_value(t2.id) OVER w AS id, 
    t2.groupID, 
    last_value(t2.recordedTimestamp) OVER w AS recordedTimestamp, 
    last_value(t2.recordedValue) OVER w AS recordedValue
  FROM selected_group g
  INNER JOIN temperature t2 ON t2.groupID = g.id
  WINDOW w AS (
    PARTITION BY t2.groupID 
    ORDER BY t2.recordedTimestamp, t2.id 
    RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
  )
) t1
GROUP BY t1.groupID;

これは 6,017,908 行を検査し、8.0.4-rc で約 17.5 秒かかりました

例 7

SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue 
FROM selected_group g
INNER JOIN temperature t1 ON t1.groupID = g.id
LEFT JOIN temperature t2 
  ON t2.groupID = g.id 
  AND (
    t2.recordedTimestamp > t1.recordedTimestamp 
    OR (t2.recordedTimestamp = t1.recordedTimestamp AND t2.id > t1.id)
  )
WHERE t2.id IS NULL
ORDER BY t1.groupID;

これは永遠にかかっていたので、私はそれを殺さなければなりませんでした。

于 2018-04-18T07:45:23.327 に答える
6

GROUP_CONCATorder by を使用して最後の関連レコードを取得SUBSTRING_INDEXし、リストからレコードの 1 つを選択する別の方法を次に示します。

SELECT 
  `Id`,
  `Name`,
  SUBSTRING_INDEX(
    GROUP_CONCAT(
      `Other_Columns` 
      ORDER BY `Id` DESC 
      SEPARATOR '||'
    ),
    '||',
    1
  ) Other_Columns 
FROM
  messages 
GROUP BY `Name` 

上記のクエリOther_Columnsは、同じNameグループ内にあるすべてをグループ化し、使用すると、特定のグループ内のすべてが降順でORDER BY id DESC結合され、私の場合は提供されたセパレーターが使用され、このリストを使用すると最初のものが選択されますOther_Columns||SUBSTRING_INDEX

フィドルのデモ

于 2014-03-29T14:51:01.050 に答える
5
SELECT 
  column1,
  column2 
FROM
  table_name 
WHERE id IN 
  (SELECT 
    MAX(id) 
  FROM
    table_name 
  GROUP BY column1) 
ORDER BY column1 ;
于 2014-04-11T06:55:00.467 に答える
5

こんにちは@Vijay Devテーブルメッセージに自動インクリメント主キーであるIDが含まれている場合、主キーに基づいて最新のレコードを取得するには、クエリは次のように読み取る必要があります。

SELECT m1.* FROM messages m1 INNER JOIN (SELECT max(Id) as lastmsgId FROM messages GROUP BY Name) m2 ON m1.Id=m2.lastmsgId
于 2014-10-21T14:08:16.030 に答える
5

私はまだ大規模なDBでテストしていませんが、これはテーブルを結合するよりも速いと思います:

SELECT *, Max(Id) FROM messages GROUP BY Name
于 2012-03-31T14:44:05.747 に答える
4

ここからも眺めることができます。

http://sqlfiddle.com/#!9/ef42b/9

最初の解決策

SELECT d1.ID,Name,City FROM Demo_User d1
INNER JOIN
(SELECT MAX(ID) AS ID FROM Demo_User GROUP By NAME) AS P ON (d1.ID=P.ID);

2 番目の解決策

SELECT * FROM (SELECT * FROM Demo_User ORDER BY ID DESC) AS T GROUP BY NAME ;
于 2015-09-28T09:07:12.013 に答える
3

このメソッドを使用してテーブル内の重複を削除する方法はありますか? 結果セットは基本的に一意のレコードのコレクションであるため、結果セットに含まれていないすべてのレコードを削除できれば、実質的に重複がなくなりますか? これを試しましたが、mySQL で 1093 エラーが発生しました。

DELETE FROM messages WHERE id NOT IN
 (SELECT m1.id  
 FROM messages m1 LEFT JOIN messages m2  
 ON (m1.name = m2.name AND m1.id < m2.id)  
 WHERE m2.id IS NULL)

出力を一時変数に保存してから、NOT IN (一時変数) から削除する方法はありますか? @ビルは非常に便利なソリューションをありがとう。

編集:解決策を見つけたと思います:

DROP TABLE IF EXISTS UniqueIDs; 
CREATE Temporary table UniqueIDs (id Int(11)); 

INSERT INTO UniqueIDs 
    (SELECT T1.ID FROM Table T1 LEFT JOIN Table T2 ON 
    (T1.Field1 = T2.Field1 AND T1.Field2 = T2.Field2 #Comparison Fields  
    AND T1.ID < T2.ID) 
    WHERE T2.ID IS NULL); 

DELETE FROM Table WHERE id NOT IN (SELECT ID FROM UniqueIDs);
于 2010-10-08T01:10:11.490 に答える
3

これを試して:

SELECT jos_categories.title AS name,
       joined .catid,
       joined .title,
       joined .introtext
FROM   jos_categories
       INNER JOIN (SELECT *
                   FROM   (SELECT `title`,
                                  catid,
                                  `created`,
                                  introtext
                           FROM   `jos_content`
                           WHERE  `sectionid` = 6
                           ORDER  BY `id` DESC) AS yes
                   GROUP  BY `yes`.`catid` DESC
                   ORDER  BY `yes`.`created` DESC) AS joined
         ON( joined.catid = jos_categories.id )  
于 2011-07-15T02:05:08.860 に答える
2

以下のクエリは、質問どおりに正常に機能します。

SELECT M1.* 
FROM MESSAGES M1,
(
 SELECT SUBSTR(Others_data,1,2),MAX(Others_data) AS Max_Others_data
 FROM MESSAGES
 GROUP BY 1
) M2
WHERE M1.Others_data = M2.Max_Others_data
ORDER BY Others_data;
于 2011-11-18T20:19:44.880 に答える
2

各 の最後の行が必要な場合はName、各行グループに行番号を付け、降順で並べName替えることができます。Id

クエリ

SELECT t1.Id, 
       t1.Name, 
       t1.Other_Columns
FROM 
(
     SELECT Id, 
            Name, 
            Other_Columns,
    (
        CASE Name WHEN @curA 
        THEN @curRow := @curRow + 1 
        ELSE @curRow := 1 AND @curA := Name END 
    ) + 1 AS rn 
    FROM messages t, 
    (SELECT @curRow := 0, @curA := '') r 
    ORDER BY Name,Id DESC 
)t1
WHERE t1.rn = 1
ORDER BY t1.Id;

SQL フィドル

于 2015-11-19T04:36:11.093 に答える
2

これはどう:

SELECT DISTINCT ON (name) *
FROM messages
ORDER BY name, id DESC;

同様の問題(postgresqlタフ)と1Mレコードテーブルで発生しました。このソリューションは、LEFT JOIN を使用したソリューションによって生成される 44 秒に対して 1.7 秒かかります。私の場合、名前フィールドの対応者を NULL 値に対してフィルタリングする必要があったため、パフォーマンスがさらに 0.2 秒向上しました。

于 2016-11-30T10:50:40.230 に答える
0

以下の Oracle クエリが役立つことを願っています。

WITH Temp_table AS
(
    Select id, name, othercolumns, ROW_NUMBER() over (PARTITION BY name ORDER BY ID 
    desc)as rank from messages
)
Select id, name,othercolumns from Temp_table where rank=1
于 2020-01-15T06:07:02.137 に答える