サブクエリでの外部エイリアスの使用


11
|    payments    |  | transactions |  | transaction_items |
|:--------------:|  |:------------:|  |:-----------------:|
|       id       |  |      id      |  |         id        |
|      date      |  |    number    |  |   transaction_id  |
|     amount     |  |     date     |  |    description    |
| transaction_id |  |      val     |  |       price       |
                                      |      discount     |
                                      |      quantity     |

トランザクションで行われた支払いのリストを表示し、各支払い後に現在の残高を表示しようとしています。以下は期待される結果の例です

| number | DATE(p.date) | total   | paid    | balance | 
| 1355   | 2016-10-31   | 899.00  | 450.00  | 449.00  | 
| 1355   | 2016-12-06   | 899.00  | 449.00  | 0.00    | 
| 1359   | 2016-09-28   | 4045.00 | 1515.00 | 2530    | 
| 1359   | 2016-10-24   | 4045.00 | 35.00   | 2495.00 | 
| 1361   | 2016-09-28   | 1548.00 | 1548.00 | 0.00    | 

これがこれまでの私のクエリですが、where句にエラーがあります

select
    t.number,
    DATE(p.date),
    ti.total 'total',
    SUM(p.amount) 'paid',
    ti.total - paid.total 'balance'
from payments p
left join transactions t
on p.transaction_id = t.id
left join (
    select inner_ti.transaction_id, sum((inner_ti.price - inner_ti.discount) * inner_ti.quantity)  'total'
    from transaction_items inner_ti
    group by inner_ti.transaction_id
) ti on t.id = ti.transaction_id
left join (
    select inner_p.transaction_id, sum(inner_p.amount) 'total'
    from payments inner_p
    where inner_p.date <= p.date -- error unknown column p.date
    group by inner_p.transaction_id
) paid on t.id = paid.transaction_id
group by t.number, DATE(p.date), ti.total, paid.total
order by DATE(p.date) ASC

p.date私たちの懸念は1日以内に行われた支払いの合計であるため、グループ化していることに注意してください。

誰かがそのエラーを受け取っている理由を誰かに教えてもらえますか?そして、期待される結果を達成するための回避策はありますか?

回答:


10

クエリでネストされた2つの選択は、派生テーブルと呼ばれます。派生テーブルは、クエリに参加している他のデータセットと相関することを意図していないため、ネストされたクエリでのそれらへの外部参照は許可されていません。

問題を解決する1つの方法は、問題のある選択を相関が許可されているコンテキストに移動するようにクエリを書き直すことです。あなたのケースでは、問題のあるサブクエリをSELECT句に移動できます。

select    t.number,
          DATE(p.date),
          ti.total 'total',
          SUM(p.amount) 'paid',
          ti.total - (select sum(inner_p.amount)
                      from     payments inner_p
                      where    inner_p.transaction_id = p.transaction_id
                      and      inner_p.date <= p.date
                     ) 'balance'
from      payments p
left join transactions t
on        p.transaction_id = t.id
left join (
          select   inner_ti.transaction_id, 
                   sum((inner_ti.price - inner_ti.discount) * inner_ti.quantity)  'total'
          from     transaction_items inner_ti
          group by inner_ti.transaction_id
          ) ti 
on        t.id = ti.transaction_id
group by  t.number, DATE(p.date), ti.total, 'balance'
order by  DATE(p.date) ASC;

ここで学期


完全を期すために、SQL標準には実際には派生テーブルの相関を可能にする構文があります。これをラテラルジョインといいます。構文の観点から見ると、通常の結合とほとんど同じように見えます。LATERALあとにキーワードを追加するだけですJOIN


left join lateral (
    select inner_p.transaction_id, sum(inner_p.amount) 'total'
    from payments inner_p
    where inner_p.date <= p.date -- this outer reference would be valid
    group by inner_p.transaction_id
) paid on t.id = paid.transaction_id

ネストされたクエリは、同じFROM句(最新のJOINキーワードの左側)にある他のデータセットを参照することが許可されているため、キーワードを追加するとすべての違いが生じます。

現在、ラテラル結合はPostgreSQLとOracleでサポートされています。SQL Serverでは、わずかに異なる(柔軟性が低い)構文を使用した同様の概念もサポートされています。ご想像のとおり、現在、MySQLはそのようなものをサポートしていません。


:MariaDBは、ウィンドウのこの1のような合計の問題を実行するために便利なことができfucntionsサポートmariadb.com/kb/en/library/window-functions
ypercubeᵀᴹ

主流のMySQLはバージョン8に窓関数を持っています:dev.mysql.com/doc/refman/8.0/en/window-functions.html以上が言うことを考えると(おそらく最初の6ヶ月で、今年のときのために私の推測を: 「Pre-General Availability Draft:2018-01-12」)。
ypercubeᵀᴹ

@McNetsとAndriy私はあなたの答えを使って今それを動かしました。あなたはそれをうまく説明し、いくつかの要点を説明しました(横方向のキーワード)。ありがとうございました!
ハイメサンキャップ

お役に立ててうれしいです。
McNets、

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