ESERCIZIO SQL

di il
3 risposte

ESERCIZIO SQL

Salve vorrei confrontarvi con voi per quanto riguarda la traccia di un esercizio. ecco la traccia: "Usando SQL DINAMICO si scriva una funzione che riceve in ingresso una lista di codici di gruppi separati dal carattere '@' e che restituisce una stringa dei nomi e cognomi degli utenti (separati da @) che fanno parte di tutti i gruppi passati per parametro".
create or replace FUNCTION funzione100 (lista VARCHAR2)
RETURN VARCHAR2 IS

inizio INTEGER := 0;
fin INTEGER := 0;
gruppo VARCHAR2(30);
n Utente.Nome%TYPE;
m Utente.Cognome%TYPE;
res VARCHAR2(200);

BEGIN
LOOP
EXIT WHEN INSTR(lista,'@',1) <= 0

  fin := INSTR(lista, '@', inizio+1);
  gruppo := SUBSTR(lista, inizio+1,fin-1);
  
  IF EXISTS(
  SELECT U.nome,U.cognome 
  FROM Utente U JOIN gruppi G 
  ON u.codu = g.codu
  WHERE g.codg = gruppo)
  
  res := res || n || m || ',';

END LOOP;
RETURN res;
END;
  

3 Risposte

  • Re: ESERCIZIO SQL

    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
  • Re: ESERCIZIO SQL

    Riposto la domanda in oracle perché non mi hai dato la risposta che mi serviva grazie comunque
  • Re: ESERCIZIO SQL

    Eggia'...
    qui non si dovrebbe parlare di Oracle
    saluti omnia
    --
    Andrea
Devi accedere o registrarti per scrivere nel forum
3 risposte