Query con SUM che mi da un valore raddoppiato

mercoledì 20 settembre 2006 - 12.48

zseven Profilo | Senior Member

Ragazzi ho un problema che mi sta facendo uscire pazzo!!!!!!!
Ho bisogno di fare una query su diverse tabelle, andando a mostrare i valori della colonna importo_ft come somma di tutti i record e quindi raggrupparli:

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

La query è un pò lunga ma è estremamente semplice. Sono solo tante tabelle messe in relazione ognuna con l'ID, fino alla tabella pagamenti che prevede un LEFT JOIN, in quanto può esistere una fattura ma non ancora il pagamento.
In pratica ho fatto le SUM per i campi che mi interessano e va tutto bene tranne che per il campo tab_fatture.importo_ft, il quale raddoppia il suo valore.
Mi spiego meglio.
La tabella tab_fatture ha UN record per una fattura di importo 12.000.
La tabella tab_pagamenti ha DUE record collegati a questa fattura, ognuno di 6.000.

Nella visualizzazione della query ottengo per la colonna SUM della tab_fatture il valore 24.000!!! Mentre, correttamente per quella SUM della tab_pagamenti ottengo 12.000.

Come mai mi raddoppia il valore che dovrei avere?!?
Ragazzi lo so che è complicato ma vi prego di aiutarmi...sto impazzendo!
Grazie

Ciciu Profilo | Senior Member

Semplificando la cosa, immagina di avere la tabella FATTURA e la tabella PAGAMENTI.
Nel momento in cui le metti in relazione, la Fattura è la tabella "uno", mentre la tabella PAGAMENTI è la "molti". Questo significa che, per ogni record di FATTURA, potresTi avere uno, nessuno, centomila records di PAGAMENTI.

La query che restituisce dei dati a partire dalla relazione di queste due tabelle, "moltiplica" il numero di records risultanti.

Fattura Pagamento
1 1
1 2
2 1
3 1
3 2
3 3

Come vedi qui sopra, la fattura 1 ha 2 pagamenti, la fattura 2 ne ha uno solo e la fattura 3 ne ha 3.
I records di fattura vengono riportati una volta per ogni pagamento, e questo, ovviamente, ti fa sballare la somma.

