web-dev-qa-db-ja.com

JOIN構文のMySQL相関サブクエリ

Innertable.id = outertable.idを指定して、内部クエリでWHERE条件を提供したいと思います。ただし、MySQL(5.0.45)は「不明な列 'outertable.id'が 'where句'にある」と報告します。このタイプのクエリは可能ですか?

内部クエリは、GROUP BYを使用して行を列にピボットします。これは完全に外部クエリで実行できますが、追加の結合により追加のオーバーヘッドが発生する可能性があります。

または、内部クエリのWHERE条件を省略して、代わりにON outertable.id = innerquery.idを指定することもできますが、その場合、内部クエリ行セット全体をフェッチして外部に再び結合するため、非効率的です。

実際のSQLを以下に示します。

select t.ticketid, u.userid, t.fullname, u.loginapi_userid, t.email, tp.subject, tp.contents, a.PhoneNumber, a.Location, a.Extension, a.BusinessUnit, a.Department
from swtickets t
inner join swticketposts tp on t.ticketid = tp.ticketid
inner join swusers u on t.userid = u.userid
left join
  (
  select
  cfv.typeid,
  min(case cfv.customfieldid when 1 then cfv.fieldvalue end) as 'PhoneNumber',
  min(case cfv.customfieldid when 3 then cfv.fieldvalue end) as 'Location',
  min(case cfv.customfieldid when 5 then cfv.fieldvalue end) as 'Extension',
  min(case cfv.customfieldid when 8 then cfv.fieldvalue end) as 'BusinessUnit',
  min(case cfv.customfieldid when 9 then cfv.fieldvalue end) as 'Department'
  from swcustomfieldvalues cfv
  where cfv.typeid = t.ticketid
  group by cfv.typeid
  ) as a on 1 = 1
where t.ticketid = 2458;
18
Taylor Gerring

あなたの質問への答えはノーです、あなたがしているように相関名を参照することは不可能です。派生テーブルは、外部クエリが結合の評価を開始する前に、内部クエリによって作成されます。そのため、ttpuなどの相関名は内部クエリでは使用できません。

これを解決するには、内部クエリで同じ定数整数値を使用し、1=1ではなく実際の条件を使用して外部クエリの派生テーブルを結合することをお勧めします。

SELECT t.ticketid, u.userid, t.fullname, u.loginapi_userid, t.email,
  tp.subject, tp.contents, a.PhoneNumber, a.Location, a.Extension,
  a.BusinessUnit, a.Department
FROM swtickets t
 INNER JOIN swticketposts tp ON (t.ticketid = tp.ticketid)
 INNER JOIN swusers u ON (t.userid = u.userid)
 LEFT OUTER JOIN (
  SELECT cfv.typeid,
    MIN(CASE cfv.customfieldid WHEN 1 THEN cfv.fieldvalue END) AS 'PhoneNumber',
    MIN(CASE cfv.customfieldid WHEN 3 THEN cfv.fieldvalue END) AS 'Location',
    MIN(CASE cfv.customfieldid WHEN 5 THEN cfv.fieldvalue END) AS 'Extension',
    MIN(CASE cfv.customfieldid WHEN 8 THEN cfv.fieldvalue END) AS 'BusinessUnit',
    MIN(CASE cfv.customfieldid WHEN 9 THEN cfv.fieldvalue END) AS 'Department'
  FROM swcustomfieldvalues cfv
  WHERE cfv.typeid = 2458
  GROUP BY cfv.typeid
  ) AS a ON (a.typeid = t.ticketid)
WHERE t.ticketid = 2458;
30
Bill Karwin

Entity-Attribute-Valueデザインを使用しており、従来の結果セットを生成しようとした場合、これをスケーラブルにする方法は最終的にありません。これを1つのクエリで実行しないでください。

代わりに、まず正規化されたテーブルをクエリします。

SELECT t.ticketid, u.userid, t.fullname, u.loginapi_userid, t.email, 
  tp.subject, tp.contents
FROM swtickets t
 INNER JOIN swticketposts tp ON (t.ticketid = tp.ticketid)
 INNER JOIN swusers u ON (t.userid = u.userid)
WHERE t.ticketid = 2458;

次に、結果セットの複数行の結果を使用して、カスタムフィールドをクエリします。

SELECT cfv.customfieldid, cfv.fieldvalue
FROM swcustomfieldvalues cfv
WHERE cfv.typeid = 2458;

結果セットには、カスタムフィールドごとに1行ずつ、複数の行が表示されます。

+---------------+--------------+
| customfieldid | fieldvalue   |
+---------------+--------------+
|             1 | 415-555-1234 |
|             3 | Third office |
|             5 | 123          |
|             8 | Support      |
|             9 | Engineering  |
+---------------+--------------+

次に、ループで結果セットフィールドをアプリケーションオブジェクトフィールドにマップするアプリケーションコードを記述する必要があります。

このようにEntity-Attribute-Valueテーブルを使用すると、パフォーマンスとコード保守の両方の点でよりスケーラブルになります。

2
Bill Karwin

複数の結合を使用して記述します。 「追加のオーバーヘッドが発生する可能性があります」と言った場合、確認のためにテストしていないことがわかります。適切なインデックスがある場合、結合は非常に簡単です。

これは、一般的な「すべてを保持する」テーブルデザインパターンの落とし穴の1つにすぎません。

1
Tom H

私の提案は、効率性を理由にあなたが除外したものになるでしょう。例えば。 where句を省略して結合を使用する(t.ticketid = a.ticketidのとおり)

いくつかの具体的な例によって、非効率性についてのあなたの考えを証明することができましたか?私はあなたの言っていることを知っていますが、外部クエリのすべての行を使用するどのような方法も内部クエリのすべての行に結合されているので、実行プランによっては、疑わしいほど効率的ではないかもしれません。

0
AJM

問題は 'cfv.typeid = t.ticketid'だと思いますか?それについての私の考えは、MySQLが相関サブクエリをサポートしている一方で、「内部」クエリが実際のように残りのクエリの「内部」ではないため、実行しようとしていることが結合で失敗する可能性があるということです。 WHERE句内。しかし、サブクエリからwhere句を取り出して、a.typeid = t.ticketidで結合条件を作成できるように見えます。

0
chaos