Verwenden des äußeren Alias ​​in einer Unterabfrage

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

Ich versuche, eine Liste der Zahlungen für Transaktionen anzuzeigen und nach jeder Zahlung den aktuellen Kontostand anzuzeigen. Unten finden Sie ein Beispiel für das erwartete Ergebnis

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

und hier ist meine Abfrage bisher, aber habe einen Fehler in der where-Klausel

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

Bitte beachten Sie, dass ich nach gruppiere, p.dateda unser Anliegen die Gesamtzahlung innerhalb eines Tages ist.

Kann mich bitte jemand aufklären, warum ich diesen Fehler bekomme? Und gibt es eine Problemumgehung, um das erwartete Ergebnis zu erzielen?

Jaime Sangcap
quelle

Antworten:

10

Die beiden verschachtelten Auswahlen in Ihrer Abfrage werden als abgeleitete Tabellen bezeichnet . Eine abgeleitete Tabelle soll nicht mit anderen an der Abfrage beteiligten Datasets korreliert werden, daher sind äußere Verweise auf diese in der verschachtelten Abfrage nicht zulässig.

Eine Möglichkeit, das Problem zu beheben, besteht darin, Ihre Abfrage neu zu schreiben, um die fehlerhafte Auswahl in den Kontext zu verschieben, in dem die Korrelation zulässig ist. In Ihrem Fall können Sie die fehlerhafte Unterabfrage in die SELECT-Klausel verschieben:

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;

hier neu testen


Der Vollständigkeit halber verfügt der SQL-Standard über eine Syntax, die eine Korrelation für abgeleitete Tabellen ermöglicht. Es wird seitliche Verbindung genannt . Aus syntaktischer Sicht sieht es fast genauso aus wie ein normaler Join. Sie müssen lediglich das LATERALSchlüsselwort hinzufügen, nachdem 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

Das hinzugefügte Schlüsselwort macht den Unterschied, da nur mit diesem Schlüsselwort eine verschachtelte Abfrage auf andere Datasets in derselben FROM-Klausel verweisen darf (links vom neuesten JOIN-Schlüsselwort).

Seitliche Verknüpfungen werden derzeit von PostgreSQL und Oracle unterstützt. Ein ähnliches Konzept mit einer etwas anderen (und weniger flexiblen) Syntax wird auch von SQL Server unterstützt. Wie Sie vielleicht vermutet haben, unterstützt MySQL derzeit nichts dergleichen.

McNets
quelle
MariaDB unterstützt Fensterfunktionen, die nützlich sein können, um Summenprobleme wie dieses auszuführen
ypercubeᵀᴹ
Mainstream MySQL wird in Version 8 eine Fensterfunktion haben: dev.mysql.com/doc/refman/8.0/en/window-functions.html Meine Vermutung für wann ist dieses Jahr, wahrscheinlich in den ersten 6 Monaten (wenn man bedenkt, dass oben steht: "Entwurf der allgemeinen Verfügbarkeit: 12.01.2018").
Ypercubeᵀᴹ
@McNets und Andriy Ich habe es jetzt mit Ihrer Antwort zum Laufen gebracht. Sie haben es gut und mit einigen Imbissbuden erklärt (seitliches Schlüsselwort). Vielen Dank!
Jaime Sangcap
Ich bin froh, dass ich helfen kann.
McNets
@ JaimeSangcap: Gerne helfen, Prost.
Andriy M