it-swarm-eu.dev

Jak zahrnout parametr datetime do uložené procedury spolu s řetězcovým dotazem?

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 ...

5
Harun

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
11
billinkc

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
3
datagod