none
SQL 2005: Stored Procedure complessa.. RRS feed

  • Domanda

  • Ciao a tutti, vediamo se riesco a farvi capire la mia necessità.  Ho una tabella, chiamata VALORIATTRIBUTI, con questa struttura:

    ID int (Primary Key Identity)

    IDDOC int (Foreign Key alla tabella DOCUMENTI)

    IDATTR int (Foreign Key alla tabella ATTRIBUTI)

    VALORE nvarchar(200)

    Bene, devo creare una stored procedure che, dato un elenco composto dalla combinazione IDATTR + VALORE mi restituisca la lista di IDDOC che ha quella particolare combinazione.  L'elenco IDATTR + VALORE è un XML che passo alla stored procedure con questa struttura

    <Attributes>
       <Attribute>
         <ID>300</ID>
          <VAL>TIP</VAL>
    </Attribute>
       <Attribute>
         <ID>350</ID>
         <VAL>LP</VAL>
       </Attribute>
      <Attribute>
          <ID>350</ID>
          <VAL>DT</VAL>
       </Attribute>
    </Attributes>

    Molto semplicemente butto tutto il contenuto dell'XML in una tabella temporanea (@Temp) che vado a mettere in inner join con la mia tabella ottenendo il risultato voluto, il mio problema è che qualora avessi campi ID identici, i valori devono essere messi in OR e non in AND.  Tradotto dovrei ottenere questo risultato

    SELECT IDDOC FROM VALORIATTRIBUTI WHERE (IDATTR=300 AND VALORE='TIP') AND (IDATTR=350 AND (VALORE='LP' OR VALORE='DT')

    Essendo il contenuto dell'XML dinamico non ho la più pallida idea di come farlo...

    Riuscite a darmi delle dritte?

    Ciao e grazie

    Enrico

     

    mercoledì 24 novembre 2010 09:47

Risposte

  • Ciao Alex, anzitutti grazie.  Ho risolto il problema e come da tua intuizione il problema era proprio nella join. ti copio la stored procedure per come l'ho fatta.

    	DECLARE @NFiltri Int
    
    	--creo la tabella di appoggio
    	CREATE TABLE #FILTRI(
    		IDATTR int,
    		VALORE nvarchar(50)
    	)
    
    	--inserisco i filtri nella tabella di appoggio
    	INSERT INTO #FILTRI (IDATTR, VALORE)
    	SELECT ParamValues.ID.value('IDATTR[1]','int') AS IDATTR ,ParamValues.ID.value('VALORE[1]','nvarchar(50)') as VALORE
    	FROM @XML.nodes('/Filters/Filter') as ParamValues(ID)
    
    	SET @NFiltri=(SELECT COUNT(DISTINCT IDATTR) FROM #FILTRI)
    
    	--FACCIO LA QUERY
    	SELECT DOCUMENTO.*
    	FROM DOCUMENTO
    	WHERE ID IN
    	(	
    		SELECT DISTINCT IDDOCUMENTO FROM ATTRIBUTODOCUMENTO
    		INNER JOIN #FILTRI ON ATTRIBUTODOCUMENTO.IDATTRIBUTO=#FILTRI.IDATTR AND ATTRIBUTODOCUMENTO.ATTRIBUTOVALUE=#FILTRI.VALORE
    		INNER JOIN DOCUMENTOELENCOELABORATI ON DOCUMENTOELENCOELABORATI.IDDOCUMENTO=ATTRIBUTODOCUMENTO.IDDOCUMENTO
    		WHERE DOCUMENTOELENCOELABORATI.IDELENCOELABORATI=@IDELENCOELABORATI AND
    			 dbo.GetDatePart(DOCUMENTOELENCOELABORATI.DATAINSERIMENTO) <= dbo.GetDatePart(@DATARIFERIMENTO) AND
    			 (ISNULL(DOCUMENTOELENCOELABORATI.DATARIMOZIONE, '1900-01-01') = '1900-01-01' OR
    			  dbo.GetDatePart(DOCUMENTOELENCOELABORATI.DATARIMOZIONE) >= dbo.GetDatePart(@DATARIFERIMENTO))
    		GROUP BY IDDOCUMENTO
    		HAVING COUNT(*) = @NFiltri
    	)
    
    

    La cosa che ho aggiunto, per far funzionarla funzionare come volevo, è stato aggiungere HAVING alla fine.  Adesso volevo vedere se c'è un modo per migliorare il WHERE sulla tabella DOCUMENTO perché mi sembra un po' macchinosa la cosa.

    Ti ringrazio ancora

    Enrico

    • Contrassegnato come risposta Enrico Gobbo giovedì 25 novembre 2010 15:56
    giovedì 25 novembre 2010 12:59

Tutte le risposte

  • forse per semplificare la domanda, e permettere a più utenti di provare ad aiutarti, potresti dirci le strutture delle 2 tabelle (@temp e quell'altra) con relativi dati, e quello che vorresti ottenere, dando così per scontato (mi sembra) la parte dove l' xml passato finisce in qualche modo nella tabella temporanea.

    Mi sembra di capire che il problema stia nella join tra le 2 tabelle

    giovedì 25 novembre 2010 09:40
  • Ciao Alex, anzitutti grazie.  Ho risolto il problema e come da tua intuizione il problema era proprio nella join. ti copio la stored procedure per come l'ho fatta.

    	DECLARE @NFiltri Int
    
    	--creo la tabella di appoggio
    	CREATE TABLE #FILTRI(
    		IDATTR int,
    		VALORE nvarchar(50)
    	)
    
    	--inserisco i filtri nella tabella di appoggio
    	INSERT INTO #FILTRI (IDATTR, VALORE)
    	SELECT ParamValues.ID.value('IDATTR[1]','int') AS IDATTR ,ParamValues.ID.value('VALORE[1]','nvarchar(50)') as VALORE
    	FROM @XML.nodes('/Filters/Filter') as ParamValues(ID)
    
    	SET @NFiltri=(SELECT COUNT(DISTINCT IDATTR) FROM #FILTRI)
    
    	--FACCIO LA QUERY
    	SELECT DOCUMENTO.*
    	FROM DOCUMENTO
    	WHERE ID IN
    	(	
    		SELECT DISTINCT IDDOCUMENTO FROM ATTRIBUTODOCUMENTO
    		INNER JOIN #FILTRI ON ATTRIBUTODOCUMENTO.IDATTRIBUTO=#FILTRI.IDATTR AND ATTRIBUTODOCUMENTO.ATTRIBUTOVALUE=#FILTRI.VALORE
    		INNER JOIN DOCUMENTOELENCOELABORATI ON DOCUMENTOELENCOELABORATI.IDDOCUMENTO=ATTRIBUTODOCUMENTO.IDDOCUMENTO
    		WHERE DOCUMENTOELENCOELABORATI.IDELENCOELABORATI=@IDELENCOELABORATI AND
    			 dbo.GetDatePart(DOCUMENTOELENCOELABORATI.DATAINSERIMENTO) <= dbo.GetDatePart(@DATARIFERIMENTO) AND
    			 (ISNULL(DOCUMENTOELENCOELABORATI.DATARIMOZIONE, '1900-01-01') = '1900-01-01' OR
    			  dbo.GetDatePart(DOCUMENTOELENCOELABORATI.DATARIMOZIONE) >= dbo.GetDatePart(@DATARIFERIMENTO))
    		GROUP BY IDDOCUMENTO
    		HAVING COUNT(*) = @NFiltri
    	)
    
    

    La cosa che ho aggiunto, per far funzionarla funzionare come volevo, è stato aggiungere HAVING alla fine.  Adesso volevo vedere se c'è un modo per migliorare il WHERE sulla tabella DOCUMENTO perché mi sembra un po' macchinosa la cosa.

    Ti ringrazio ancora

    Enrico

    • Contrassegnato come risposta Enrico Gobbo giovedì 25 novembre 2010 15:56
    giovedì 25 novembre 2010 12:59
  • bene sono contento. Per la query, non sò dovrei vedere bene adesso dopo lavoro sono un pò cotto.

    Cmq vedo una cosa, tu valorizzi la variabile @NFiltri e la utilizzi in fondo nella Having Count(*)

    Forse puoi mettere direttamente

    HAVING COUNT (*) = SELECT COUNT (DISTINCT IDATTR) FROM #FILTRI)

    e forse anche non dichiarare nemmeno la temporarea #FILTRI, ma fare tutto diretto, con 1 query in un colpo.

    Dovresti guadagnare in performance.

     

    giovedì 25 novembre 2010 19:09