Moje uložená procedura je následující,
-- 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
Spuštění tohoto řetězcového dotazu má za následek následující chybu,
"Převod selhal při převodu data a/nebo času z řetězce znaků."
Pomozte mi prosím někoho vyřešit ...
Zásadní problém spočívá v tom, že TSQL nemůže implicitně převést datetime (nebo celé číslo nebo plovoucí desetinnou čárku) na charakterové datové typy. Ve skutečnosti jde zpět, pokouší se implicitně převést znaková data na datetime (hodnota int/floating point) na základě pravidel priority datového typu. To je to, co vaše chybová zpráva říká mimochodem, nemohl převést řetězce na hodnoty datetime. Musíte explicitně požádat, aby mash hodnoty do řetězce znaků.
Tento příklad demonstruje princip s celými čísly, protože jsou snáze pochopitelné očekávané hodnoty.
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
Hodnota implicitní konverze ukazuje, že @stringint je nejprve převeden na celé číslo a potom je + považováno za číselné sčítání a výsledkem je 8. Explicitní převod @intint na datový typ znaku má za následek znaménko + považované za zřetězení s vrátil řetězec 35
implicit_conversion explicit_conversion
------------------- -------------------
8 35
Chcete-li vyřešit zadaný problém, musíte explicitně přetypovat hodnoty datetime na typ znaku, aby mohl být řetězec dotazu zřetězen podle očekávání.
set @query='SELECT [col1]
FROM [Table1]
WHERE ([col2] BETWEEN ''' + CONVERT(nvarchar(24), @FromDate, 121) +''' AND'''+ CONVERT(nvarchar(24), @ToDate, 121) +''')'
Ale jak je uvedeno výše, opravdu to nechcete dělat z mnoha důvodů, protože SQL Injection je jedním z nich. To také ztěžuje vaši údržbu, když krájíte a nakrájíte řetězec dotazů v TSQL.
Lepším přístupem je parametrizace dotazu a využití síly sp_executesql . Pěkná věc na parametru sp_executesql je, že nemusíte používat všechny dodané parametry. V závislosti na tom, co se opravdu snažíte, to může být užitečné.
Ukázková tabulka a data
CREATE TABLE
dbo.table1
(col1 int, col2 datetime)
INSERT INTO
dbo.table1
SELECT
3, '2009-04-06'
UNION ALL SELECT
1, '2001-09-11'
Ukázka použití parametrů
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
Výsledek
col1
3
Chcete-li se vyhnout této chybě a zranitelnostem SQL Injection, měli byste přepsat svůj dotaz následujícím způsobem:
@FromDate datetime,
@ToDate datetime
--Select query
SELECT [col1]
FROM [Table1]
WHERE [col2] BETWEEN @FromDate AND @ToDate