web-dev-qa-db-ja.com

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

私はこのクエリを持っています( 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と一緒にバインドしてみましたが、頭がよくありません。

herehere 、および here のメソッドも試しましたが、最新のアクティビティを持つ人を正しく取得できません。

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

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

8
stiq

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

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

7
ypercubeᵀᴹ

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

ypercubeは、MySQLが結果をグループ化する方法についての他の同様の質問を指摘する答えを私に示しました。これは私を this resource に導き、そこで何が起こっているのかを最終的に理解しました。

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

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

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

2
stiq

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

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フィドル

1
cha