2016-06-24 6 views
0

Ich habe eine C# -Konsolenanwendung, die Berichte aus einer SQL Server-Datenbank generiert. Alle meine Berichte basieren auf gespeicherten Prozeduren und mein App-Code ruft die gespeicherten Prozeduren auf die gleiche Weise auf.Gespeicherte Prozedur, die nicht die gleichen Ergebnisse liefert wie die SQL-Zeichenfolge

Ich bin auf ein Problem gestoßen, bei dem eine gespeicherte Prozedur in meiner App nicht so funktioniert, wie es erwartet wird, obwohl die gespeicherte Prozedur erwartungsgemäß funktioniert, wenn sie von SQL Server Management Studio ausgeführt wird.

Ich bin am Ende meines Wissens versucht, dieses Problem zu lösen. Ich habe es so viele verschiedene Arten seziert, wie ich kann, hatte ein paar zusätzliche Augenpaare diesen Code untersuchen, und trotzdem kann ich das nicht zur Arbeit bringen.

// code in my app 
public DataTable DeviceAuthorizationAffectedDeviceGroup(string affectedDeviceGroupNameArray, DateTime startDate, int deviceId) { 
    dt = new DataTable(); 
    DataTable dt2 = new DataTable(); 

    string sql = "SELECT StartTime EventTime, EventText, UserName AS Username, AffectedDeviceGroupName"; 
    sql += " FROM eventlog"; 
    sql += " WHERE AffectedDeviceGroupName IN (SELECT LTRIM(RTRIM(Item)) FROM dbo.SplitString('" + affectedDeviceGroupNameArray + "', ','))"; 
    sql += " AND StartTime >= '" + startDate + "'"; 
    sql += " AND (DeviceID = " + deviceId + ")"; 
    sql += " ORDER BY StartTime"; 

    using (var cn = new SqlConnection(this.ConnectionString)) { 
     using (var cmd = new SqlCommand(sql, cn)) { 
      using (var da = new SqlDataAdapter(cmd)) { 
       cmd.CommandType = CommandType.Text; 

       Debug.WriteLine(MyDamnClass.CommandAsSql(cmd)); 
       da.Fill(dt); //SQL string, data table contains 6 rows 
      } 
     } 

     using (var cmd = new SqlCommand("usp_REPORTS_SubReport_GetDeviceAuthorizationAffectedDeviceGroup_TEST", cn)) { 
      using (var da = new SqlDataAdapter(cmd)) { 
       cmd.CommandType = CommandType.StoredProcedure; 
       cmd.Parameters.Add("@AffectedDeviceGroupNameArray", SqlDbType.VarChar).Value = affectedDeviceGroupNameArray; 
       cmd.Parameters.Add("@StartTime", SqlDbType.DateTime).Value = startDate; 
       cmd.Parameters.Add("@DeviceID", SqlDbType.Int).Value = deviceId; 

       Debug.WriteLine(MyDamnClass.CommandAsSql(cmd)); 
       da.Fill(dt2); //stored proc, data table contains 0 rows 
      } 
     } 
    } 

    return dt; 
} // breakpoint here to examine the contents of each data table 

Stored Procedure auf dem Server:

CREATE PROCEDURE [dbo].[usp_REPORTS_SubReport_GetDeviceAuthorizationAffectedDeviceGroup_TEST] 
    (@AffectedDeviceGroupNameArray varchar(MAX), 
     @StartTime datetime, @DeviceID int) 
AS 
    SELECT 
     StartTime EventTime, 
     EventText, 
     UserName AS Username, 
     AffectedDeviceGroupName 
    FROM 
     eventlog 
    WHERE 
     AffectedDeviceGroupName IN (SELECT LTRIM(RTRIM(Item)) 
            FROM dbo.SplitString(@AffectedDeviceGroupNameArray, ',')) 
     AND StartTime >= @StartTime 
     AND (DeviceID = @DeviceID) 
    ORDER BY 
     StartTime 

