Salve,
probabilmente HAI sbagliato gruppo in quanto questo e' pertinente per SQL Server, ed il dialetto che hai postato NON e' utilizzabile con questo DBMS...
detto cio', e restando in ambito SQL Server, questo modo di scrivere codice NON e' mai consigliato in quanto questo DBMS non e' stato progettato, come invece altri (vedi Oracle, Postgres, ....), per "ciclare" sulle righe ma, sulla scorta del suo progenitore Sybase, e' stato progettato per lavorare al meglio con i "set" di dati per intiero.
quindi, i cicli vanno meglio ristudiati (e ripudiati laddove possibile) al fine di evitare quello che in SQL Server richiederebbe l'utilizzo di un "CURSOR", che di base gestisce "male" le risorse in quanto richiede ad ogni ciclo l'intervento del codice utente (cosa si vuol fare con la riga corrente? assegnazioni?, oerazioni?, ....).
Il dialetto utilizzato da SQL Server permette tranquillamente l'utilizzo di Common Table Expressions che possono efficacemente "splittare" una stringa in "sotto-stringhe" da restituire in un set, che potra' poi essere utilizzato per la proiezione successiva, che restituira' la JOIN tra il set che popola la Common Table Expression e le altre tabelle/viste/funzioni necessarie.
In questo caso mi pare di aver compreso sia richiesto una "concatenazione", altra operazione tendenzialmente onerosa in termini di risorse, che in SQL Server ora puo' essere risolta utilizzando l'estensione di proiezione FROM ... FOR XML, funzionalita' che oltre ad una migliore prestanza computazionale in termini di risorse, consente anche l'eventuale possibilita' di ordinamento del risultato (laddove richiesto), operazione che sara' eseguita precedentemente all'operazione di concatenazione di stringhe, cosa che invece la concatenazione tradizionale non permette, visto che sappiamo bene che l'operazione di ordinamente e' "semanticamente" sempre l'ultima operazione eseguita nell'esecuzione di una query, quindi "sempre e solo DOPO" il popolamento del set di dati finale.
Non conosco il DBMS che stai studiando, ma in ambiente SQL Server (e mi risulta ovunque), per "codice dinamico" si intende:
- codice SQL generato dal client e passato al motore per la sua esecuzione dinamica, quindi NON utilizzando moduli interni al DBMS quali stored procedure, viste, funzioni...
- codice SQL generato ad esempio all'interno di una stored procedure laddove si richiedano ad esempio set mai standard tra loro, dipendenti da parametri forniti alla procedura; mi vengono in mente ad esempio "rotazioni" da riga a colonna che l'istruzione PIVOT non puo' gestire laddove non si conosca a priori la cardinalita' delle colonne da ruotare nel risultato... e questa query NON lo richiede
Se sei arrivato fino a qui, allora probabilmente utilizzi SQL Server ma non scrivi codice per esso, e tornando alla richiesta, quindi, in Transact-SQL (dialetto di SQL Server) possiamo risolvere il problema indicato senza usare codice dinamico, trivialmente:
considerando uno scenariocome di seguito (non posto il DDL in quanto solitamente inibito dal parser del forum)
[Gruppo]{CodG varchar(n), ...}
[Utente]{CodU varchar(n), CodG varchar(n), Cognome varchar(n), Nome varchar(n)}
cosi' popolato
[Gruppo] ( '00001' ), ( '00002' ), ( '00003' ),( '00004' ), ( '00005' );
[Utente] ( '00001', '00001', 'A', 'a' )
( '00002', '00002', 'B', 'b' ), ( '00003', '00002', 'C', 'c' )
( '00004', '00003', 'D', 'd' ), ( '00005', '00003', 'E', 'e' ), ( '00006', '00003', 'F', 'f' );
possiamo procedere come di seguito:
-- parametro in ingresso di ricerca
DECLARE @param varchar(8000) = '00001@00002@00003@00004';
-- carattere separatore dei codici Gruppo
DECLARE @sep char(1) = '@';
PRINT 'Common Table Expression per "splittare" la stringa di parametro in righe separate di Token con Id Gruppo';
WITH Pieces(pn, startPos, endPos, flgList) AS (
SELECT 1, 1, CHARINDEX(@sep, @param), @param AS flgList
UNION ALL
SELECT pn + 1, endPos + 1, CHARINDEX(@sep, Pieces.flgList , endPos + 1), Pieces.flgList
FROM Pieces
WHERE endPos > 0
),
cteAllGroups AS (
SELECT LTRIM(RTRIM(SUBSTRING(Pieces.flgList, startPos, CASE WHEN endPos > 0 THEN endPos-startPos ELSE 8000 END))) AS [CodG]
FROM Pieces
)
SELECT * FROM cteAllGroups;
-- parametro in OutPut che concatena tutti i risultati
DECLARE @output varchar(MAX) = '';
--
PRINT 'la common table expression viene messa in join con Utenti e si ottiene la proiezione';
WITH Pieces(pn, startPos, endPos, flgList) AS (
SELECT 1, 1, CHARINDEX(@sep, @param), @param AS flgList
UNION ALL
SELECT pn + 1, endPos + 1, CHARINDEX(@sep, Pieces.flgList , endPos + 1), Pieces.flgList
FROM Pieces
WHERE endPos > 0
),
cteAllGroups AS (
SELECT LTRIM(RTRIM(SUBSTRING(Pieces.flgList, startPos, CASE WHEN endPos > 0 THEN endPos-startPos ELSE 8000 END))) AS [CodG]
FROM Pieces
)
SELECT * FROM cteAllGroups g
JOIN [dbo].[Utente] u ON u.[CodU] = g.[CodG]
PRINT 'concatenamento del risultato richiesto';
PRINT ' -> utilizzo di concatenazione standard, meno elegante';
WITH Pieces(pn, startPos, endPos, flgList) AS (
SELECT 1, 1, CHARINDEX(@sep, @param), @param AS flgList
UNION ALL
SELECT pn + 1, endPos + 1, CHARINDEX(@sep, Pieces.flgList , endPos + 1), Pieces.flgList
FROM Pieces
WHERE endPos > 0
),
cteAllGroups AS (
SELECT LTRIM(RTRIM(SUBSTRING(Pieces.flgList, startPos, CASE WHEN endPos > 0 THEN endPos-startPos ELSE 8000 END))) AS [CodG]
FROM Pieces
)
SELECT @output +=
-- separatore tra Utenti, se richiesto
CASE WHEN LEN(@output) >0 THEN '@' ELSE '' END
-- concatenazione di Cognome + Nome separati da ","
+ u.[Cognome] + ',' + u.[Nome]
FROM cteAllGroups g
JOIN [dbo].[Utente] u ON u.[CodG] = g.[CodG];
SELECT @output;
-- cleanup
SELECT @output = '';
PRINT 'concatenamento del risultato richiesto';
PRINT ' -> utilizzo di concatenazione con espressione FOR XML, piu'' elegante E permette ordinamento interno';
WITH Pieces(pn, startPos, endPos, flgList) AS (
SELECT 1, 1, CHARINDEX(@sep, @param), @param AS flgList
UNION ALL
SELECT pn + 1, endPos + 1, CHARINDEX(@sep, Pieces.flgList , endPos + 1), Pieces.flgList
FROM Pieces
WHERE endPos > 0
),
cteAllGroups AS (
SELECT LTRIM(RTRIM(SUBSTRING(Pieces.flgList, startPos, CASE WHEN endPos > 0 THEN endPos-startPos ELSE 8000 END))) AS [CodG]
FROM Pieces
)
SELECT @output +=
STUFF((SELECT '@'
+ u.[Cognome] + ',' + u.[Nome]
AS [text()]
FROM cteAllGroups g
JOIN [dbo].[Utente] u ON u.[CodG] = g.[CodG]
ORDER BY g.[CodG], u.[CodU] DESC
FOR XML PATH('')
), 1, 1, '' );
SELECT @output;
con risultato
concatenamento del risultato richiesto
-> utilizzo di concatenazione standard, meno elegante
--------------------------------------------------------
A,a@B,b@C,c@D,d@E,e@F,f
concatenamento del risultato richiesto
-> utilizzo di concatenazione con espressione FOR XML, piu' elegante E permette ordinamento interno
--------------------------------------------------------
A,a@C,c@B,b@F,f@E,e@D,d
saluti omnia
--
Andrea