salve,
la cosa e' "parzialmente" sostituibile in SQL Server 2000, ad esempio utilizzando la "concatenzazione" implicita di una variabile di tipo "carattere", quindi aggiungendo l'estrazione di ogni riga al valore gia' "raccolto" similarmente a
SET NOCOUNT ON;
GO
USE tempdb;
GO
CREATE TABLE dbo.t1 (
Id int NOT NULL PRIMARY KEY,
Data varchar(20) NOT NULL
);
CREATE TABLE dbo.t2 (
Id int NOT NULL IDENTITY PRIMARY KEY,
IdT int NOT NULL
CONSTRAINT FK_t2$has$t1 FOREIGN KEY
REFERENCES dbo.t1 (Id),
Data varchar(10) NOT NULL
);
GO
INSERT INTO dbo.t1 VALUES (1, 'header1');
INSERT INTO dbo.t1 VALUES (2, 'header2');
INSERT INTO dbo.t1 VALUES (3, 'header3');
INSERT INTO dbo.t1 VALUES (4, 'empty');
INSERT INTO dbo.t2 VALUES (1, 'row1.1');
INSERT INTO dbo.t2 VALUES (2, 'row2.1');
INSERT INTO dbo.t2 VALUES (2, 'row2.2');
INSERT INTO dbo.t2 VALUES (3, 'row3.1');
INSERT INTO dbo.t2 VALUES (3, 'row3.2');
INSERT INTO dbo.t2 VALUES (3, 'row3.3');
GO
CREATE FUNCTION dbo.udf_GetT2$Concat (
@IdT1 int
) RETURNS varchar(1000)
AS BEGIN
DECLARE @value varchar(1000);
SET @value = '';
SELECT @value = @value + CASE WHEN DATALENGTH(@value) <> 0 THEN ',' ELSE '' END + t2.Data
FROM dbo.t2 t2
WHERE t2.IdT = @IdT1
ORDER BY t2.Data;
RETURN (@value);
END;
GO
SELECT t1.Id, t1.Data, dbo.udf_GetT2$Concat(t1.Id) AS [Concat]
FROM dbo.t1 t1
ORDER BY t1.Id
GO
DROP FUNCTION dbo.udf_GetT2$Concat;
DROP TABLE dbo.t2, dbo.t1;
GO
--<---------
Id Data Concat
----------- -------------------- ---------------------
1 header1 row1.1
2 header2 row2.1,row2.2
3 header3 row3.1,row3.2,row3.3
4 empty
dove la variabile @value deve essere dimensionata sufficientemente "grande" da poter ospitare la concatenazione dei risultati.. questo dimensionamento non puo' eccedere gli 8000 caratteri o 4000 unicode, a seconda venga utilizzato il tipo di dato carattere "normale" (varchar) o carattere nazionale (nvarchar)...
sappi pero' che questa espressione puo' dare risultati non corretti in termini di ordinamento... malgrado la funzione utente espliciti un'estrazione "... ORDER BY t2.Data;", come ben sai l'ordinamento di un'estrazione e' "l'ultima parte" eseguita in una query di estrazione.. a dire il vero non fa neanche parte della query stessa, nel senzo che:
tipicamente, una query SQL viene eseguita come segue, almeno in teoria, visto che ogni produttore poi chiaramente cerca di ottimizzare sia le operazioni preliminari che l'insieme generale al fine di migliare le prestazioni...
-) iniziando dalla clausola FROM, viene construita una working table che tenga in considerazione tutte le tabelle conivolte, quindi JOIN, unioni, intersezioni eccetera.. l'aliasing di tabelle e SUBQUERY consente successivamente di "nominare" tale risultato..
-) la clausola WHERE rimuove le righe che non soddisfino i filtri impostati, cioe' che non ritornino, in base al filtro di WHERE, un risultato VERO (true), per cui falso e unknown vengono scartati.. tale clausola viene applicata al working set derivante dalla esplosione della clausola FROM..
-) l'eventuale presenza di una clausola GROUP BY provvede alla produzione degli aggregati riducendo ognuno di essi ad una singola riga, rimpiazzando la working table con la nuova aggragata.. le righe di una tale tabella devono avere caratteristiche di aggregazione, qualie un raggruppamento di colonna, una statistica sul raggruppamento (tipo le funzioni built'in di aggregazione), una funzione ovvero un'espressione composta dai tre elementi di cui sopra..
-) l'eventuale clausola opzionale HAVING, applicata alla working table raggruppata; qualora non fosse presente la clausola GROUP BY clause, l'intera working table viene trattata come un unico raggruppamento...
-) esplosione della proiezione con riferimento alla SELECT list, qundi dopo tutte le operazioni preliminari di selezione/intersezione/unione... le operazioni di algebra relazionale avvengono precedentemente.. l'utilizzo di alias di colonna avviene a livello atomico, sempre dopo l'esecuzione della proiezione, quindi non sono utilizzabili ad esempio nel filtro di WHERE...
l'eventuale presenza di DISTINCT provvede all'eliminazione di righe
duplicate..
-) subquery innestate utilizzano il normale scope dei linguaggi strutturali, per cui le piu' interne possono fare riferimento a colonne delle esterne che le contengono..
-) finalmente la clausola ORDER BY, che non e' piu' parte della query in quanto tale, ma di un'operazione di cursore; il risultato della query viene passato al cursore che porvvede all'ordinamento
visto che come visto lo storage engine, invece, puo' ritornare le righe che soddisfano il filtro di WHERE in qualsiasi ordine, ad esempio grazie alla parallelizzazione dell'operazione di estrazione, e che "l'aggregazione" sulla variabile temporanea utilizzata e' un'operazione "precedente" all'ordinamento eseguito solo successivamente, potenzialmente per t1.Id = 3 potresti ottenere il risultato "row3.3,row3.1,row3.2" ovvero una qualsiasi delle 9 possibilita' di aggregazione.. cio' non toglie che in SQL Server 2000 restava l'unica possibilita' di ottenere un risultato simile a quello richiesto..
saluti