Utilizzo dell'alias esterno in una sottoquery


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

Sto cercando di visualizzare un elenco di pagamenti effettuati sulle transazioni e di mostrare il saldo corrente dopo ogni pagamento. Di seguito è riportato un esempio del risultato atteso

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

e qui è la mia query finora, ma ho un errore nella clausola 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

Si prega di notare che sto raggruppando p.datepoiché la nostra preoccupazione è il totale dei pagamenti effettuati entro il giorno.

Qualcuno può illuminarmi per favore perché ricevo questo errore? E c'è qualche soluzione alternativa per raggiungere il risultato atteso?

Risposte:


10

Le due selezioni nidificate nella query vengono chiamate tabelle derivate . Una tabella derivata non è pensata per essere correlata con altri set di dati che partecipano alla query, pertanto non sono consentiti riferimenti esterni ad essi nella query nidificata.

Un modo per risolvere il problema è riscrivere la query in modo da spostare la selezione offensiva nel contesto in cui è consentita la correlazione. Nel tuo caso puoi spostare la subquery offensiva nella clausola 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;

rextester qui


Per completezza, lo standard SQL ha effettivamente una sintassi che consente la correlazione per le tabelle derivate. Si chiama join laterale . Dal punto di vista sintattico, sembra quasi esattamente come un normale join, devi solo aggiungere la LATERALparola chiave dopo 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

La parola chiave aggiunta fa la differenza, poiché solo con quella parola chiave una query nidificata può fare riferimento ad altri set di dati nella stessa clausola FROM (a sinistra della parola chiave JOIN più recente).

I join laterali sono attualmente supportati da PostgreSQL e Oracle. SQL Server supporta anche un concetto simile con una sintassi leggermente diversa (e meno flessibile). Come avrai intuito, MySQL al momento non supporta nulla del genere.


MariaDB supporta le funzioni finestra che possono essere utili per l'esecuzione di problemi di totali come questo: mariadb.com/kb/en/library/window-functions
ypercubeᵀᴹ

MySQL mainstream avrà la funzione finestra nella versione 8: dev.mysql.com/doc/refman/8.0/en/window-functions.html La mia ipotesi su quando sarà quest'anno, probabilmente nei primi 6 mesi (considerando che quanto sopra dice: "Progetto di disponibilità pre-generale: 12-01-2018").
ypercubeᵀᴹ

@McNets e Andriy L'ho fatto funzionare ora usando la tua risposta. Lo hai spiegato bene e con alcuni takeaway (parola chiave laterale). Grazie!
Jaime Sangcap,

Sono felice di aiutare.
McNets,

@JaimeSangcap: Felice di aiutarti, evviva.
Andriy M,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.