web-dev-qa-db-ja.com

テーブルまたはcteに参加

まず、インターネットで適切な解決策を見つけようとしましたが、実際に自分に合った解決策は見つかりませんでした。私の問題は何だと思われますか?上手...

私の新しい仕事では、MySQLを使用しています。私はDB2とSQLServerでの作業に慣れているので、一般的なテーブル式(cte)を使用したり、テーブルを適切に結合したりできないことに非常に驚いていました。たとえば、(サブ)テーブルを2番目のfromステートメントとして作成している間は、最初のfromステートメントのデータを使用して2つのテーブルを接続することはできません。動作するのは、(sub)テーブルで最初のfromステートメントを再度使用することですが、2番目のfromステートメントの(sub)テーブルの結果を使用する必要がある3番目のテーブルを追加すると、エラー。 :-(

私の質問を単純化するために。顧客データの表があります。お客様はそれぞれ異なります。私はお客様の番号と名前を使用します。また、一意の顧客ごとに複数の請求書とそれらの請求書の日付が記載された請求書テーブルもあります。最後に、すべての収益データを含む収益テーブルがあります。複数の行が可能で、収益が予約される日付があります。

ここで(これも単純化された例です)、請求書テーブルから最大日付を取得し、その日付を使用して、その日付以降の収益のみを取得したいと思います。そして、クエリ全体の結果として、顧客番号、顧客名、最大請求日、収益の合計を取得します。

以前は、fromステートメントで共通テーブル式または(サブ)テーブルを使用して最大日付を実行し、これを3番目のfromステートメントの収益日>最大請求日で使用していました。しかし、これをMySQL内で機能させるにはどうすればよいですか?これは単純な例ですが、複雑になったときにこのようなことをどのように行いますか?

どんな助けでも大歓迎です!ありがとう。

クエリの例:

select * 
from table_A t1 
  join table 
    ( select t0.customernumber, max(t0.date) as max_date 
      from table_B t0 
      where t1.customernumber = t0.customernumber
    ) t2 
    on  t1.customernumber = t2.customernumber 
  join table_C t3 
    on  t1.customernumber = t3.customernumber
    and t3.date > t2.max_date
1
vvanasperen

テーブル構造がないと、コードを書くのは簡単ではありませんが、簡単なクエリを次に示します。

_SELECT 
    c.*, i.*,
    r.max_date
FROM 
    customer AS c
  LEFT JOIN                                        -- or just JOIN 
    ( SELECT customernumber, 
             MAX(revenue_date) AS max_date
      FROM revenue
      GROUP BY customernumber
    ) AS r
      ON  r.customernumber = c.customernumber
  LEFT JOIN                                        -- or just JOIN
    invoice AS i
      ON  i.customernumber = c.customernumber
      AND i.invoice_date >= r.max_date ;
_

上記は標準SQLであり、他のすべてのDBMSと同様にMySQLでも機能します。ただし、LATERALまたは同様の構文を使用してよりエレガントな(またはより効率的な)SQLを提供できる、より複雑な状況では、MySQLは役に立ちません。標準のSQL構文の多くが欠けています(一般的なテーブル式、テーブル値コンストラクター、ウィンドウ関数、LATERALCHECK制約、そしておそらく私が忘れている他のいくつかのような)。

(SQL-Serverの)_OUTER APPLY_、(ISO/ANSI)LATERAL、または(DB2の)TABLE構文をシミュレートする場合、(悪いニュース)は非常に複雑になりますが、(良いニュース)通常、適切なインデックス付けで非常に効率的です。これは主に、小さな「ベース」テーブル(この場合はcustomer)がある場合、またはクエリをWHERE句を持つ少数の顧客のみに制限する場合に役立ちます。上記の_GROUP BY_を使用したクエリでは、すべての顧客のMAX(revenue_date)を見つける必要があります(つまり、revenueの完全なテーブルまたは完全なインデックススキャンを意味します)。選択された少数の顧客の最大値のみが検出されます(したがって、いくつかのインデックスがシークします)。

_SELECT 
    c.*, i.*,
    r.revenue_date AS max_date
FROM 
    customer AS c
  LEFT JOIN
    revenue AS r
      ON  r.customernumber = .customernumber
      AND r.PK = 
          ( SELECT ri.PK
            FROM revenue AS ri
            WHERE ri.customernumber = c.customernumber
            ORDER BY ri.revenue_date DESC
              LIMIT 1
          ) 
  LEFT JOIN                                        
    invoice AS i
      ON  i.customernumber = c.customernumber
      AND i.invoice_date >= r.revenue_date 
WHERE
    <some conditions on the customer table> ;
_
  • 利点は、最終的なrevenueリストにSELECTテーブルの任意の列を含めることができることです。
  • _(customernumber, revenue_date)_が一意である場合、結合の主キーの代わりに_revenue_date_を使用できるなど、いくつかの改善/バリエーションがあります。
  • 1行だけではなく複数行(_TOP n_クエリ)が必要な場合は、非常に複雑になりますが、それでも実行できます。
3
ypercubeᵀᴹ