it-swarm.it

Come includere un parametro datetime in una procedura memorizzata insieme alla query stringa?

La mia procedura memorizzata è la seguente,

    -- Add the parameters for the stored procedure here 
   @FromDate datetime,
   @ToDate datetime

       --Select query
      DECLARE @query nvarchar(max)

      set @query='SELECT [col1] 
                  FROM [Table1]              
                  WHERE ([col2] BETWEEN '''[email protected]+''' AND'''[email protected]+''')'

       execute sp_executesql @query

L'esecuzione di questa query stringa provoca il seguente errore,

"Conversione non riuscita durante la conversione di data e/o ora dalla stringa di caratteri."

Qualcuno per favore aiutami a risolvere questo ...

5
Harun

Il problema fondamentale è che TSQL non può convertire implicitamente il datetime (o intero o in virgola mobile) in tipi di dati di carattere. In realtà va indietro, tenta di convertire implicitamente i dati dei caratteri in datetime (valore int/valore in virgola mobile) in base alle regole di precedenza del tipo di dati. Questo è ciò che ti dice il tuo messaggio di errore, non è stato possibile convertire le stringhe in valori datetime. Devi esplicitamente chiedergli di mescolare i valori in stringhe di caratteri.

Questo esempio mostra il principale con numeri interi in quanto sono più facili da comprendere i valori previsti.

DECLARE 
    @stringInt nvarchar(3)
,   @intint int

SELECT
    @stringInt = N'3'
,   @intint = 5

SELECT 
    @stringInt + @intint AS implicit_conversion
,   @stringInt + CAST(@intint AS nvarchar(5)) AS explicit_conversion

Il valore della conversione implicita mostra che @stringint viene prima convertito in numero intero e poi + viene trattato come aggiunta numerica e risulta in 8. La conversione esplicita di @intint in un tipo di dati carattere determina il segno + trattato come concatenazione con il valore stringa restituita di 35

implicit_conversion explicit_conversion
------------------- -------------------
8                   35

Per risolvere il problema fornito, è necessario eseguire il cast esplicito dei valori datetime su un tipo di carattere in modo che la stringa di query possa essere concatenata come previsto.

set @query='SELECT [col1] 
FROM [Table1]              
WHERE ([col2] BETWEEN ''' + CONVERT(nvarchar(24), @FromDate, 121) +''' AND'''+ CONVERT(nvarchar(24), @ToDate, 121) +''')'

Ma come indicato sopra, non vuoi davvero farlo per una serie di motivi, SQL Injection è uno di questi. Inoltre, rende la manutenzione molto più difficile quando si taglia e si taglia a dadini una stringa di query in TSQL.

Un approccio migliore è parametrizzare la query e utilizzare la potenza di sp_executesql . Un aspetto positivo del parametro sp_executesql è che non è necessario utilizzare tutti i parametri forniti. A seconda di ciò che stai veramente cercando di fare, questo può essere utile.

Tabella di esempio e dati

CREATE TABLE 
dbo.table1
(col1 int, col2 datetime)

INSERT INTO
    dbo.table1
SELECT
3, '2009-04-06'
UNION ALL SELECT
1, '2001-09-11'

Demo sull'uso dei parametri

DECLARE
    @FromDate datetime,
    @ToDate datetime

SELECT    
    @FromDate = '2005-03-17'
,   @ToDate = current_timestamp

DECLARE
    @query nvarchar(max)
SET @query = N'    
SELECT [col1] 
FROM [Table1]              
WHERE ([col2] BETWEEN @start AND @end)'

-- gratuitous use of parameter assignment here
-- could just as easily used @FromDate and @ToDate
-- in the @query and the parameter list
EXECUTE sp_executesql 
    @query
,   N'@start datetime, @end datetime'
,   @start = @FromDate
,   @end = @ToDate

Risultati

col1
3
11
billinkc

Per evitare questo errore e le vulnerabilità di SQL Injection, è necessario riscrivere la query come segue:

@FromDate datetime,
@ToDate datetime

--Select query
 SELECT [col1] 
   FROM [Table1]              
  WHERE [col2] BETWEEN @FromDate AND @ToDate
3
datagod