I casi sono due : o spezzi in due la query, calcolando una volta il totale di pagamenti ed una volta quello di fattura (in quest'ultimo caso, però, devi togliere dalla query il join con pagamenti), oppure modifichi la tua query per evitare che l'importo della fattura venga preso in considerazione più volte...

Ciao - Fabio
Fabio G

zseven Profilo | Senior Member

Grazie mille per la risposta, sei stato chiarissimo!
Infatti ho provato ad eliminare dalla query la join con la tabella pagamenti, e la somma dell'importo delle fatture avviene correttamente.

Resta però il problema che ho assolutamente bisogno di mettere in relazione anche la tabella dei pagamenti per poter effettuare in visualizzazione di pagina una serie di calcoli sul da pagare rispetto al fatturato.
Potresti indirizzarmi meglio su come risolvere il problema?
Cioè mi è chiaro quello che dici, ma non so come attuarlo...
Grazie

Ciciu Profilo | Senior Member

Una prima idea che mi viene è :

Sum(iif(campo is null or campo = 1;tab_fatture.importo_ft;0)) AS somma

Questo significa : Le somme da fare sulla tabella Fattura, le fai solo se un determinato campo ha valore null oppure ha valore 1.

Posso immaginare che la Tua tabella Pagamenti abbia, oltre al link con la fattura, anche un campo (compreso nella chiave primaria) che identifica la sequenza del pagamento. Se questo campo ha una numerazione progressiva che parte da 1 per ogni fattura, il gioco è fatto : se, nella query, il campo vale null, allora la fattura non ha pagamenti, quindi nella sum considero l'importo. Se il campo ha valore 1, quindi esiste almeno un pagamento, nella sum considero l'importo. Se il campo ha valore 2, andrò a sommare 0, poiché la mia condizione non è soddisfatta...

Immagino che il Tuo DB sia Access... Confermi ?
Non sono sicurissimo della sintassi, ma su quella ci puoi lavorare...

Ciao - FabioG
Fabio G

lbenaglia Profilo | Guru

>Una prima idea che mi viene è :
>
>Sum(iif(campo is null or campo = 1;tab_fatture.importo_ft;0))
>AS somma

Io invece proporrei n query da unire tramite l'operatore UNION ognuna delle quali calcola il valore di pertinenza.
Se posti la struttura completa delle tabelle (CREATE TABLE), alcune righe di prova (INSERT INTO) ed il risultato che ti aspetti proverò a scriverti la query.

Ciao!

--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

Ciciu Profilo | Senior Member

Scusa, ma con la Union, come può ottenere le 4 sum sullo stesso record ?
Almeno, questo è quanto ho capito...
Cia'
Fabio
Fabio G

lbenaglia Profilo | Guru

>Scusa, ma con la Union, come può ottenere le 4 sum sullo stesso
>record ?

Semplice, alla fine aggreghi tutto con un bel MAX() eliminando di conseguente le colonne che avrai preventivamente valorizzato a NULL o 0.

>Almeno, questo è quanto ho capito...
Hai capito bravo

Ciao!

--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

zseven Profilo | Senior Member

credo di aver capito cosa dici...
...ma sulla tabella pagamenti ho solo l'ID della chiave primaria e l'id secondario collegato alla tabella fatture, oltre ovviamente ai dati del pagamento. Ma non ho nessun progressivo relativo ad ogni singolo pagamento.

non c'è un'altra soluzione?
Grazie

zseven Profilo | Senior Member

Cia Ibenaglia,
mentre rispondevo ho visto che avevi dato quest'altro suggerimento... del quale però non ho capito veramente niente!!
Se mi date un indirizzo email vi posso spedire il database, così date uno sguardo alle relazioni ed alla query in questione.

Che ne dite?
Grazie a tutti

Ciciu Profilo | Senior Member

Quella di Lorenzo !
Fabio G

Ciciu Profilo | Senior Member

La mia è f.grande@poker.it
Fabio G

zseven Profilo | Senior Member

Te l'ho inviato!

lbenaglia Profilo | Guru

>Cia Ibenaglia,

Ciao lbenaglia

>mentre rispondevo ho visto che avevi dato quest'altro suggerimento...
>del quale però non ho capito veramente niente!!
>Se mi date un indirizzo email vi posso spedire il database, così
>date uno sguardo alle relazioni ed alla query in questione.

No, no, o posti qua in modo che TUTTI possano intervenire alla discussione, oppure non se ne fa niente
Questo è un forum di discussione, non un help desk.

Ciao!

--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

zseven Profilo | Senior Member

ok allora cerco di spiegarti le tabelle meglio che posso.
LE tabelle comprese nella query sono le seguenti:

Tab_categorie
- ID_categorie
- nome_categoria
- descrizione_categoria

Tab_voci
- ID_voci
- id_categoria (collegato a ID_categorie)

Tab_ordini
- ID_ordini
- id_voce (collegato a ID_voci)

Tab_fatture
- ID_fatture
- id_ordine (collegato a ID_ordini)
- importo_ft
- conto_anticipo

Tab_pagamenti
- ID_pagamenti
- id_fattura (collegato a ID_fatture)
- importo_pagamento
- importo_pagamento_anticipo

I campi che ho la necessità di mostrare sono:

nome_categoria (raggruppato per questo)
descrizione_categoria (raggruppato)
importo_ft (la somma di tutti i valori)
conto_anticipo (la somma)
importo_pagamento (lasomma)
importo_pagamento_anticipo(la somma)

Spero di aver spiegato al meglio la situazione che ho ed il problema indicato sopra.

Grazie mille.
Speriamo che riuscite ad aiutarmi ragazzi!

Ciciu Profilo | Senior Member

Tanto il db è arrivato...

Cmq, la soluzione applicata, in Benaglia-Style, è (semplificando un po' le cose) :

select campoa, campob, max(importo1), max(importo2)
from
(select campoa, campob, 0 as importo1, sum(importo2) as importo2
union
select campoa, campob, sum(importo1) as importo1, 0 as importo2)
group by campoa, campob

Continuo ad aver "capito bravo" ?!?!?!?!


Fabio G

lbenaglia Profilo | Guru

>ok allora cerco di spiegarti le tabelle meglio che posso.
Se rileggi bene io ti ho chiesto i comandi SQL, alcune righe di prova ed il risultato preciso che vuoi ottenere...

--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

lbenaglia Profilo | Guru

>select campoa, campob, max(importo1), max(importo2)
>from
>(select campoa, campob, 0 as importo1, sum(importo2) as importo2
> union
>select campoa, campob, sum(importo1) as importo1, 0 as importo2)
>group by campoa, campob
>
>Continuo ad aver "capito bravo" ?!?!?!?!
Direi di no dato che mancano le clausole FROM delle due subqueries
Senza comandi DML e righe di esempio non mi ci metto nemmeno ad improvvisare (perché di questo stiamo parlando) una query...

--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

Ciciu Profilo | Senior Member

Vabbé, dai, lascia fare.... le from me le sono dimenticate ma, ovviamente, ci vanno !
Quello che mi interessa è il concetto di base, non la soluzione al problema.
Devo dire che non ho mai usato una soluzione di questo tipo...
Secondo Te, in termini di elaborazione, è più veloce questa soluzione rispetto all'utilizzo di decode/case/iif ?

Ciao - Fabio
Fabio G

lbenaglia Profilo | Guru

>Secondo Te, in termini di elaborazione, è più veloce questa soluzione
>rispetto all'utilizzo di decode/case/iif ?
Ovviamente si
Immagina di avere milioni di righe. Con la tua soluzione costringi SQL Server a verificare OGNI SINGOLA RIGA prima di effettuare l'eventuale aggregazione e ciò probabilmente comporterà un table scan; la mia soluzione si limita ad eseguire le 2, 3,...n query e poi aggrega una manciata di righe.

Ciao!

--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

zseven Profilo | Senior Member

Ciao ragazzi,
scusate l'assenza per tutto il pomeriggio ma sono tornato soltanto adesso.
Come prima cosa grazie a Fabio per la query inviatami, il problema è che non ci ho capito assolutamente niente della query che mihai inviato. Non c'è dubbio che mi servirà, ma vorrei capirla, anche perchè dovrei utilizzare query simili per molti altri report.
Vedo una tabella con un nome strano "%&##Alias" e non ci capisco davvero niente.

Per Lorenzo.
Scusami ma non ho capito precisamente cosa ti serve per potermi aiutare.
Da quello che hai scritto non ho capito cosa vuoi... sono un pò cretino, potresti spiegarmi meglio cosa devo mostrarti?

Magari anche fare un passo alla volta. Ame interessa sì ottenere il risultato, ma se non ci capisco niente è pressochè inutile, non trovate?

Grazie infinite a tutti per l'aiuto.

zseven Profilo | Senior Member

Forse sto capendo...
vi posto la query:

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

In pratica fai due SELECT.
Una che somma i valori delle fattur e l'altra che somma i valori dei pagamenti. Entrambe con le relazioni che avevo impostato.
Poi le unisci.
Sono due le cose che non mi sono del tutto chiare.
Quel "AS" finale con il nome strano di tabella, e i valori che metti "0 AS somma"....etc etc...
che significa utilizzare questa dicitura?

Grazie mille

lbenaglia Profilo | Guru

>Per Lorenzo.
>Scusami ma non ho capito precisamente cosa ti serve per potermi
>aiutare.

1) Che DBMS utilizzi?
In base alla risposta orienterò le mie eventuali altre domande

Ciao!
--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

zseven Profilo | Senior Member

ACCESS 2003

lbenaglia Profilo | Guru

>ACCESS 2003
OK, prepara un nuovo mdb con 2 tabelle di esempio che riproducano la tua situazione ma MOLTO semplificate (quindi con un numero più limitato di colonne, diciamo al max 5 o 6), ciascuna popolata con una decina di righe di prova, fai un bello zip ed allegalo al prossimo post tramite l'apposito link (Allega un File) e spiega dettagliatamente che risultato ti aspetteresti dalla query che vuoi scrivere (nel corpo del messaggio).

A questo punto se i dati saranno completi ti preparerò la query spiegandoti i passaggi in modo che tu possa riprodurre la stessa situazione sul vero database, OK?

Attendo impaziente una tua risposta

Ciao!
--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

zseven Profilo | Senior Member

Eccomi qui.
Lorenzo ho dovuto mettere per forza tre tabelle, altrimenti non era chiaro il mio problema.
In pratica la query mi resituitsce una somma degli importi delle fatture non esatto.
Dovrebbe darmi 120000 ed invece mi da 240000.

Ti allego il db così ti è piu chiaro il tutto.
Grazie mille!

squilibrium Profilo | Junior Member

Hai provato a fare una join tra 2 subquery?
una query del tipo

select * from

(select id_fattura, sum(pagamento) from tb_pagamenti group by id_fattura) as qryPagamenti

inner join

(select * from tb_fatture) as qryfatture

on qryPagamenti.id_fattura = qryfatture.id_fattura

le join con le altre tabelle le fai dentro la qryFatture

Ciciu Profilo | Senior Member


Ciao.
Quel "AS [%$##@_Alias]" è qualcosa che aggiunge Access. In pratica attribuisce un alias (un "soprannome", se così vogliamo dire) alla tabella risultante dalla query compresa tra parentesi quadre.
Le query che fanno la parte degli attori di una union, per essere unite devono tassativamente avere gli stessi campi. Questo significa che, per esempio, la somma degli importi derivanti dalla tabella pagamenti, deve esistere in entrambe. Solo che, mentre in una è effettivamente la somma dei pagamenti, nell'altra è fissata a 0. La group by finale, aggrega i dati, estraendo solo le colonne valorizzate, grazie alla funzione max().

Spero di essere stato chiaro.

Ciao - Fabio
Fabio G

zseven Profilo | Senior Member

La query me la sono studiata un pò e dovrei averla capita.
Ma tu l'hai scritta tutta da solo, o ti ha aiutato access?
Perchè sto provando a farne una simile per un altro report, e in pratica faccio con access le SELECT semplici relative alle semplice relazioni, e poi vado a scrivere le union, le sum e i max...
ma da quello che hai scritto mi sa che access ti ha aiutato anche per leunion ed il resto, giusto?

Ciciu Profilo | Senior Member

Ciao.

>Ma tu l'hai scritta tutta da solo, o ti ha aiutato access?
A parte l'idea di Lorenzo, che mi ha dato lo "start", l'ho scritta a mano.

Ovviamente sono partito dalla Tua query e l'ho modificata.

Personalmente, per lavoro utilizzo Oracle e SQLServer, ed in entrambi i casi ho imparato a scrivere le query "a mano", evitando ogni tipo di Wizard... Quando mi capita di usare Access, però, tendo ad utilizzare il wizard per farmi scrivere automaticamente una query base, con i campi che mi interessano. Le logiche particolari, poi, le implemento scrivendo...

Ciao - Fabio
Fabio G

lbenaglia Profilo | Guru

>Ti allego il db così ti è piu chiaro il tutto.

Prova a dare un'occhiata alla seguente query:

SELECT Nome , Descrizione , MAX(Importo) AS SumImporto , MAX(Anticipo) AS SumAnticipo , MAX(Pagamento) AS SumPagamento , MAX(PagamentoAnticipo) AS SumPagamentoAnticipo FROM( SELECT C.nome_categoria AS Nome , C.descrizione_categoria AS Descrizione , SUM(F.importo_ft) AS Importo , SUM(F.conto_anticipo) AS Anticipo , 0 AS Pagamento , 0 AS PagamentoAnticipo FROM tab_categorie AS C INNER JOIN tab_fatture AS F ON C.ID_categorie = F.id_categoria GROUP BY C.nome_categoria, C.descrizione_categoria UNION ALL SELECT C.nome_categoria , C.descrizione_categoria , 0 , 0 , SUM(P.importo_pagamento) , SUM(P.importo_pagamento_anticipo) FROM (tab_categorie AS C INNER JOIN tab_fatture AS F ON C.ID_categorie = F.id_categoria) LEFT JOIN tab_pagamenti AS P ON F.ID_fatture = P.ID_fattura GROUP BY C.nome_categoria, C.descrizione_categoria ) AS Q GROUP BY Nome, Descrizione;

SQL Server permette di riscrivere la precedente query in modo più "compresso":

SELECT C.nome_categoria AS Nome , C.descrizione_categoria AS Descrizione , SUM(DISTINCT F.importo_ft) AS SumImporto , SUM(DISTINCT F.conto_anticipo) AS SumAnticipo , SUM(P.importo_pagamento) AS SumPagamento , SUM(P.importo_pagamento_anticipo) AS SumPagamentoAnticipo FROM tab_categorie AS C INNER JOIN tab_fatture AS F ON C.ID_categorie = F.id_categoria LEFT JOIN tab_pagamenti AS P ON F.ID_fatture = P.ID_fattura GROUP BY C.nome_categoria, C.descrizione_categoria;

La clausola DISTINCT permette di selezionare solo i valori distinti, quindi la somma risulterà corretta.

>Grazie mille!
Prego.

Ciao!

--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5