Group by questo sconosciuto

martedì 22 luglio 2008 - 16.33

Vinsanto Profilo | Newbie

Ciao a tutti,
oggi mi sono trovato con un problemino a cui non trovo soluzione.
Prendiamo come esempio il database Northwind presente su SQL 2000 ed eseguiamo questa query:
select CustomerID, OrderDate from dbo.Orders where CustomerID='ALFKI'

in particolare analiziamo i record
CustomerID OrderDate ALFKI 1997-10-03 00:00:00.000 ALFKI 1997-10-13 00:00:00.000

quello che sto cercando di ottenere con una query è, partendo dai due record sopra descritti, questo:
CustomerID OrderDate ALFKI 03,13 Ottobre

Cerco di spiegarmi meglio, vorrei, con una select, eseguire una group by sul CustomerID e in un altro campo eseguire la concatenazione dei giorni con lo stesso mese. La mia idea era quella di fare group by sia su CustomerId che sull'anno e mese della data solo che dopo non riesco a trovare una funzione di aggregazione che mi concateni le stringhe. Mi servirebbe qualcosa del tipo

select CustomerID , year(OrderDate) as anno , month(OrderDate) as mese , concatenamiGiorni(OrderDate) as giorni from dbo.Orders where CustomerID='ALFKI' group by CustomerID, year(OrderDate), month(OrderDate)

Il problema è che non ho trovato nemmeno sul sito Microsoft TechNet nessuna funzione di aggregazione che faccia quello che voglio io.

Mi sono venute in mente due soluzioni
1) Dato che il tutto verrà usato da una pagina aspx, prendere il risultato della select sula tabella di partenza e tramite codice C# mettere tutto su un datatable e manipolarlo con un paio di cicli.
2) Crearmi una Function in SQL che faccia quello che voglio io, piccolo problema non ho la minima idea di come si possa creare una Function SQL che lavori come funzione di aggregazione (se avete dei link mi fareste un grandissimo favore)

Ho scartato la prima strada dato che la select in realtà ha una quindicina di join e il quantitativo di dati su cui lavoro è notevole, quindi lavorare da codice C# eseguendo la select, metterela in un datatable e poi scorrerlo tutto ho paura che mi deteriori le prestazioni. Penso che eseguire il tutto sul motore SQL e farmi restituire solo i risultati sia molto più veloce.

Grazie a tutti e Ciao

P.S. Lavoro su SQL server 2000

alx_81 Profilo | Guru

>Ciao a tutti,
Ciao

Prova a vedere questo post se può esserti di aiuto
http://groups.google.com/group/microsoft.public.it.sql/browse_thread/thread/134a68f5b76db686
--

Alessandro Alpi | SQL Server MVP

http://www.alessandroalpi.net
http://blogs.dotnethell.it/suxstellino
http://mvp.support.microsoft.com/profile/Alessandro.Alpi
http://italy.mvps.org

Dainesi Profilo | Senior Member

Esiste una terza via.

Se il tuo obiettivo è l'output (magari in forma tabellare) allora procedi così:

- Esegui la tua select aggregata con l'accortezza di ordinare i campi data.
- Ogni volta che devi "riempire" il campo giorni (quello che tu volevi frutto di una concatenazione) confronti se il record successivo si riferisce allo stesso cliente e se si aggiungi (concateni la data) mentre in caso contrario chiudi la riga e passi alla successiva inserendo il nome del prossimo cliente.

In questo modo scorri il recordset una sola volta e non applichi costore routine di ulteriore accesso ai dati. Le performance non ne avranno a male ...

Vinsanto Profilo | Newbie

>>Ciao a tutti,
>Ciao
>
>Prova a vedere questo post se può esserti di aiuto
>http://groups.google.com/group/microsoft.public.it.sql/browse_thread/thread/134a68f5b76db686
>--
>
>Alessandro Alpi | SQL Server MVP
>

Ciao Alessandro e Grazie mille per l'interessamento.

Solo che ho un piccolo problema legato alla tipologia di dato, ell'esempio che mi ha presentato esegue una concatenazione tra varchar, io invece lavoro su date, nel tuo esempio c'è:

SELECT Durata, dbo.ufn_Concat(Durata) FROM dbo.Dati GROUP BY Durata;

nel mio
select CustomerID , year(OrderDate) as anno , month(OrderDate) as mese , dbo.ufn_Concat(OrderDate) as giorni from dbo.Orders where CustomerID='ALFKI' group by CustomerID, year(OrderDate), month(OrderDate)

e questo mi da errore dato che nella clausola group by non ho "OrderDate", ma quel campo non lo posso mettere nella group by dato che a me servirebbe il raggruppamento solo per anno e mese e non per giorno.

Vinsanto Profilo | Newbie

