Risultato Query in orizzontale

mercoledì 14 novembre 2007 - 16.00

allforum Profilo | Junior Member

Non sò se il titolo del thread è appropriato, ma il mio problema è il seguente:

Ho due tabelle, T1 e T2 (SQL2000)

in T1 ho i seguenti records:

cod
---
1
2
3
4

in T2 ho i seguenti records:

cod lettera
--- -------
1 A
1 B
1 C
2 C
2 F
3 A
4 B
4 C
4 A
4 D

Vorrei ottenere come risultato il seguente dataset ...

cod let1 let2 let3 let4 let5 ..... ecc
1 A B C
2 C F
3 A
4 B C A D

..... sapendo ovviamente che per ogni record di T1 possono corrispondere al massimo n records in T2 (diciamo massimo 10).

C'è qualcuno che potrebbe aiutarmi a costruire la query ? ... o dirmi dove posso trovare della documentazione?


alx_81 Profilo | Guru

>Non sò se il titolo del thread è appropriato, ma il mio problema
>è il seguente:
>C'è qualcuno che potrebbe aiutarmi a costruire la query ? ...
>o dirmi dove posso trovare della documentazione?
Ciao, puoi risolvere con una function di sql server, eccoti lo script di esempio.. lo avevo nei miei utili e non la usavo da tempo Se non ricordo male ho preso spunto da una simile di Andrea Benedetti, ma non trovo il link da passarti.. comunque eccola qui:

USE tempdb -- prima tabella CREATE TABLE T1 ( Id int NOT NULL PRIMARY KEY CLUSTERED ) GO -- popolo con gli id INSERT T1 SELECT 1 INSERT T1 SELECT 2 INSERT T1 SELECT 3 INSERT T1 SELECT 4 GO -- seconda tabella CREATE TABLE T2 ( Id int NOT NULL, Lettera char(1) NOT NULL, CONSTRAINT PK_T2 PRIMARY KEY CLUSTERED ( Id , Lettera ) ) GO -- popolo con le lettere INSERT T2 SELECT 1,'A' INSERT T2 SELECT 1,'B' INSERT T2 SELECT 1,'C' INSERT T2 SELECT 2,'C' INSERT T2 SELECT 2,'F' INSERT T2 SELECT 3,'A' INSERT T2 SELECT 4,'B' INSERT T2 SELECT 4,'C' INSERT T2 SELECT 4,'A' INSERT T2 SELECT 4,'D' GO SELECT T1.Id , T2.Lettera FROM T1 JOIN T2 ON T1.Id = T2.Id GO CREATE FUNCTION dbo.ufn_Trasponi ( @Id int ) RETURNS varchar(8000) AS BEGIN -- riga di ritorno DECLARE @retRiga varchar(8000) SET @retRiga = '' -- concateno alla riga la lettera per ogni id passato SELECT @retRiga = @retRiga + ' ' + Lettera FROM T1 JOIN T2 ON T1.Id = T2.Id WHERE T1.Id = @Id RETURN @retRiga END GO SELECT DISTINCT T1.Id , dbo.ufn_Trasponi(T1.Id) FROM T1 JOIN T2 ON T1.Id = T2.Id GO DROP TABLE T1 DROP TABLE T2 DROP FUNCTION dbo.ufn_Trasponi GO

spero possa aiutarti..
ciao!
Alx81 =)

http://blogs.dotnethell.it/suxstellino

lbenaglia Profilo | Guru

>Se non ricordo male ho preso spunto da una simile
>di Andrea Benedetti, ma non trovo il link da passarti..

Ciao Sux,

Quella funzione è un "best seller" del ng microsoft.public.it.sql che probabilmente Andrea avrà "fatto sua"
Comunque veniamo a noi. La soluzione che hai proposto non risponde alla domanda originale in quanto il tuo output è su due colonne:

Id ----------- ---------- 1 A B C 2 C F 3 A 4 A B C D (4 row(s) affected)

mentre il risultato desiderato è su 10 colonne:

cod let1 let2 let3 let4 let5 ... --- ---- ---- ---- ---- ---- 1 A B C 2 C F 3 A 4 B C A D

Purtroppo SQL Server 2000 è piuttosto limitato in questo senso dato che non offre gli operatori PIVOT e UNPIVOT e la funzione ROW_NUMBER(). Una soluzione che spesso proponevo, prevedeva l'utilizzo della funzione CASE() ed un bel raggruppamento.
Prima di tutto occorre modificare la struttura di T2 aggiungendo una colonna IDENTITY, poi si potrà scrivere la query:

