it-swarm.com.de

Wie füge ich einen datetime-Parameter zusammen mit einer Zeichenfolgenabfrage in eine gespeicherte Prozedur ein?

Meine gespeicherte Prozedur lautet wie folgt:

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

Das Ausführen dieser Zeichenfolgenabfrage führt zu folgendem Fehler:

"Konvertierung fehlgeschlagen beim Konvertieren von Datum und/oder Uhrzeit aus der Zeichenfolge."

Bitte helfen Sie mir, das zu klären ...

5
Harun

Das grundlegende Problem ist, dass TSQL datetime (oder Integer oder Floating Point) nicht implizit in Zeichendatentypen konvertieren kann. Es geht tatsächlich rückwärts und versucht, die Zeichendaten basierend auf den Prioritätsregeln für Datentypen implizit in die Datumszeit (int/Gleitkommawert) zu konvertieren. Dies ist, was Ihre Fehlermeldung Ihnen übrigens sagt, sie konnte die Zeichenfolgen nicht in datetime-Werte konvertieren. Sie müssen explizit darum bitten, Werte in Zeichenfolgen zu mischen.

Dieses Beispiel zeigt das Prinzip mit Ganzzahlen, da diese die erwarteten Werte leichter verstehen.

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

Der Wert der impliziten Konvertierung zeigt an, dass @stringint zuerst in eine Ganzzahl konvertiert wird und dann das + als numerische Addition behandelt wird und 8 ergibt. Die explizite Konvertierung von @intint in einen Zeichendatentyp führt dazu, dass das + -Zeichen als Verkettung mit dem behandelt wird zurückgegebene Zeichenfolge von 35

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

Um das angegebene Problem zu lösen, müssen Sie Ihre datetime-Werte explizit in einen Zeichentyp umwandeln, damit die Abfragezeichenfolge wie erwartet verkettet werden kann.

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

Aber wie oben erwähnt, möchten Sie dies aus mehreren Gründen wirklich nicht tun, darunter auch SQL Injection. Dies erschwert auch die Wartung erheblich, wenn Sie eine Abfragezeichenfolge in TSQL aufteilen und in Würfel schneiden.

Ein besserer Ansatz besteht darin, Ihre Abfrage zu parametrisieren und die Potenz von sp_executesql zu verwenden. Das Schöne am Parameter sp_executesql ist, dass Sie nicht alle angegebenen Parameter verwenden müssen. Je nachdem, was Sie wirklich versuchen, kann dies von Vorteil sein.

Beispieltabelle und Daten

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 zur Verwendung von Parametern

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

Ergebnisse

col1
3
11
billinkc

Um diesen Fehler und die Schwachstellen von SQL Injection zu vermeiden, sollten Sie Ihre Abfrage wie folgt umschreiben:

@FromDate datetime,
@ToDate datetime

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