Creare intestazioni dinamiche per le colonne in Microsoft SQL

giovedì 25 gennaio 2007 - 14.18

MagicBotolo Profilo | Newbie

Ciao a tutti, sono nuovo del forum e volevo farvi i complimenti percè ho trovato un sacco di info su questo sito
Volevo fare una domanda sulle intestazioni delle colonne: è possibile creare i nomi delle intestazioni in maniera dinamica attraverso istruzioni SQL ?
In pratica io estraggo una colonna di dati dal database e per ogni dato estratto devo cercare altri dati e memorizzarli in un'altra tabella. Per fare questo ho creato una nuova tabella nella quale, tramite un ciclo While, aggiungo una colonna per ogni dato estratto durante la prima query e nella nuova colonna memorizzo i dati trovati con la seconda query. Il problema è che vorrei assegnare alle nuove colonne create un nome tipo "Colonna + (numero progressivo di colonna)". Sapete indicarmi una strada? Grazie...

Brainkiller Profilo | Guru

>Ciao a tutti, sono nuovo del forum e volevo farvi i complimenti
>percè ho trovato un sacco di info su questo sito
>Volevo fare una domanda sulle intestazioni delle colonne: è possibile
>creare i nomi delle intestazioni in maniera dinamica attraverso
>istruzioni SQL ?

Mah, puoi creare un alias della colonna, esempio:

select a,b,c from tabella

puoi trasformarlo in :

select A as Alfa, B as Beta, C as Gamma from tabella

Ora bisogna capire cosa vuoi fare con questi dati, se accodarli in una tabella esistente, o inserirli in una già presente. Rinominare le colonna nel modo che hai chiesto tu esempio colonna1, colonna2, ecc. penso sia possibile solo tramite un programmaino in C# o VB.NET dove manualmente vai a costruire le INSERT.




David De Giacomi | Microsoft MVP
http://blogs.dotnethell.it/david/

MagicBotolo Profilo | Newbie

Il problema è che a priori non so quante colonne avrò: ecco perchè vorrei creare una tabella con i nomi della colonna riferiti al dato estratto dalla prima query (per esempio: immaginando un database di dati ricavati da sensori, estraggo un certo numero di date e un certo numero di stanze nelle quali ho fatto misure. Poi creo una tabella dove ho tante righe quante sono le date e creo una nuova colonna per ogni stanza presente nella tabella originale. In ogni stanza ho un tot di misure che estraggo dal database originale e inserisco nella corrispondente colonna nella tabella appena creata. Il nome della colonna vorrei che derivasse dal nome della stanza. Altrimenti, se uso sempre lo stesso nome, Microsoft SQL segnala nome di colonna ripetuto e si ferma).
Ciao!!

lbenaglia Profilo | Guru

>Il problema è che a priori non so quante colonne avrò
<SNIP>

Ciao MagicBotolo,

ho letto e riletto i tuoi quesiti, ma devo ammettere che non ho capito niente
Potresti gentilmente fornirci un esempio completo, con la struttura delle tabelle (CREATE TABLE), alcune righe di prova (INSERT INTO) ed il risultato finale che vorresti ottenere?

Grazie,

Ciao!
--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

MagicBotolo Profilo | Newbie

Vediamo se sono un po' più chiaro... Io parto da una tabella contenente le colonne "DataOra", "Stanza", "Dato rilevato". Per ogni "DataOra" ho un certo numero di dati (memorizzati nella colonna "Dato rilevato"). Per ogni "DataOra" ho un certo numero di stanze (memorizzate nella colonna "Stanza"). Si tratta di dati ottenuti tramite monitoraggio ambientale. Io vorrei creare una tabella avente come righe i valori del campo "DataOra", come colonne i campi "Stanza" e come valori in ogni colonna i "Dato rilevato" corrispondenti.
Per il momento riesco a fare questa cosa tramite un'interfaccia realizzata in LabView: leggo il database, estraggo i valori che mi servono e creo la nuova tabella in LabView. Quando i dati diventano molti (50000 come ordine di grandezza) l'interfaccia realizzata in LabView mostra qualche limite di velocità. Io vorrei, se possibile, realizzare la stessa tabella tramite query in Microsoft SQL Server: dovrebbe (credo) risultare più veloce. Con LabView poi farò tutte le elaborazioni matematiche che mi servono.
Scusate la confusione
Ciao!!

