22 messaggi dal 07 aprile 2011
Ciao a tutti,
mi trovo a dover sviluppare una query per calcolare gli acquisti effettuati tutti gli utenti del db elencati per prodotto, l'unico grattacapo è che essendoci molto utenti che hanno acquistato più prodotti e dovendo per forza elencare il Modello del prodotto non posso fare una somma totale per utente , quindi se ad esempio un utente ha acquistato 2 prodotti dovrei sommare al secondo record il prezzo del record precedente e ovviamente portare il campo N_Acquisti a 2
esempio :
Nome, Cognome,Provincia, ModelloPRod TotaleSpeso N_ACQ
Mario ROssi MI NOmeMOdello 500 1
Mario Rossi MI NomeMOdello prezzo+prezzoPRecedente 2

COme posso realizzare una cosa del genere, ammesso che sia possibile ?

Grazie anticipatamente a tutti =).
1.976 messaggi dal 27 luglio 2005
Contributi
salve,
eldest139 wrote:
Ciao a tutti,
mi trovo a dover sviluppare una query per calcolare gli acquisti effettuati tutti gli utenti del db elencati per prodotto, l'unico grattacapo è che essendoci molto utenti che hanno acquistato più prodotti e dovendo per forza elencare il Modello del prodotto non posso fare una somma totale per utente , quindi se ad esempio un utente ha acquistato 2 prodotti dovrei sommare al secondo record il prezzo del record precedente e ovviamente portare il campo N_Acquisti a 2
esempio :
Nome, Cognome,Provincia, ModelloPRod TotaleSpeso N_ACQ Mario ROssi MI NOmeMOdello 500 1 Mario Rossi MI NomeMOdello prezzo+prezzoPRecedente 2 COme posso realizzare una cosa del genere, ammesso che sia possibile ? Grazie anticipatamente a tutti =).

non indichi quale motore relazionale tu stia utilizzando, parlero' quindi di quello che un po' conosco, Microsoft SQL Server, dove putroppo non e' direttamente fattibile, in quanto la sintassi supportata ancora non prevede una funzionalita' del tipo "PREVIOUS", che lo standard ANSI scriverebbe similarmente a

SELECT SUM(colonna) OVER (PARTITION BY IdOrdine ORDER BY idRigaOrdine RANGE UNBOUND PRECEEDING AND CURRENT ROW) AS [RunningTotal]
FROM tabellaDettaglioOrdini
WHERE....;

una funzionalita' di windowing potentissima che estende la presente (SQL Server 2005 e 200 la clausola OVER(..) risolvendo facilmente, in maniera molto elegante e con prestazioni eccellenti (solitamente limitate ad un singolo scan) le diffuse problematiche di aggregazione parziale dei running totals...
detto questo, solitamente si ricorre a pesanti (in termini prestazionali) self join fra la tabella ordini coinvolta con se stessa al fine di aggregare in sommatoria il valore desiderato..
ad esempio potresti scrivere similarmente a
SET NOCOUNT ON;
USE tempdb;
GO
CREATE TABLE dbo.Clienti (
Id int NOT NULL PRIMARY KEY,
Nome varchar(10) NOT NULL
);
CREATE TABLE dbo.Prodotti (
Id int NOT NULL PRIMARY KEY,
Nome varchar(10) NOT NULL,
Prezzo decimal (18,4) NOT NULL
);
CREATE TABLE dbo.Ordini_M (
Id int NOT NULL PRIMARY KEY,
Data datetime NOT NULL,
IdCliente int NOT NULL
CONSTRAINT fk_Ordini_M$has$Cliente
FOREIGN KEY REFERENCES dbo.Clienti (Id)
);
CREATE TABLE dbo.Ordini_D (
Id int NOT NULL IDENTITY PRIMARY KEY,
IdOrdine int NOT NULL
CONSTRAINT fk_Ordini_D$has$Ordine
FOREIGN KEY REFERENCES dbo.Ordini_M (Id),
IdProdotto int NOT NULL
CONSTRAINT fk_Ordini_D$is$Prodotto
FOREIGN KEY REFERENCES dbo.Prodotti (id),
Quantity decimal (18,4) NOT NULL
);
GO
INSERT INTO dbo.Clienti
VALUES ( 1, 'Andrea' ), ( 2, 'eldest139' ), ( 3, 'Daniele' ); INSERT INTO dbo.Prodotti
VALUES ( 1, 'a', 1.1 ), ( 2, 'b', 2.2 ), ( 3, 'c', 3.3 ), ( 4, 'd', 4.4 ), ( 5, 'e', 5.5 );