>Esiste una terza via.
>
>Se il tuo obiettivo è l'output (magari in forma tabellare) allora
>procedi così:
>
>- Esegui la tua select aggregata con l'accortezza di ordinare
>i campi data.
>- Ogni volta che devi "riempire" il campo giorni (quello che
>tu volevi frutto di una concatenazione) confronti se il record
>successivo si riferisce allo stesso cliente e se si aggiungi
>(concateni la data) mentre in caso contrario chiudi la riga e
>passi alla successiva inserendo il nome del prossimo cliente.
>
>In questo modo scorri il recordset una sola volta e non applichi
>costore routine di ulteriore accesso ai dati. Le performance
>non ne avranno a male ...

Immagino tu stia parlando di creare codice in C# che si metta a scorrere i risultati della mia select, come ho detto prima sto lavorando in aspx e non vorrei caricare troppo di lavoro IIS, preferire che il lavoro "sporco" lo facesse SQL server, si parla potenzialmente di qualche milionata di record e preferirei farmi restituire da SQL solo i record gia elaborati anche per evitare traffico di rete inutile.

Mi sta venendo in mente proprio ora che sto scrivendo che potrei fare il tutto tramite stored.

Ok ci provo grazie mille per l'aiuto
Ciao

lbenaglia Profilo | Guru

>Solo che ho un piccolo problema legato alla tipologia di dato

Questo è un esempio compatibile con SQL Server 2000 e superiori che dovrebbe soddisfare le tue esigenze:

USE tempdb; CREATE TABLE dbo.Orders( CustomerID char(5) NOT NULL, OrderDate datetime NOT NULL ); INSERT dbo.Orders VALUES('ALFKI', '19970101 00:00:00.000'); INSERT dbo.Orders VALUES('ALFKI', '19971003 00:00:00.000'); INSERT dbo.Orders VALUES('ALFKI', '19971013 00:00:00.000'); INSERT dbo.Orders VALUES('ALFKI', '19971101 00:00:00.000'); INSERT dbo.Orders VALUES('ALFKI', '19971102 00:00:00.000'); INSERT dbo.Orders VALUES('ALFKI', '19971130 00:00:00.000'); INSERT dbo.Orders VALUES('ALFKI', '19971201 00:00:00.000'); INSERT dbo.Orders VALUES('ALFKI', '19971205 00:00:00.000'); INSERT dbo.Orders VALUES('ALFKI', '19971231 00:00:00.000'); INSERT dbo.Orders VALUES('ALFKI', '19980101 00:00:00.000'); GO CREATE FUNCTION dbo.ufn_GetLastMonthDay( @Date datetime ) RETURNS datetime BEGIN RETURN DATEADD(month, DATEDIFF(month, 0, @Date) + 1, 0) - 1; END GO CREATE FUNCTION dbo.ufn_ConcatenaGiorni( @CustomerID char(5), @Anno int, @Mese int ) RETURNS varchar(122) BEGIN DECLARE @Output varchar(122); SET @Output = ''; /* Calcolo il primo del mese */ DECLARE @OrderDate datetime; SET @OrderDate = DATEADD(year, @Anno - 1900, 0) + DATEADD(month, @Mese - 1, 0); SELECT @Output = @Output + ', ' + CONVERT(char(2), OrderDate, 103) FROM dbo.Orders WHERE CustomerID = @CustomerID AND OrderDate BETWEEN @OrderDate AND dbo.ufn_GetLastMonthDay(@OrderDate) ORDER BY OrderDate; RETURN STUFF(@Output, 1, 2, ''); END GO SELECT Q.* , dbo.ufn_ConcatenaGiorni(Q.CustomerID, Q.Anno, Q.Mese) AS Giorni FROM ( SELECT CustomerID , YEAR(OrderDate) AS Anno , MONTH(OrderDate) AS Mese FROM dbo.Orders WHERE CustomerID = 'ALFKI' GROUP BY CustomerID, YEAR(OrderDate), MONTH(OrderDate) ) AS Q; /* Output: CustomerID Anno Mese Giorni ---------- ----------- ----------- ----------- ALFKI 1997 1 01 ALFKI 1997 10 03, 13 ALFKI 1997 11 01, 02, 30 ALFKI 1997 12 01, 05, 31 ALFKI 1998 1 01 (5 row(s) affected) */ DROP FUNCTION dbo.ufn_ConcatenaGiorni, dbo.ufn_GetLastMonthDay; DROP TABLE dbo.Orders;

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

Vinsanto Profilo | Newbie

Scusa se ti rispondo solo ora, ma sono stato parecchio incasinato in ufficio (oltre ad essere andato anche in ferie).
Grazie mille per il tuo aiuto, la soluzione da te proposta è quella che ho implementato nella struttura del progetto.

Grazie ancora
CIAO!!!
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