22 messaggi dal 05 febbraio 2009
Ciao a tutti

devo scrivere una stored procedure che restituisce due campi per popolare una combo box, ma non riesco a farlo, o meglio riesco a farlo solo in parte.

Le tabelle sono T1 e T2 con i campi (metto solo quelli che mi servono):

T1: Id1, Descrizione, tipo2;
T2: Id2, Valore, tipo3, tipo4, Ottimo.

LA stored che ho scritto è questa:
  BEGIN
    SELECT T1.Descrizione, 
           T2.Valore
    FROM T1 , T2 
    WHERE T1.tipo2 = 1
      AND T2.tipo3 = 1
    ORDER BY T2.Ottimo
    
    RETURN @modello
    RETURN @potNom
  END


C'è una relazione 1:molti fra T1.Id1 e T2.tipo4

Con la stored sopra ottengo tante righe quante sono quelle di T1 a cui sono associati tanti valori quanti sono quelli della t2, invece dovrei ottenere una riga di t1 ed il relativo valore che leggo in t2 (forse manca un join, ma non sò scriverlo ...), inoltre non mi ordina per il campo Ottimo che è di tipo Byte e per ultimo non sò se i due parametri si restituiscono in quel modo (poi li devo leggere attraverso un DataReader).

Potete darmi una mano a correggerla?

Grazie
Modificato da andrea99999 il 05 marzo 2009 20.17 -
Modificato da andrea99999 il 05 marzo 2009 20.18 -
1.976 messaggi dal 27 luglio 2005
Contributi
salve,
andrea99999 ha scritto:
Ciao a tutti

devo scrivere una stored procedure che restituisce due campi per popolare una combo box, ma non riesco a farlo, o meglio riesco a farlo solo in parte.

Le tabelle sono T1 e T2 con i campi (metto solo quelli che mi servono):

T1: Id1, Descrizione, tipo2;
T2: Id2, Valore, tipo3, tipo4, Ottimo.

LA stored che ho scritto è questa:
  BEGIN
    SELECT T1.Descrizione, 
           T2.Valore
    FROM T1 , T2 
    WHERE T1.tipo2 = 1
      AND T2.tipo3 = 1
    ORDER BY T2.Ottimo
    
    RETURN @modello
    RETURN @potNom
  END




non hai scritto una belllissima query.. l'hai lasciata indicando la sintassi di join ANSI 89, e sarebbe meglio scriverla nella nuova sintassi, con indicazione esplicita delle join..
tendenzialmente

SET NOCOUNT ON;
USE tempdb;
GO
CREATE TABLE dbo.t2 (
  Id2 int,
  Valore varchar(5),
  tipo3 int,
  tipo4 int,
  Ottimo int
  );
CREATE TABLE dbo.t1 (
  Id1 int,
  Descrizione varchar(5),
  tipo2 int
  );
GO
INSERT INTO dbo.t2 VALUES ( 1, 'x', 1, 4, 5 );
INSERT INTO dbo.t2 VALUES ( 2, 'y', 1, 4, 5 );

INSERT INTO dbo.t1 VALUES ( 1, 'x', 1 );
INSERT INTO dbo.t1 VALUES ( 2, 'z', 1 );
GO
SELECT t1.Descrizione, t2.Valore
  , t1.Id1, t2.Id2
  FROM dbo.t1 t1
  JOIN dbo.t2 t2 ON t1.tipo2 = t2.Id2
  WHERE t1.tipo2 = 1
    AND t2.tipo3 = 1
  ORDER BY t2.Ottimo;
GO
DROP TABLE dbo.t1, dbo.t2;




C'è una relazione 1:molti fra T1.Id1 e T2.tipo4

Con la stored sopra ottengo tante righe quante sono quelle di T1 a cui sono associati tanti valori quanti sono quelli della t2, invece dovrei ottenere una riga di t1 ed il relativo valore che leggo in t2 (forse manca un join, ma non sò scriverlo ...), inoltre non mi ordina per il campo Ottimo che è di tipo Byte e per ultimo non sò se i due parametri si restituiscono in quel modo (poi li devo leggere attraverso un DataReader).