INSERT INTO dbo.Ordini_M VALUES ( 1, '20110101', 1 );
INSERT INTO dbo.Ordini_D
VALUES ( 1, 1, 2 ), ( 1, 2, 1 );

INSERT INTO dbo.Ordini_M VALUES ( 2, '20110101', 2 );
INSERT INTO dbo.Ordini_D
VALUES ( 2, 1, 2 ), ( 2, 2, 1 ), ( 2, 3, 1 ), ( 2, 4, 1 );

INSERT INTO dbo.Ordini_M VALUES ( 3, '20110101', 3 );
INSERT INTO dbo.Ordini_D
VALUES ( 3, 3, 1 ), ( 3, 4, 1 );

GO
SELECT c.Id, c.Nome,
m.Id, m.Data,
p.Nome, d.Quantity, p.Prezzo, p.Prezzo * d.Quantity AS [Costo], (SELECT SUM(p2.Prezzo * d2.Quantity)
FROM dbo.Ordini_D d2
JOIN dbo.Prodotti p2 ON d2.IdProdotto = p2.Id
WHERE d2.IdOrdine = d.IdOrdine AND d2.Id <= d.Id ) AS [Progressivo di costo]
FROM dbo.Ordini_D d
JOIN dbo.Ordini_M m ON d.IdOrdine = m.Id
JOIN dbo.Prodotti p ON d.IdProdotto = p.Id
JOIN dbo.Clienti c ON m.IdCliente = c.Id
ORDER BY c.Id, m.IdCliente, m.Data, d.Id;
GO
DROP TABLE dbo.Ordini_D, dbo.Ordini_M, dbo.Prodotti, dbo.Clienti; --<-----------
Id Nome Id Data Nome Quantity Prezzo Costo Progressivo di costo
--
--------
---
---------------------
--------
--------
------
----------
----------------------
1 Andrea 1 2011-01-01 00 0 0.000 a 2.0000 1.1000 2.20000000 2.20000000
1 Andrea 1 2011-01-01 00 0 0.000 b 1.0000 2.2000 2.20000000 4.40000000
2 eldest139 2 2011-01-01 00 0 0.000 a 2.0000 1.1000 2.20000000 2.20000000
2 eldest139 2 2011-01-01 00 0 0.000 b 1.0000 2.2000 2.20000000 4.40000000
2 eldest139 2 2011-01-01 00 0 0.000 c 1.0000 3.3000 3.30000000 7.70000000
2 eldest139 2 2011-01-01 00 0 0.000 d 1.0000 4.4000 4.40000000 12.10000000
3 Daniele 3 2011-01-01 00 0 0.000 c 1.0000 3.3000 3.30000000 3.30000000
3 Daniele 3 2011-01-01 00 0 0.000 d 1.0000 4.4000 4.40000000 7.70000000

che al di la' della trivialita' dell'esempio minimale, ben ti rende l'idea della pesantezza nell'esplosione cartesiana per l'aggregazione dei risultati intermedi... non so quale dbms supporti lo standard ANSI nelle funzionalita' di windowing sopra citate, ma la sintassi utilizzata come workaround e' relativamente standard e comune, anche se solitamente deprecata dagli amministratori di basi di dati proprio per la pesantezza di esecuzione... saluti

Andrea Montanari
http://www.hotelsole.com - http://www.hotelsole.com/asql/index.php
22 messaggi dal 07 aprile 2011
Grazie mille Spiegazione perfetta, grazie al tuo esempio ho risolto tutto in un attimo, Gentilissimo.

Ciao e grazie ancora

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.