USE tempdb; CREATE TABLE dbo.T1( Id int NOT NULL PRIMARY KEY ); CREATE TABLE dbo.T2( Id int NOT NULL IDENTITY PRIMARY KEY, T1_Id int NOT NULL, Lettera char(1) NOT NULL, CONSTRAINT FK_T2_T1 FOREIGN KEY(T1_Id) REFERENCES dbo.T1(Id) ); INSERT dbo.T1 VALUES(1); INSERT dbo.T1 VALUES(2); INSERT dbo.T1 VALUES(3); INSERT dbo.T1 VALUES(4); INSERT dbo.T2 VALUES(1, 'A'); INSERT dbo.T2 VALUES(1, 'B'); INSERT dbo.T2 VALUES(1, 'C'); INSERT dbo.T2 VALUES(2, 'C'); INSERT dbo.T2 VALUES(2, 'F'); INSERT dbo.T2 VALUES(3, 'A'); INSERT dbo.T2 VALUES(4, 'B'); INSERT dbo.T2 VALUES(4, 'C'); INSERT dbo.T2 VALUES(4, 'A'); INSERT dbo.T2 VALUES(4, 'D'); GO /* Query Crosstab */ CREATE VIEW dbo.vwCrosstab AS SELECT T1_Id , MAX(CASE Riga WHEN 1 THEN Lettera ELSE '' END ) AS Let1 , MAX(CASE Riga WHEN 2 THEN Lettera ELSE '' END ) AS Let2 , MAX(CASE Riga WHEN 3 THEN Lettera ELSE '' END ) AS Let3 , MAX(CASE Riga WHEN 4 THEN Lettera ELSE '' END ) AS Let4 , MAX(CASE Riga WHEN 5 THEN Lettera ELSE '' END ) AS Let5 , MAX(CASE Riga WHEN 6 THEN Lettera ELSE '' END ) AS Let6 , MAX(CASE Riga WHEN 7 THEN Lettera ELSE '' END ) AS Let7 , MAX(CASE Riga WHEN 8 THEN Lettera ELSE '' END ) AS Let8 , MAX(CASE Riga WHEN 9 THEN Lettera ELSE '' END ) AS Let9 , MAX(CASE Riga WHEN 10 THEN Lettera ELSE '' END ) AS Let10 FROM ( SELECT T1_Id, Lettera, ( SELECT COUNT(*) FROM dbo.T2 WHERE Q1.Id >= Id AND Q1.T1_Id = T1_Id ) AS Riga FROM dbo.T2 AS Q1 ) AS Q GROUP BY T1_Id GO /* Query finale */ SELECT V.* FROM dbo.T1 JOIN dbo.vwCrosstab AS V ON T1.Id = V.T1_Id; /* Output: T1_Id Let1 Let2 Let3 Let4 Let5 Let6 Let7 Let8 Let9 Let10 ----------- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----- 1 A B C 2 C F 3 A 4 B C A D (4 row(s) affected) */ DROP VIEW dbo.vwCrosstab; DROP TABLE dbo.T2, dbo.T1;

Ciao!

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

alx_81 Profilo | Guru

>>Se non ricordo male ho preso spunto da una simile
>>di Andrea Benedetti, ma non trovo il link da passarti..
>
>Ciao Sux,
>Quella funzione è un "best seller" del ng microsoft.public.it.sql
>che probabilmente Andrea avrà "fatto sua"
Se non ricordo male rispondeva ad un post.. ma non ha detto fosse sua.. la usava e basta
grazie per la correzione, ho intepretato male quei let1, let2, letn..
allora meglio riposarsi..



Alx81 =)

http://blogs.dotnethell.it/suxstellino

allforum Profilo | Junior Member

.... perfetto, ne farò tesoro di tutte e due. Grazie.

Un'ultima cosa, pensate che SQL 2005 abbia qualche strumento in più per ottenere facilmente lo stesso risultato ?

lbenaglia Profilo | Guru

>.... perfetto, ne farò tesoro di tutte e due. Grazie.
>
>Un'ultima cosa, pensate che SQL 2005 abbia qualche strumento
>in più per ottenere facilmente lo stesso risultato ?

Eh si, l'ho anche scritto
Cerca su MSDN i comandi PIVOT, UNPIVOT e ROW_NUMBER()

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