cos'e' il tipo "byte"? SQL Server non ha questo tipo di dato, che dbms stai usando? se trattasi di un varbinary, non capisco bene che tipo di ordinamento tu possa aspettarti o pretendere..
al di la' di cio', usi anche 2 return,
RETURN @modello
RETURN @potNom
.. di nuovo, non so che dbms tu stia utilizzando, ma mi pare comunque strano questo possa essere fatto.. in SQL Server la sintassi del "return" di una stored procedure permette di caricarci solo un valore numerico nel dominio degli interi, quindi probabilmente non va bene nel tuo caso, e comunque di ritornare 1 ed 1 solo valore..
andrebbe quindi modificato con una
SELECT @modello, @potNom;
che ritornerebbe appunto il relativo result set, oppure le due variabili potrebbero caricare 2 parametri della procedura dichiarati come OUTPUT, e quindi suscettibili di ritornare valori, ma da quanto dici,ì (l'uso di un reader) direi che ti serva il resultset..
ora, prendi il codice che ho postato, modifica le righe come a te interessanti e magari spiega meglio (portando l'esempio completo di DDL e dati di insert) cosa vuoi ottenere..
saluti

Andrea Montanari
http://www.hotelsole.com - http://www.hotelsole.com/asql/index.php
22 messaggi dal 05 febbraio 2009
Intanto grazie per l'aiuto; i dbms li faremo il prox anno, ma volevo iniziare ad imparare le SP ed i trigger, quindi sono alle prime armi ...

Ecco le risposte: uso SQL Server 2008 express; il tipo booleano è un "bit" e non un "byte", mi ero confuso, anche i RETURN ho sbagliato il cut/paste, infatti i due parametri li ho dicharati come OUTPUT ma non sò come legarli ai parametri t1.descrizione e t2.valore della SELECT principale ... come scrivo questa associazione???

Ho comunque modificato la SP come mi hai indicato e funziona (ad esclusione ovviamente di quei due parametri di outout), inoltre volevo chiederti a cosa serve il DROP TABLE finale ... non vorrei che mi cancellasse i dati nelle mie tabelle ...

Ciao & grazie
1.976 messaggi dal 27 luglio 2005
Contributi
salve,
andrea99999 ha scritto:
Intanto grazie per l'aiuto; i dbms li faremo il prox anno, ma volevo iniziare ad imparare le SP ed i trigger, quindi sono alle prime armi ...


personalmente non ho mai cominciato le "cose" direttamente "facendo", ma prima studiando l'architettura, ma forse questo e' un problema mio :)

con questo non dico che imbrattarsi subito le mani scrivendo queries sia sbagliato, ma prima, almeno personalmente, mi piacerebbe sapere "cosa sto facendo".. poi il resto va tutto bene, sempre che se ne sia compresa la "filosia" di base, sia dell'architettura che della scelta fatta..


Ecco le risposte: uso SQL Server 2008 express; il tipo booleano è un "bit" e non un "byte", mi ero confuso,


il bit, in SQL Server, non e' un vero valore booleano.. e' infatti un numero nel dominio degli interi, ma limitato ad accettare 3 sole valorizzazioni:
1 (solitamente accettato come "True")
0 (solitamente accettato come "False")
NULL

questo potrebbe essere il tuo problema circa l'ordinamento inaspettato.. se pensavi che True fosse = -1, e quindi l'ordinamento standard crescente : -1 , 0
allora sei purtroppo stato tratto in inganno.. infatti un ordinamento crescente per una colonna di tipo bit restituisce prima 0 e poi 1..

anche i RETURN ho sbagliato il cut/paste, infatti i due parametri li ho dicharati come OUTPUT ma non sò come legarli ai parametri t1.descrizione e t2.valore della SELECT principale ... come scrivo questa associazione???


non avviente un'associazione bensi' un'assegnazione.. che avviene direttamente nell'esecuzione della proiezione, quindi nello statement di SELECT..
tipicamente avrai quindi
DECLARE @p1 int, @p2 int;
SELECT @p1 = col1, @p2 = col2
FROM ....
WHERE ....;

non indico un order by per un motivo molto semplice.. come sicuramente ben sai, l'operazione di ORDER BY e' un'operazione di cursore che avviene al termine della proiezione stessa.. la worktable risultante dalla proiezione, includente tutte le eventuali subquery e tutte le join, viene alla fine ordinata secondo quanto indicato nella clausola ORDER BY..
visto che nel caso in esame parliamo di un'assegnazione ad una variabile, la cosa ha poco senso in quanto l'assegnazione dovrebbe essere di per se unica, cioe' il filtro di WHERE dovrebbe ritornare una ed una sola riga, cosi' che l'assegnazione possa avere un senso.. in caso diverso, per ogni riga risultante, si avrebbe un'assegnazione dei parametri. cio' sta ad indicare che, qualora fossero ritornate piu' righe, solo l'ultima riga sarebbe risultante (e vincitrice) nell'assegnazione dei parametri.
questo in SQL Server, ma probabilmente anche in altri dbms.. dico questo in quanto, ad esempio in FireBird, questo tipo di sintassi viene utilizzata per vere e proprie operazioni sia di cursore che di restituzione dei dati, e la sintassi di SELECT prevede un vero e proprio datapump al chiamante con l'istruzione SUSPEND, che invia la riga ritornata al chiamante prima di riprendere l'esecuzione del ciclo.. in questo c'e' una grossa differenza con SQL Server, in quanto in FireBird ogni singola riga viene materializzata conseguentemente, e va in questo modo processata (ripeto, sia restituendola al chiamante che magari internamente per successive operazioni row based), mentre in SQL Server verra' solamente materializzato un (o diversi, in quanto SQL Server consente ad esempio stored procedure che ritornino piu' di un resultset) resultset al termine della proiezione completa, che verra' poi ritornato al chiamante non riga per riga ma come un set di dati, serializzato in uno stream, il T(abular) D(ata) S(tream), un protocollo proprietario Microsoft, che al suo interno contiene sia resultset, che messaggi, che valorizzazione di parametri in Input/Output.. questa e' una delle piu' grosse differenze architetturali che puoi trovare, e se non sbaglio anche Oracle opera similarmente.. spesso infatti i programmatori Oracle che arrivano a SQL Server si trovano in difficolta' per questo diverso modus operandi, che forza il programmatore ad operare in maniera "set based" e non "row based".. ma stiamo divagando :)
tornando al problema, personalmente non ti consiglierei l'utilizzo dei parametri di output, ma ovviamente non conosco il "tuo problema"..
ritornerei quindi al chiamante direttamente la proiezione desiderata, quindi
SELECT col_List FROM .. WHERE .. (ORDER BY..[nel caso di set di dati con piu' di una riga]);
e sara' poi il chiamante a consumare i dati come desiderato..
ovviamente puoi anche prendere la strada dei parametri in Input/Output e nulla lo vieta, sempre che il risultato della proiezione sia al massimo mono riga..


Ho comunque modificato la SP come mi hai indicato e funziona (ad esclusione ovviamente di quei due parametri di outout), inoltre volevo chiederti a cosa serve il DROP TABLE finale ... non vorrei che mi cancellasse i dati nelle mie tabelle ...


quando si prepara un esempio, e' buona norma fornirne uno che includa "il tutto".. con questo si intende sia il codice DDL di creazione degli oggetti coinvolti, le eventuali righe di INSERT INTO per popolare le tabelle come desiderato, il codice DML eventualmente provato/da provare/consigliato come soluzione, (nel caso di domanda e non di risposta si deve indicare anche cosa si desidera ottenere in base ai dati forniti), ed "infine", il codice di cleanup che provveda alla pulizia di quanto "fatto".. il DROP finale che ho messo, appunto, provvede alla eliminazione delle tabelle che faccio generare, in modo che, alla fine dell'esecuzione dello script, la macchina sulla quale e' stato eseguito sia esattamente nelle medesime condizioni (in termini di catalogo e ovviamente non in termini di risorse consumate, quali memoria etc) di prima dell'esecuzione dello stesso.. e' quindi una forma civile e di buon senso per una serena "convivenza" :) avrai tra l'altro notato che la seconda istruzione dello script, dopo SET NOCOUNT ON; (che serve a rimuovere la messaggistica emessa da SQL Server relativamente al numero di righe interessate dall'operazione da eseguirsi), sia USE tempdb; , che serve a "spostare" l'ambito di esecuzione di tutto lo script non gia' in un database utente qualsiasi, bensi' nel database di sistema "tempdb", il database utilizzato da SQL Server per tante funzionalita', che vanno dallo storage temporaneo per worktable, agli ordinamenti, etc.. quindi gli oggetti generati nel contesto dello script non "sporcheranno" mai dei database "importanti"..

quindi, tornando alla tua domanda, quelle istruzioni di DROP cancellano fisicamente le tabelle che prima avevo fatto generare e, ovviamente, non vanno lasciate nel database finale di destinazione :)
saluti

Andrea Montanari
http://www.hotelsole.com - http://www.hotelsole.com/asql/index.php
22 messaggi dal 05 febbraio 2009
Il fatto di usare un campo bit per inserire valori booleani mi pare che l'ho letto proprio sul sito della Microsoft, ma se non và bene quale campo posso usare come campo booleano? Un int e valorizzarlo 0 di default o 1?? In pratica in quella tabella una sola riga sarà valore ottimo.

Per i parametri di output, devo popolare una combo box in un form Windows; quindi non ho solo un valore ma più valori, il primo è quello che ha quel campo bool = true, e poi gli altri sono ordinati in maniera discendente rispetto al valore T2.Valore.

Quindi in conclusione faccio la select tradizionale, l'order by si scrive così:

order by Ottimo and T2.Valore DESC ??

E poi dal programma chiamante istanzio un DataReader, eseguo la SP, leggo i valori restituiti e compilo la combo box.
Il fatto du isare dei parametri di output è solo perchè credevo che quello fosse l'unico modo per "inserirli" nel DataReader una volta eseguita la SP.
Modificato da andrea99999 il 07 marzo 2009 10.07 -
1.976 messaggi dal 27 luglio 2005
Contributi
salve,
andrea99999 wrote:
Il fatto di usare un campo bit per inserire valori booleani mi pare che l'ho letto proprio sul sito della Microsoft, ma se non và bene quale campo posso usare come campo booleano? Un int e valorizzarlo 0 di default o 1?? In pratica in quella tabella una sola riga sarà valore ottimo.

puoi tranquillamente utilizzare il tipo bit, giusto ricordati la sua peculiarita' relativamente all'ordinamento che desideri..

Per i parametri di output, devo popolare una combo box in un form Windows; quindi non ho solo un valore ma più valori, il primo è quello che ha quel campo bool = true, e poi gli altri sono ordinati in maniera discendente rispetto al valore T2.Valore.

Quindi in conclusione faccio la select tradizionale, l'order by si scrive così:

order by Ottimo and T2.Valore DESC ??

ORDER BY [Ottimo] DESC, t2.Valore ASC;
in questo modo hai l'ordinamento per il valore bit con prima i valori 1 e poi i valori 0, e poi l'ordinamento continua per t2.Valore (ascendente)
E poi dal programma chiamante istanzio un DataReader, eseguo la SP, leggo i valori restituiti e compilo la combo box.
Il fatto du isare dei parametri di output è solo perchè credevo che quello fosse l'unico modo per "inserirli" nel DataReader una volta eseguita la SP. Modificato da andrea99999 il 07 marzo 2009 10.07 -
no, il datareader e' una tecnologia che ti permette di scorrere (solo in avanti) il resultset eventualmente restituito.. i parametri in output invece sono da "verificare" nell'oggetto .Command, che appunto ha un collezione di ..Parameters ..
saluti

Andrea Montanari
http://www.hotelsole.com - http://www.hotelsole.com/asql/index.php
22 messaggi dal 05 febbraio 2009
non avviente un'associazione bensi' un'assegnazione.. che avviene direttamente nell'esecuzione della proiezione, quindi nello statement di SELECT.. 
tipicamente avrai quindi 
DECLARE @p1 int, @p2 int; 
SELECT @p1 = col1, @p2 = col2 
FROM .... 
WHERE ....; 

Se scrivo così ottengo però l'errore:
Le istruzioni SELECT per l'assegnazione di valori alle variabili non devono essere eseguite insieme a operazioni di recupero dei dati.

Effettivamente con google ho trovato questa sintassi, che però in sql server 2008 sembra non funzionare.
Ti posto la SP con l'assegnazione che non funziona:

  SET NOCOUNT ON;
  
  DECLARE @mod varchar(40);

  BEGIN
  
    SELECT @mod = TTipoTecnologia.Descrizione, <-- errore
           TValoriParTecnologie.Valore, 
           TTipoTecnologia.Id ,
           TValoriParTecnologie.IdTipoTecnologia 
    FROM dbo.TTipoTecnologia TTipoTecnologia
    JOIN dbo.TValoriParTecnologie TValoriParTecnologie
    ON   TTipoTecnologia.Id = TValoriParTecnologie.IdTipoTecnologia   
    WHERE TValoriParTecnologie.IdParTecnologia = 1
      AND TTipoTecnologia.IdEnergia = 1
    ORDER BY TValoriParTecnologie.ValoreOttimo desc,
         TValoriParTecnologie.Valore desc
    
    
    SET @mod = @modello
    SELECT @modello as [Modello]
  END


Ho comunque letto che in questo modo viene restituito solo l'ultimo valore, e non più valori nel caso come il mio la select ne restituisse diversi.

no, il datareader e' una tecnologia che ti permette di scorrere (solo in avanti) il resultset eventualmente restituito..

Però a me serve per popolare una combo box, quindi potrebbe andarmi bene, oppure faccio come mi hai suggerito?
Modificato da andrea99999 il 11 marzo 2009 17.54 -
1.976 messaggi dal 27 luglio 2005
Contributi
salve,
andrea99999 wrote:

Se scrivo così ottengo però l'errore:
Le istruzioni SELECT per l'assegnazione di valori alle variabili non devono essere eseguite insieme a operazioni di recupero dei dati.
Effettivamente con google ho trovato questa sintassi, che però in sql server 2008 sembra non funzionare.
Ti posto la SP con l'assegnazione che non funziona:

SET NOCOUNT ON;

DECLARE @mod varchar(40);

BEGIN

SELECT @mod = TTipoTecnologia.Descrizione, <
errore
TValoriParTecnologie.Valore,
TTipoTecnologia.Id ,
TValoriParTecnologie.IdTipoTecnologia
FROM dbo.TTipoTecnologia TTipoTecnologia
JOIN dbo.TValoriParTecnologie TValoriParTecnologie
ON TTipoTecnologia.Id = TValoriParTecnologie.IdTipoTecnologia WHERE TValoriParTecnologie.IdParTecnologia = 1
AND TTipoTecnologia.IdEnergia = 1
ORDER BY TValoriParTecnologie.ValoreOttimo desc,
TValoriParTecnologie.Valore desc


SET @mod = @modello
SELECT @modello as [Modello]
END

il messaggio di errore e' "chiaro"... parte della proiezione fa un assegnazione e parte ritorna dei dati.. la devi scomporre in 2, oppure fare una completa assegnazione seguita dal ritorno dei dati tipo


assegnazione
SELECT @mod = TTipoTecnologia.Descrizione,
@altroParam= TValoriParTecnologie.Valore,
@altroParamAncora= TTipoTecnologia.Id ,
..... FROM ...

SELECT @mod, @altroParam, @altroParamAncora ...
che invece restituira' un resultset monoriga..


Ho comunque letto che in questo modo viene restituito solo l'ultimo valore, e non più valori nel caso come il mio la select ne
restituisse diversi.

e' corretto.. in altri dbms non e' cosi', come dicevo prima... ma in SQL Server, se hai un parametro e la proiezione ritorna 5 righe, il parametro sara' caricato con il valore della 5 riga..

no, il datareader e' una tecnologia che ti permette di scorrere (solo in avanti) il resultset eventualmente restituito..
Però a me serve per popolare una combo box, quindi potrebbe andarmi bene, oppure faccio come mi hai suggerito?

certo che ti puo' bastare.. scorri il Reader e popoli il combobox, anche se "architetturalmente" non e' piu' cosi' bello.. in teoria dovresti ritornare alla form una "Lista"... list of (....)
popoli la lista, che sia essa una datatable, list of strings, list of YourClass, ... , e quindi ritorni la lista al form, che scorrera' la lista per il caricamento o la mettera' in databinding.. ma questo e' altro argomento
saluti

Andrea Montanari
http://www.hotelsole.com - http://www.hotelsole.com/asql/index.php

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.