複数の結合がある最新の日付に基づいて行を選択します


8

私はこのクエリを持っています(SQLFiddle):

SELECT
c.name,
a.user_id,
a.status_id,
a.title,
a.rtime,
u.user_name,
s.status_name

FROM company c

LEFT JOIN action a ON a.company_id=c.id
LEFT JOIN user u ON u.id=a.user_id
LEFT JOIN status s ON s.id=a.status_id



WHERE u.user_name='Morgan'

-- WHERE c.name='Fiddle'

GROUP BY c.id

HAVING a.rtime IS NULL OR a.rtime = (
 SELECT max(rtime)
 FROM action a2
 WHERE deleted IS NULL
 AND a2.company_id = c.id
 )

問題1

すべての会社をリストして、ユーザーと会社が最後に会社に対してアクションを行ったステータスを表示したいと思います。同時に、何も行われていない会社を表示します。

問題2

また、名前でユーザーを検索できるようにする必要があります。これにより、このユーザーが最後に活動した企業をすべて選択できます。クエリはフォームから作成されるため、変数を挿入できます。


現在のところ、データベースSCHEMAを変更することはできませんが、将来の移行のためのアドバイスはかなり役に立ちます。

私はそれを一緒にバインドしようとしましたINNER JOIN ( SELECT.. ) t ONが、私はそれの周りに頭を得ることができません。

私はまた、から方法を試してみた ここでここでは、とここで私は、最新のアクティビティ権を持つ人を取得することはできません。

MySQLバージョン:5.5.16。会社のテーブルの行数は約1ミルで、アクションテーブルは70Kになり、増加しています。ここではパフォーマンスが重要です。

これをどのように解決できますか?


2
この質問を参照してください:MySQLの最適化されたクエリの代わりのMAX(Marks)あたりをTaskID、あなたが欲しいMAX(ActivityDate)ごとにCompany)あなたが一つのテーブルを持っているか、参加する場合の大きな違いはありません。
ypercubeᵀᴹ

回答:


7

クエリは次のように簡略化できます。

SELECT
    c.id,
    c.name,
    a.rtime,
    s.status_name,
    u.user_name
FROM company c
    LEFT JOIN
      ( SELECT 
            company_id,
            MAX(rtime) AS maxdate
        FROM action
        WHERE deleted IS NULL
        GROUP BY company_id
      ) AS x ON x.company_id = c.id
    LEFT JOIN action a ON  a.deleted IS NULL
                       AND a.company_id = x.company_id 
                       AND a.rtime = x.maxdate 
    LEFT JOIN user u ON u.id = a.user_id
    LEFT JOIN status s ON s.id = a.status_id
WHERE 
    c.name LIKE 'Company%' ;

インデックスを(deleted, company_id, rtime)付けると、派生テーブルのサブクエリが効率的になります。結合に使用される列とにすでにインデックスがあると思いますCompany (name)

SQLフィドル


1
これは単純で、私の回答よりも100行あたり約0.3秒速いようです。
stiq

2

さまざまな答えを試してみましたが、うまくいきましたが、設定が遅いことがわかりました。

ypercubeは、MySQLが結果をグループ化する方法に関する他の同様の質問を指摘する答えを私に示しました。これが私をこのリソースに導き、そこで何が起こっているのかをようやく理解しました。

結果は次のようなクエリになります。

SELECT
c.id,
c.name,

a.rtime,

s.status_name,

u.user_name


FROM company c

LEFT JOIN (
    SELECT 
        a.company_id,
        a.rtime,
        a.user_id,
        a.status_id
        FROM
            (
            SELECT company_id,
 MAX(rtime) as maxdate
            FROM action
            WHERE deleted IS NULL
            GROUP BY company_id
            ) as x

        LEFT JOIN action a ON a.rtime=x.maxdate AND a.company_id=x.company_id

) as a ON a.company_id=c.id

LEFT JOIN user u ON u.id=a.user_id
LEFT JOIN status s ON s.id=a.status_id

WHERE (1)

-- Search by user
-- AND u.user_name LIKE 'Johnny'

-- Seach by company name
AND c.name LIKE 'Company%'

これが動作するクエリのフィドルです


1

次のように、ユーザー、アクション、ステータスのテーブルをサブクエリに移動する必要があります。

SELECT
c.name,
a.user_id,
a.status_id,
a.title,
a.max_rtime,
a.user_name,
a.status_name

FROM company c

LEFT JOIN
(select company_id, user_id, 
 max(rtime) max_rtime, 
 title, status_id, s.status_name,
 u.user_name
 from action INNER JOIN
  status s ON s.id=action.status_id
  INNER JOIN user u ON u.id=action.user_id
 where action.deleted IS NULL
 group by company_id, user_id, status_id, s.status_name, title, u.user_name
) a ON a.company_id=c.id AND a.user_name='Morgan'


GROUP BY c.id

SQLフィドル

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.