lbenaglia Profilo | Guru

>Vediamo se sono un po' più chiaro... Io parto da una tabella
>contenente le colonne "DataOra", "Stanza", "Dato rilevato". Per
>ogni "DataOra" ho un certo numero di dati (memorizzati nella
>colonna "Dato rilevato"). Per ogni "DataOra" ho un certo numero
>di stanze (memorizzate nella colonna "Stanza"). Si tratta di
>dati ottenuti tramite monitoraggio ambientale. Io vorrei creare
>una tabella avente come righe i valori del campo "DataOra", come
>colonne i campi "Stanza" e come valori in ogni colonna i "Dato
>rilevato" corrispondenti.
Quello di cui stai parlando è una query cross tab.
Che DBMS e quale versione utilizzi?
Infine posta come già richiesto i comandi SQL per definire la tabella, una manciata di righe di prova ed il result set finale che vuoi ottenere con quei dati.

Ciao!
--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

MagicBotolo Profilo | Newbie

Eccomi qui dopo alcune prove. Io lavoro con Microsoft SQL Server 2000. Partendo da un altro post di questo forum nel quale si parlava di CrossTab Query e sfruttando un esempio scritto dal Benaglia (grazie 1000 per l'aiuto) ho creato questa procedura:

use Database_Dati;

GO
/*IF EXISTS dbo.sp_CrossTab THEN*/ DROP PROCEDURE dbo.sp_CrossTab -- Eliminazione procedura se già esistente

GO
CREATE PROC dbo.sp_CrossTab
@table AS sysname, -- Tabella sulla quale operare la CrossTab
@onrows AS nvarchar(128), -- Campo da inserire nella prima colonna della tabella finale
@onrowsalias AS sysname = NULL, -- Eventuale alias per la prima colonna
@oncols AS nvarchar(128), -- Campo da suddividere sulle colonne della tabella finale
@sumcol AS sysname = NULL, -- Campo da inserire come dato nella tabella finale
@sensore AS nvarchar(128) -- Identificativo sensore
AS

DECLARE
@sql AS varchar(8000), -- Stringa contenente la query da eseguire
@supporto_sql AS varchar(8000), -- Stringa di supporto se la prima stringa è corta
@NEWLINE AS char(1) -- Ritorno a capo (usato solo per leggibilità)

-- Inizializzazione variabili
SET @sql='';
SET @supporto_sql='';
SET @NEWLINE = CHAR(10)

-- Inizio creazione della stringa di query: prima colonna della tabella finale
SET @sql =
'SELECT' + ' ' + @onrows +
CASE
WHEN @onrowsalias IS NOT NULL THEN ' AS ' + @onrowsalias
ELSE ''
END

--PRINT ('step 1, @sql: ' + @sql)

-- Estrazione dei valori presenti nel campo da suddividere nelle colonne della tabella finale
CREATE TABLE #keys(keyvalue nvarchar(100) NOT NULL PRIMARY KEY)

DECLARE @keyssql AS varchar(4000)
SET @keyssql =
'INSERT INTO #keys ' +
'SELECT DISTINCT ' + @oncols +
' FROM ' + @table + ' WHERE ID_SENS=' + @sensore

SET NOCOUNT ON
EXEC (@keyssql)
SET NOCOUNT OFF

--PRINT ('step 2, #keyssql: ' + @keyssql);
--SELECT * FROM #keys;

-- Suddivisione delle colonne della tabella finale con i relativi dati
DECLARE @key AS nvarchar(100)

SELECT @key = MIN(keyvalue) FROM #keys
WHILE @key IS NOT NULL
BEGIN
SET @sql = @sql + ',' + @NEWLINE +
' SUM(CASE CAST(' + @oncols +
' AS nvarchar(100))' + @NEWLINE +
' WHEN N''' + @key +
''' THEN ' + CASE
WHEN @sumcol IS NULL THEN '1'
ELSE @sumcol
END + @NEWLINE +
' ELSE 0' + @NEWLINE +
' END) AS [' + @key + ']'

SELECT @key = MIN(keyvalue) FROM #keys
WHERE keyvalue > @key

IF LEN(@sql)>7950
BEGIN
SET @supporto_sql=@sql;
SET @sql=''
END;

END;

--PRINT ('step 3, @sql: ' + @sql)
--PRINT ('step 3bis, @supporto_sql: ' + @supporto_sql);

-- Esecuzione della stringa di query creata
--PRINT ('Query finale: ' + @supporto_sql + @sql + ' FROM ' + @table + ' WHERE ID_SENS=' + @sensore + ' GROUP BY ' + @onrows + ' ORDER BY ' + @onrows) -- For debug
EXEC (@supporto_sql + @sql + ' FROM ' + @table + ' WHERE ID_SENS=' + @sensore + ' GROUP BY ' + @onrows + ' ORDER BY ' + @onrows)
GO


-- Chiamata della procedura (da inserire nel programma chiamante)
/*EXEC dbo.sp_CrossTab
@table = 'NS_DATI',
@onrows = 'DATAORA',
@oncols = 'ID_MIS',
@sumcol = 'DATO',
@sensore = '158';

GO*/

Due domandone:
1) IF EXISTS dbo.sp_CrossTab THEN DROP PROCEDURE dbo.sp_CrossTab ... cosa sbaglio nella stringa iniziale che controlla se la procedura esiste già e in caso affermativo la cancella per memorizzarla nuovamente? Mi viene segnalato un errore prima del primo dbo ...
2) Come risultato dell'esecuzione della procedura ottengo una tabella perfetta per ciò che devo fare io. Il problema è che il database viene analizzato tramite LabView ed è quest'ultimo che fisicamente effettua le query. Normalmente, quando lavoro con query di selezione ed estrazione dati ("semplici" SELECT) ottengo come risultato della query un RECORDSET che posso manipolare con LabView per creare una tabella.
Con la Procedura creata nello script che ho riportato non ho RECORDSET in uscita. Come posso farmi restituire i dati (in formato tabellare o come RECORDSET sarebbe meglio)?

Grazie ancora...
Ciao!!

lbenaglia Profilo | Guru

>Eccomi qui dopo alcune prove. Io lavoro con Microsoft SQL Server
>Due domandone:
>1) IF EXISTS dbo.sp_CrossTab THEN DROP PROCEDURE dbo.sp_CrossTab
>... cosa sbaglio nella stringa iniziale che controlla se la procedura
>esiste già e in caso affermativo la cancella per memorizzarla
>nuovamente? Mi viene segnalato un errore prima del primo dbo
>...

Eh si, la sintassi è sbagliata
Utilizza questo codice:

IF NOT OBJECT_ID('dbo.sp_CrossTab') IS NULL DROP PROCEDURE dbo.sp_CrossTab;

>2) Come risultato dell'esecuzione della procedura ottengo una
>tabella perfetta per ciò che devo fare io. Il problema è che
>il database viene analizzato tramite LabView ed è quest'ultimo
>che fisicamente effettua le query. Normalmente, quando lavoro
>con query di selezione ed estrazione dati ("semplici" SELECT)
>ottengo come risultato della query un RECORDSET che posso manipolare
>con LabView per creare una tabella.
>Con la Procedura creata nello script che ho riportato non ho
>RECORDSET in uscita. Come posso farmi restituire i dati (in formato
>tabellare o come RECORDSET sarebbe meglio)?

Non conosco LabView, ma l'output generato dalla tua procedura è un normalissimo resultset, quindi dovrebbe essere la stessa identica cosa.

>Grazie ancora...
Prego.

Ciao!
--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

MagicBotolo Profilo | Newbie

Ho fatto altre prove: la procedura funziona a meraviglia e il risultato che voglio appare sullo schermo (nella finestra di Query Analyzer per intenderci). Però siccome i risultati non rientrano in un recordset LabView non li legge. Come posso modificare la procedura per far sì che il risultato finisca in una tabella? Perchè facendo così alla fine posso inserire un SELECT * FROM <tabella> e leggere i dati tramite LabView e Recordset. Tanto per dare un'idea: con LabView implemento la comunicazione tra interfaccia e database in modo molto simile a Visual Basic. Attraverso il driver ODBC richiamo il database e su questo faccio le query. Il risultato delle query viene estratto sottoforma di recordset: questo può essere manipolato (il primo comando è GetRows con il quale estraggo i dati e li presento all'utente dopo averli formattati in una tabella). Posso usare metodi tipo GetString e muovermi tra i record come in VB (anche la sintassi è molto simile).
Ciao!!

lbenaglia Profilo | Guru

>Ho fatto altre prove: la procedura funziona a meraviglia e il
>risultato che voglio appare sullo schermo (nella finestra di
>Query Analyzer per intenderci). Però siccome i risultati non
>rientrano in un recordset LabView non li legge.
Mi sembra di averti detto che l'output generato dalla sp E' UN NORMALISSIMO RESULTSET
Probabilmente quel controllo che utilizzi è "schizzinoso" e non funziona, ma la colpa non è certo di SQL Server

>Come posso modificare
>la procedura per far sì che il risultato finisca in una tabella?
- Definisci una tabella in base all'output generato (CREATE TABLE...)
- Popolala con il comando:

INSERT dbo.Tabella
EXEC dbo.sp

>Perchè facendo così alla fine posso inserire un SELECT * FROM
><tabella> e leggere i dati tramite LabView e Recordset.
Puoi tranquillamente definire un Recordset (ADO) con il result set generato da una sp utilizzando un oggetto ADODB.Command senza la necessità di passare da una tabella temporanea...

Ciao!
--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

MagicBotolo Profilo | Newbie

1) "- Definisci una tabella in base all'output generato (CREATE TABLE...)
- Popolala con il comando:

INSERT dbo.Tabella
EXEC dbo.sp"

Ma devo sapere a priori quante colonne ci saranno nel risultato? Perchè io a priori non so quante colonne avrò alla fine...

2) "Puoi tranquillamente definire un Recordset (ADO) con il result set generato da una sp utilizzando un oggetto ADODB.Command senza la necessità di passare da una tabella temporanea..."

Come faccio? Sto cercando in internet informazioni riguardo il comando "Command" ma non riesco a capire come posso fare. Io alla fine della Store Procedure non ottengo nè un singolo valore (in questo caso potrei usare la funzione Return se non sbaglio) nè una tabella precisa (a meno di poter memorizzare i valori se non c'è il problema del punto 1).

3) "Mi sembra di averti detto che l'output generato dalla sp E' UN NORMALISSIMO RESULTSET
Probabilmente quel controllo che utilizzi è "schizzinoso" e non funziona, ma la colpa non è certo di SQL Server".

LabView mette a disposizione comandi presi dalla libreria ADO sottoforma di blocchi grafici. Per comunicare con un database uso il blocco "Connection", con lo stesso blocco eseguo una query e come risultato ottengo un Recordset (o meglio, LabView si aspetta un recordset). Ecco perchè se non ho un recordset in uscita dalla query non posso leggere i risultati. Sto cercando qualche info in + ...

Intanto grazie 1000 !


Ciao!!

lbenaglia Profilo | Guru

>Ma devo sapere a priori quante colonne ci saranno nel risultato?
>Perchè io a priori non so quante colonne avrò alla fine...
Eh si, il discorso si complica proprio per questo motivo

>2) "Puoi tranquillamente definire un Recordset (ADO) con il result
>set generato da una sp utilizzando un oggetto ADODB.Command senza
>la necessità di passare da una tabella temporanea..."
>
>Come faccio? Sto cercando in internet informazioni riguardo il
>comando "Command" ma non riesco a capire come posso fare.
Non hai mai usato un oggetto ADODB.Command?
Su questo forum e su microsoft.public.it.sql troverai centinaia di esempi...

>alla fine della Store Procedure non ottengo nè un singolo valore
>(in questo caso potrei usare la funzione Return se non sbaglio)
>nè una tabella precisa (a meno di poter memorizzare i valori
>se non c'è il problema del punto 1).
Ancora, il risultato di quella stored procedure è un resultset, ovvero un recordset ADO (non so più come dirtelo ).

>LabView mette a disposizione comandi presi dalla libreria ADO
>sottoforma di blocchi grafici. Per comunicare con un database
>uso il blocco "Connection", con lo stesso blocco eseguo una query
>e come risultato ottengo un Recordset (o meglio, LabView si aspetta
>un recordset). Ecco perchè se non ho un recordset in uscita dalla
>query non posso leggere i risultati. Sto cercando qualche info
>in + ...
Io non conosco quel controllo, ma se accetta recordset ADO non dovresti aver problemi.

>Intanto grazie 1000 !
Prego.

Ciao!
--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

MagicBotolo Profilo | Newbie

Ehm... purtroppo la mia conoscenza di SQL non è enorme... Credevo che i ResultSet fossero diversi dai RecordSet...
Comunque: sto guardando i Command. Se io passo in ingresso all'istruzione Command la query che normalmente uso per richiamare la Stored Procedure dovrei ottenere i risultati voluti, giusto?
Se ho capito bene io apro una connessione; poi passo il nome della connessione all'oggetto Connection o all'oggetto Command ed eseguo la query. Posso poi elaborare i risultati con l'oggetto RecordSet.

Allego un'immagine della programmazione LabView: al momento io sto usando i blocchi Connection e RecordSet. La prova successiva sarà con il blocco Command:


805x352 95Kb


Purtroppo oggi non posso lavorare con SQL Server e queste prove le farò domani ma intanto cerco materiale.
Al solito grazie... prego (questa volta ti batto in velocità... )
Ciao!!

lbenaglia Profilo | Guru

>Ehm... purtroppo la mia conoscenza di SQL non è enorme... Credevo
>che i ResultSet fossero diversi dai RecordSet...
Ah, OK

>Comunque: sto guardando i Command. Se io passo in ingresso all'istruzione
>Command la query che normalmente uso per richiamare la Stored
>Procedure dovrei ottenere i risultati voluti, giusto?
No, devi semplicemente specificare il nome della stored procedure, definirne i parametri di input e richiamare il metodo Execute ottenendo come valore di ritorno un oggetto Rescordset.
A titolo di esempio osserva il seguente codice:
http://tinyurl.com/37z5zt

>Se ho capito bene io apro una connessione; poi passo il nome
>della connessione all'oggetto Connection o all'oggetto Command
>ed eseguo la query. Posso poi elaborare i risultati con l'oggetto
>RecordSet.
Si, passa la stringa connessione all'oggetto Command proprio come nell'esempio che ti ho segnalato.
Una volta che ottieni il recordset assegnalo al tuo controllo.

>Al solito grazie... prego (questa volta ti batto in velocità...
> )


Ciao!
--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

MagicBotolo Profilo | Newbie

Fatto!!
Alla fine era sufficiente passare all'oggetto Connection una stringa con il nome della Store Procedure seguito dai parametri della stessa.
Grazie mille per le risposte!!
Ciao!!

Ps: una cosina ancora aggiunta dopo... è possibile recuperare anche le intestazioni delle colonne create? Quando leggo il ResultSet (o RecordSet che dir si voglia... giusto? ) riesco a leggere i dati ma non le intestazioni delle colonne create con la Store Procedure.
È possibile recuperarle?

Aggiunta: mi rispondo da solo... Ho modificato l'ordine di estrazione dei campi che uso come intestazioni delle colonne create con la Store Procedure per adattare il tutto.

Continuiamo ad aggiungere: adesso sto cercando di modificare la Store Procedure in modo che i dati vengano estratti in base ad un controllo sulla data.
Ho modificato la SP come segue:

GO
IF NOT OBJECT_ID('dbo.sp_CrossTab') IS NULL
DROP PROCEDURE dbo.sp_CrossTab; -- Eliminazione procedura se già esistente

GO
CREATE PROC dbo.sp_CrossTab
@table AS sysname= 'NS_DATI', -- Tabella sulla quale operare la CrossTab
@onrows AS nvarchar(128)= 'DATAORA', -- Campo da inserire nella prima colonna
della tabella finale
@onrowsalias AS sysname = NULL, -- Eventuale alias per la prima colonna
@oncols AS nvarchar(128)= 'ID_MIS', -- Campo da suddividere sulle colonne
della tabella finale
@sumcol AS sysname = 'DATO', -- Campo da inserire come dato nella
tabella finale
@sensore AS varchar(128), -- Identificativo sensore
@inizio AS datetime, -- Inizio intervallo per la query
@fine AS datetime = NULL -- Fine intervallo per la query
AS

DECLARE
@sql AS nvarchar(4000), -- Stringa contenente la query da eseguire
@supporto_sql_1 AS nvarchar(4000), -- Stringa di supporto se la prima stringa è corta
@supporto_sql_2 AS nvarchar(4000), -- Stringa di supporto se la prima stringa è corta
@supporto_sql_3 AS nvarchar(4000), -- Stringa di supporto se la prima stringa è corta
@supporto_sql_4 AS nvarchar(4000), -- Stringa di supporto se la prima stringa è corta
@supporto_sql_5 AS nvarchar(4000), -- Stringa di supporto se la prima stringa è corta
@supporto_sql_6 AS nvarchar(4000), -- Stringa di supporto se la prima stringa è corta
@NEWLINE AS char(1) -- Ritorno a capo (usato solo per leggibilità)

-- Inizializzazione variabili
SET @sql='';
SET @supporto_sql_1='';
SET @supporto_sql_2='';
SET @supporto_sql_3='';
SET @supporto_sql_4='';
SET @supporto_sql_5='';
SET @supporto_sql_6='';
SET @NEWLINE = CHAR(10)

-- Inizio creazione della stringa di query: prima colonna della tabella finale
SET @sql =
'SELECT ' + @onrows +
CASE
WHEN @onrowsalias IS NOT NULL THEN ' AS ' + @onrowsalias
ELSE ''
END

--PRINT ('step 1, @sql: ' + @sql)

-- Estrazione dei valori presenti nel campo da suddividere nelle colonne della tabella finale
CREATE TABLE #keys(keyvalue nvarchar(100) NOT NULL PRIMARY KEY)

DECLARE @keyssql AS varchar(4000)
SET @keyssql =
'INSERT INTO #keys ' +
'SELECT DISTINCT ' + @oncols +
' FROM ' + @table + ' WHERE ID_SENS=' + @sensore + ' AND DATAORA' +
CASE WHEN @fine IS NULL THEN '>' + @inizio
ELSE ' between ' + @inizio + ' and ' + @fine
END;

SET NOCOUNT ON
EXEC (@keyssql)
SET NOCOUNT OFF

--PRINT ('step 2, #keyssql: ' + @keyssql);
--SELECT * FROM #keys;

-- Suddivisione delle colonne della tabella finale con i relativi dati
DECLARE @key AS nvarchar(100)

SELECT @key = MIN(keyvalue) FROM #keys
WHILE @key IS NOT NULL
BEGIN
SET @sql = @sql + ',' + @NEWLINE +
' SUM(CASE CAST(' + @oncols +
' AS nvarchar(100))' + @NEWLINE +
' WHEN N''' + @key +
''' THEN ' + CASE
WHEN @sumcol IS NULL THEN '1'
ELSE @sumcol
END + @NEWLINE +
' ELSE 0' + @NEWLINE +
' END) AS [' + @key + ']'

SELECT @key = MIN(keyvalue) FROM #keys
WHERE keyvalue > @key

IF LEN(@sql)>3900
BEGIN

IF LEN(@supporto_sql_1)=0
SET @supporto_sql_1=@sql
ELSE
IF LEN(@supporto_sql_2)=0
SET @supporto_sql_2=@sql
ELSE
IF LEN(@supporto_sql_3)=0
SET @supporto_sql_3=@sql
ELSE
IF LEN(@supporto_sql_4)=0
SET @supporto_sql_4=@sql
ELSE
IF LEN(@supporto_sql_5)=0
SET @supporto_sql_5=@sql
ELSE
SET @supporto_sql_6=@sql

SET @sql=''
END;

END;

/*PRINT ('step 3, @sql: ' + @sql)
PRINT ('step 3bis, @supporto_sql_1: ' + @supporto_sql_1);
PRINT ('step 3bis, @supporto_sql_2: ' + @supporto_sql_2);
PRINT ('step 3bis, @supporto_sql_3: ' + @supporto_sql_3);
PRINT ('step 3bis, @supporto_sql_4: ' + @supporto_sql_4);
PRINT ('step 3bis, @supporto_sql_5: ' + @supporto_sql_5);
PRINT ('step 3bis, @supporto_sql_6: ' + @supporto_sql_6);*/

-- Esecuzione della stringa di query creata
PRINT ('Query finale: ' + @supporto_sql_1 + @supporto_sql_2 + @supporto_sql_3 + @supporto_sql_4 + @supporto_sql_5 + @supporto_sql_6 + @sql + ' FROM ' + @table
+ ' WHERE ID_SENS=' + @sensore + ' GROUP BY ' + @onrows + ' ORDER BY ' + @onrows)
-- For debug

--EXEC (@supporto_sql_1 + @supporto_sql_2 + @supporto_sql_3 + @supporto_sql_4 + @supporto_sql_5 + @supporto_sql_6 + @sql + ' FROM ' + @table + ' WHERE ID_SENS=' + @sensore + ' GROUP BY ' + @onrows + ' ORDER BY ' + @onrows);

GO

In pratica: ho aggiunto alcune variabili stringa di supporto da utilizzare se la variabile principale (@sql) si riempie (le varie @supporto_sql...) e ho inserito valori di default per la maggior parte delle variabili (l'utente può scegliere il valore da assegnare alla variabile @sensore... gli altri valori sono fissati).
Ma il nuovo pezzo riguarda il controllo delle date.
Ho aggiunto due variabili:
@inizio e @fine entrambe di tipo datetime.
Dal programma esterno mi aspetto di ricevere date del tipo 2006/09/29 10:16:11 .
Poi ho inserito una clausola nella selezione dei campi che costituiranno le colonne finali:
SET @keyssql =
'INSERT INTO #keys ' +
'SELECT DISTINCT ' + @oncols +
' FROM ' + @table + ' WHERE ID_SENS=' + @sensore + ' AND DATAORA' +
CASE WHEN @fine IS NULL THEN '>' + @inizio
ELSE ' between ' + @inizio + ' and ' + @fine
END;

In pratica: ho la possibilità di inserire due date (@inizio e @fine) o solo la data iniziale (@inizio... poi prendo i dati che hanno il campo DATAORA maggiore di @inizio. Per fare questo ho assegnato alla variabile @fine un valore di default pari a NULL [si può fare con le variabili di tipo datetime?] ).
Ho costruito la query in modo dinamico con l'operatore CASE.

L'errore che incontro riguarda la conversione da varchar a datetime per le variabili @inizio e @fine (io passo questi valori alla SP come stringhe... ho provato anche con la funzione CONVERT (cioè passo come valore la funzione CONVERT applicata alla data in formato stringa) ma ottengo un errore (errore di sintassi in prossimità di CONVERT).
Sto continuando a fare prove ma inizio a chiedervi consigli.

Aggiungo un altro pezzettino: io passo alla Store Procedure due date in formato '2006/09/29 13:44:32'. Ho provato a dichiarare le variabili @inizio e @fine come varchar, datetime, timestamp... ho provato a modificare la disposizione dei valori di mese, anno e giorno, ho provato a modificare i caratteri tra le parti della data ( / o - ) e tra le parti dell'ora ( : e . )... ho provato ad usare CAST e CONVERT da varchar verso datetime, da nvarchar verso datetime, da varchar verso timestamp...
In tutti questi casi ottengo sempre un errore di conversione.
Come faccio per trasformare le variabili @inizio e @fine in modo che possano essere usate in un SELECT come date e orario?

Dunque nuovo aggiornamento: ho modificato le date in ingresso. Adesso le variabili @inizio e @fine hanno il seguente formato: '2006/29/09 13:44:32', con anno-giorno-mese.
Strano ma se poi inserisco queste variabili nella query senza CAST o CONVERT la procedura funziona. E se alla fine di tutto stampo la query ottenuta mettendo insieme i vari pezzi ottengo:
SELECT DATAORA ,
SUM(CASE CAST(ID_MIS AS nvarchar(100))
WHEN N'114' THEN DATO
ELSE 0
END) AS [114],
SUM(CASE CAST(ID_MIS AS nvarchar(100))
WHEN N'134' THEN DATO
ELSE 0
END) AS [134],
SUM(CASE CAST(ID_MIS AS nvarchar(100))
WHEN N'154' THEN DATO
ELSE 0
END) AS [154],
SUM(CASE CAST(ID_MIS AS nvarchar(100))
WHEN N'19' THEN DATO
ELSE 0
END) AS [19],
SUM(CASE CAST(ID_MIS AS nvarchar(100))
WHEN N'21' THEN DATO
ELSE 0
END) AS [21],
SUM(CASE CAST(ID_MIS AS nvarchar(100))
WHEN N'39' THEN DATO
ELSE 0
END) AS [39],
SUM(CASE CAST(ID_MIS AS nvarchar(100))
WHEN N'41' THEN DATO
ELSE 0
END) AS [41],
SUM(CASE CAST(ID_MIS AS nvarchar(100))
WHEN N'54' THEN DATO
ELSE 0
END) AS [54],
SUM(CASE CAST(ID_MIS AS nvarchar(100))
WHEN N'61' THEN DATO
ELSE 0
END) AS [61],
SUM(CASE CAST(ID_MIS AS nvarchar(100))
WHEN N'74' THEN DATO
ELSE 0
END) AS [74] FROM NS_DATI WHERE ID_SENS=192 AND DATAORA between '2006/29/09 13:44:32' and '2006/29/09 22:44:38' GROUP BY DATAORA ORDER BY DATAORA

che funziona alla grande .
A questo punto sostituisco l'istruzione PRINT con l'istruzione EXEC e mi salta fuori un errore: "sintassi errata prima di CASE"... ... come mai? EXEC e PRINT sono seguiti dalla stessa identica stringa complessiva.

Sono sicuro che il problema dipenda proprio dall'istruzione CASE: se la tolgo (o la salto considerandola un commento) l'errore sparisce... BOH...

Risolto!! Ho inserito il blocco di istruzioni CASE...END in una stringa:
IF @flag_fine=0
SET @stringa_data = ' between ''' + @inizio + ''' and ''' + @fine + ''''
ELSE SET @stringa_data = '>''' + @inizio + ''''

Grazie per i consigli,
MagicBotolo
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5