SQL-Code aus meiner Anwendung ausgeführt wird (mit @ Flapper Code von this question)

use MyDatabase; 
SELECT 
    StartTime EventTime, EventText, UserName AS Username, 
    AffectedDeviceGroupName 
FROM 
    eventlog 
WHERE 
    AffectedDeviceGroupName IN (SELECT LTRIM(RTRIM(Item)) 
           FROM dbo.SplitString('(Unassigned)', ',')) 
    AND StartTime >= '10/12/2015 2:46:51 PM' 
    AND (DeviceID = 281) 
ORDER BY 
    StartTime 

use MyDatabase; 
declare @return_value int; 
exec [usp_REPORTS_SubReport_GetDeviceAuthorizationAffectedDeviceGroup_TEST] 
    @AffectedDeviceGroupNameArray = '(Unassigned)' 
    , @StartTime = '10/12/2015 2:46:51 PM' 
    , @DeviceID = 281 
; 
select 'Return Value' = convert(varchar, @return_value); 

Was bin ich nicht zu sehen? Was bewirkt, dass die gespeicherte Prozedur keine Zeilen zurückgibt, wenn die identisch aufgebaute SQL-Zeichenfolge das zurückgibt, was ich erwartet habe? Ich bin mir sicher, dass es etwas Kleines ist und eines dieser "Oh!" Momente, sobald es darauf hingewiesen wird.

+1

Sie sollten wirklich eine parametrisierte Abfrage verwenden. String-Kontaktierung ist nicht zuverlässig, wechsle deine Textversion, um Parameter zu verwenden und zu sehen, ob sie es behebt. –

+3

Ich frage mich, ob in Ihrem C# -Code die DateTime in eine Zeichenfolge (wegen der Verkettung) gezwungen wird, während wenn Sie die gespeicherte Prozedur aufrufen, wird es als DateTime übergeben (über den Parameter.) – Duston

+0

Sie sollten auch das Datum verwenden format 'yyyy-mm-ddThh: mi: ss' mit String-Literalen, andere Formate sind sprach-/einstellungsspezifisch. Nicht sicher, ob das der Grund ist oder nicht. –

Antwort

1

Ein Unterschied zwischen der SELECT-Anweisung, die Sie durch Verketten von Zeichenfolgen und der Ausführung der gespeicherten Prozedur erstellt haben, ist der Datentyp Ihrer Parameter, die Sie vergleichen. Abhängig vom Datentyp Ihrer Tabellenfelder können sich dadurch die Ergebnisse zwischen den Methoden ändern. Insbesondere erhalten Sie andere Ergebnisse, wenn das Feld StartTime in Ihrer Tabelle eventlog Varchar anstelle von Datetime ist.

in Ihrer SELECT-Abfrage Sie vergleichen die Starttime-Feld zu einem Stringliteral:

StartTime >= '" + startDate + "'"; 

Wenn StartTime ein varchar-Typ ist, das in einem String-Vergleich statt eines Datumsvergleich führen würde, was nicht sein würde, was du beabsichtigt hast. Es würde Daten alphabetisch sortieren, also wäre beispielsweise '10/12/2015 2:46:51 PM 'größer als '01/12/2016 2:46:51 PM', weil es mit einer 1 beginnt und das andere mit einem 0.

Wenn Sie jedoch das Feld StartTime mit dem Parameter in der gespeicherten Prozedur vergleichen, werden die Daten als datetime verglichen. Aufgrund der Priorität des Datentyps wird versucht, das Tabellenfeld implizit in einen Datetime-Datentyp zu konvertieren und die beiden dann als Daten zu vergleichen.

Wenn Sie tun eine explizite Umwandlung in Datetime entweder der Starttime Feld oder der String-Parameter Sie sollten die gleichen Ergebnisse mit beiden Methoden erhalten:

convert(datetime, StartTime) >= '" + startDate + "'"; 
Verwandte Themen