11

私のテーブルtitlesはこんな感じ

id |group|date                |title
---+-----+--------------------+--------
1  |1    |2012-07-26 18:59:30 | Title 1
2  |1    |2012-07-26 19:01:20 | Title 2
3  |2    |2012-07-26 19:18:15 | Title 3
4  |2    |2012-07-26 20:09:28 | Title 4
5  |2    |2012-07-26 23:59:52 | Title 5

日付順に降順で並べ替えられた各グループからの最新の結果が必要です。このようなもの

id |group|date                |title
---+-----+--------------------+--------
5  |2    |2012-07-26 23:59:52 | Title 5
2  |1    |2012-07-26 19:01:20 | Title 2

私は試した

SELECT *
FROM `titles`
GROUP BY `group`
ORDER BY MAX( `date` ) DESC

しかし、グループから最初の結果を得ています。このような

id |group|date                |title
---+-----+--------------------+--------
3  |2    |2012-07-26 18:59:30 | Title 3
1  |1    |2012-07-26 19:18:15 | Title 1

私は何を間違っていますか?LEFT JOIN を使用すると、このクエリはより複雑になりますか?

4

8 に答える 8

11

このページは私にとって非常に役に立ちました。グループごとに最大/最小/何かn行を取得するために自己結合を使用する方法を教えてくれました。

あなたの状況では、次のように必要な効果に適用できます。

SELECT * FROM
(SELECT group, MAX(date) AS date FROM titles GROUP BY group)
AS x JOIN titles USING (group, date);
于 2012-07-27T21:29:25.290 に答える
1

Google でこのトピックを見つけましたが、同じ問題が発生しているように見えました。私のように、サブクエリが気に入らない場合の私自身の解決策は次のとおりです。

-- Create a temporary table like the output
CREATE TEMPORARY TABLE titles_tmp LIKE titles;

-- Add a unique key on where you want to GROUP BY
ALTER TABLE titles_tmp ADD UNIQUE KEY `group` (`group`);

-- Read the result into the tmp_table. Duplicates won't be inserted.
INSERT IGNORE INTO titles_tmp
  SELECT *
    FROM `titles`
    ORDER BY  `date` DESC;

-- Read the temporary table as output
SELECT * 
  FROM titles_tmp
  ORDER BY `group`;

はるかに優れたパフォーマンスを発揮します。date_column が auto_increment_one と同じ順序である場合に速度を上げる方法は次のとおりです (その場合、ORDER BY ステートメントは必要ありません)。

-- Create a temporary table like the output
CREATE TEMPORARY TABLE titles_tmp LIKE titles;

-- Add a unique key on where you want to GROUP BY
ALTER TABLE titles_tmp ADD UNIQUE KEY `group` (`group`);

-- Read the result into the tmp_table, in the natural order. Duplicates will update the temporary table with the freshest information.
INSERT INTO titles_tmp
  SELECT *
    FROM `titles`

  ON DUPLICATE KEY 
    UPDATE  `id`    = VALUES(`id`), 
            `date`  = VALUES(`date`), 
            `title` = VALUES(`title`);

-- Read the temporary table as output
SELECT * 
  FROM titles_tmp
  ORDER BY `group`;

結果 :

+----+-------+---------------------+---------+
| id | group | date                | title   |
+----+-------+---------------------+---------+
|  2 |     1 | 2012-07-26 19:01:20 | Title 2 |
|  5 |     2 | 2012-07-26 23:59:52 | Title 5 |
+----+-------+---------------------+---------+

大きなテーブルでは、この方法はパフォーマンスの点で重要です。

于 2015-06-10T11:21:08.283 に答える
0

フィールドが自動インクリメント フィールドであり、フィールドの最大値が任意のグループの最大値でもidあると言っても過言ではない場合、これは簡単な解決策です。iddate

SELECT   b.*
FROM     (SELECT MAX(id) AS maxid FROM titles GROUP BY group) a
JOIN     titles b ON a.maxid = b.id
ORDER BY b.date DESC 
于 2012-07-27T21:55:25.030 に答える
0

日付がグループ内で一意である場合、これは機能します (そうでない場合は、グループ内の最大日付に一致する行がいくつか表示されます)。(また、列、'group'、'date' の不適切な命名により、構文エラーや、特に 'group' などのエラーが発生する可能性があります)

select t1.* from titles t1, (select group, max(date) date from titles group by group) t2
where t2.date = t1.date
and t1.group = t2.group
order by date desc
于 2012-07-27T21:29:54.750 に答える
0

以下の mysql クエリを使用して、テーブルから最新の更新/挿入されたレコードを取得します。

SELECT * FROM 
(
  select * from `titles` order by `date` desc
) as tmp_table
group by `group`
order by `date` desc
于 2015-05-17T07:57:11.143 に答える
0

もう 1 つの方法は、MySQL ユーザー変数を使用して、値の「コントロール ブレーク」を識別することgroupです。

余分な列が返されても構わない場合は、次のようなものが機能します。

SELECT IF(s.group = @prev_group,0,1) AS latest_in_group
     , s.id
     , @prev_group := s.group AS `group`
     , s.date
     , s.title
  FROM (SELECT t.id,t.group,t.date,t.title
          FROM titles t
         ORDER BY t.group DESC, t.date DESC, t.id DESC
       ) s
  JOIN (SELECT @prev_group := NULL) p
HAVING latest_in_group = 1
 ORDER BY s.group DESC

これが行っていることは、すべての行groupdate降順に並べ替えることです。(group,date,id)( MySQL が「逆スキャン」を実行できるインデックスがある場合に備えて、ORDER BY のすべてのカラムに DESC を指定しますid。最新の値を持つ行が複数ありdateます。) これは、 としてエイリアス化されたインライン ビューsです。

使用する「トリック」は、値を前の行groupの値と比較することです。group値が異なる場合は常に、「新しい」グループを開始していること、およびこの行が「最新」の行であることがわかります (IF 関数が 1 を返すようにします)。それ以外の場合 (グループ値が一致する場合)、それは最新の行ではありません (IF 関数が 0 を返すようにします)。

latest_in_group次に、 1 として設定されていないすべての行を除外します。

そのクエリを (インライン ビューとして) 別のクエリでラップすることにより、余分な列を削除することができます。

SELECT r.id
     , r.group
     , r.date
     , r.title
  FROM ( SELECT IF(s.group = @prev_group,0,1) AS latest_in_group
              , s.id
              , @prev_group := s.group AS `group`
              , s.date
              , s.title
           FROM (SELECT t.id,t.group,t.date,t.title
                   FROM titles t
                  ORDER BY t.group DESC, t.date DESC, t.id DESC
                ) s
           JOIN (SELECT @prev_group := NULL) p
         HAVING latest_in_group = 1
       ) r
 ORDER BY r.group DESC
于 2012-07-27T21:53:20.867 に答える
0

GROUP BYMySQL は、そのような結果を取得したい場合に信頼できないダム拡張を使用するため、次を使用できます。

select id, group, date, title from titles as t where id = 
(select id from titles where group = a.group order by date desc limit 1);

このクエリでは、最新の日付を見つけることができるように、テーブルが各グループに対して完全にスキャンされるたびに。これに代わるより良い代替品は見つかりませんでした。これが誰かを助けることを願っています。

于 2017-06-15T08:00:23.030 に答える