0

わかりましたので、私はこのクエリに取り組んできましたが、ステートメントを相互にネストする現在の方法よりも、より良い方法が必要であると確信しています。

これが私の2つのメインテーブルです(すぐに書き直したので、完全な「テーブル作成」コードではない可能性があります)

CREATE TABLE `person` (
    `personid` INT PRIMARY KEY AUTO_INCREMENT,
    `personuuid` VARCHAR(64),
    `flags` INT,
    `last_updated` DATETIME,
    `first_name` VARCHAR(64),
    `last_name` VARCHAR(64)
);

CREATE TABLE `person_status` (
    `person_statusid` INT PRIMARY KEY AUTO_INCREMENT,
    `person_statusesid` INT,
    `personuuid` VARCHAR(64),
    `groupsuuid` VARCHAR(64),
    `start_date` DATE
);

簡単な説明: ご覧のとおり、個人は (潜在的に) 複数のステータスを持つことができます。最新のステータスは、開始日 (開始日が最も長い方) によって決定されます。各人物は、個人テーブル内に複数のエントリを持つ可能性もあります。(ユーザー情報の更新を追跡するのに役立ちます) 最新の情報は、最新の last_updated 値を持つ情報です。

私がやろうとしていること: 次のようなすべての人 (別名 personuuid) のリストを取得しようとしています:

  1. 私たちに戻ってくるエントリには、最新の人のステータスがあります
  2. ステータスは、特定の groupsuuid に対してのみ表示されます (別名、グループによってフィルター処理されます)。
  3. 名前がフィルタリングされるように、追加のフィルタリングも必要です
  4. flags が 0 であることも確認する必要があります。

私が実行しているクエリは次のとおりです。

SELECT personuuid FROM (
    SELECT personuuid, flags FROM (
        SELECT DISTINCT personuuid, flags
            FROM person 
            JOIN (
                SELECT personuuid, t2.person_statusesid FROM (
                        SELECT personuuid, groupsuuid, t1.person_statusesid FROM (
                            SELECT personuuid, groupsuuid, p1.person_statusesid 
                                FROM person_status as p1
                                ORDER BY start_date DESC, person_statusid DESC
                        ) as t1
                        GROUP BY personuuid, groupsuuid
                    ) as t2
                    WHERE groupsuuid='xxxxxxxxxx' AND person_statusesid = X
            ) AS t3 USING (personuuid)
            WHERE  (first_name LIKE '%TEST%' OR last_name LIKE '%TEST%')
            ORDER BY person_statusesid, last_name, first_name, last_updated DESC
        ) as t4
        GROUP BY personuuid
    ) as t5
WHERE flags <> 2;

ご覧のとおり、私が行っていることは、個人のステータスを並べ替え、グループと statusesid でフィルター処理するテーブルと個人テーブルを結合することです。次に、結合された 2 つのテーブルを名前でフィルタリングして取得し、最新の人物の行を取得して、適切なフラグが設定されていることを確認します。

これは楽しいパズルのように思えるので、誰かが適切な解決策を思い付くことができるかどうかを確認してもらいたいと思いました. 私はこれらのことの専門家ではないので、基本的な SQl コマンドしか知らないので、どんなアドバイスでも役に立ちます。ありがとう =)

4

1 に答える 1

0

必要なデータを 1 か所にまとめることで、これに取り組みます。つまり、最新のステータス レコードと最新の人物レコードです。これには、2 つのテーブルの最新の更新日を見つけてから、さまざまなテーブルとサブクエリを結合する必要があります。

select ps.*, p.*
from person_status ps join
     (select personuuid, max(last_updated) as maxlu
      from person_status ps
      group by person_status
     ) psm
     on psm.personuuid = psm.personuuid and psm.maxlu = ps.last_updated join
     (select personuuid, max(last_updated) as maxlu
      from person p
      group by personuuid
     ) pm
     on pm.personuuid = ps.personuuid join
     person p
     on pm.personuuid = p.personuuid and pm.maxlu = p.lastupdated
where p.flags = 0 and
      ps.groupsuuid in (<list of groups>) and
      additional filtering;

レコードの「有効日」( lastupdated) を持つデータ構造を使用する場合は、「終了日」も考慮する必要があります。これは更新での作業が少し増えます (通常はトリガーが必要です) が、このようなクエリは非常に簡単になります。

編集:

元のクエリにはかなりの数のサブクエリが含まれています。いずれにせよ、問題を単純化するために、サブクエリなしでこれを書き直すことができます。次の場合、(両方のテーブルの) インデックスpersonuuid, lastupdatedがパフォーマンスのために必要になります。

select ps.*, p.*
from person_status ps join
     person p
     on ps.personuuid = p.personuuid and
        p.lastupdated = (select p2.lastupdated
                         from person p2
                         where p2.personuuid = p.personuuid
                         order by p2.lastupdated desc
                         limit 1
                        ) and
        ps.lastupdated = (select ps2.lastupdated
                          from person_status ps2
                          where ps2.personuuid = ps.personuuid
                          order by ps2.lastupdated desc
                          limit 1
                         )
where p.flags = 0 and
      ps.groupsuuid in (<list of groups>) and
      additional filtering;

このバージョンでは、サブクエリは相互に関連付けられており、インデックス ルックアップに変わります。

于 2013-08-09T00:20:11.137 に答える