2012-07-11 60 views
0

我有一個SQLCLR程序集,它使用條形碼掃描程序創建Telnet接口,並將收到的任何東西放置在表中。偶爾,它崩潰,出現錯誤:「子查詢返回多個值」在SQLCLR程序集上

 
Executed as user: NT AUTHORITY\SYSTEM. 
A .NET Framework error occurred during execution of user-defined routine 
or aggregate "fnBarcodeScanner": 

System.Data.SqlClient.SqlException: Subquery returned more than 1 value. 
This is not permitted when the subquery follows =, !=, , >= or 
when the subquery is used as an expression. 

System.Data.SqlClient.SqlException:  
    at System.Data.SqlClient.SqlConnection.OnError(
     SqlException exception, Boolean breakConnection)  
    at System.Data.SqlClient.SqlInternalConnection.OnError(
     SqlException exception, Boolean breakConnection)  
    at System.Data.SqlClient.SqlInternalConnectionSmi.EventSink.DispatchMessages(
     Boolean ignoreNonFatalMessages)  
    at Microsoft.SqlServer.Server.SmiEventSink_Default.DispatchMessages(
     Boolean ignoreNonFatalMessages)  
    at System.Data.SqlClient.SqlCommand.RunExecuteNonQuerySmi(
     Boolean sendToPipe)  
    at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(
     DbAsyncResult result, String methodName, Boolean sendToPipe)  
    at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()  
    at MinimalisticTelnet.Program.Connect(String ip) . 

[SQLSTATE 42000] (Error 6522) The statement has been terminated. 
[SQLSTATE 01000] (Error 3621). The step failed. 

我明白了什麼錯誤意思,但我不知道它是如何在這種情況下所引起。程序集中唯一的SQL是一個插入語句,它在表中插入一個字符串。應該沒有辦法擁有多個價值。下面是用於組件的C#代碼(包括爲簡潔起見省略了):

namespace MinimalisticTelnet 
{ 
    public class Program 
    { 
     [Microsoft.SqlServer.Server.SqlProcedure] 
     public static void Main(string[] args) 
     { 
     } 

     public static void Connect(String ip) 
     { 
      String lastCode = null; 
      TelnetConnection tc = new TelnetConnection(ip, 23); 

      using (SqlConnection conn = new SqlConnection("context connection=true")) 
      { 
       SqlCommand InsertID = new SqlCommand(); 
       InsertID.Connection = conn; 
       SqlParameter IDCodeParam = new SqlParameter("@Barcode", SqlDbType.VarChar); 
       conn.Open(); 
       while (tc.IsConnected) 
       { 
        String barcode = tc.Read(); 
        if (!((barcode).Length == 0)) 
        { 
         barcode = barcode.Substring(0,barcode.IndexOf("\n") - 1); 
         if (!(barcode == lastCode)) 
         { 
          lastCode = barcode; 
          SqlString sqlBarcode = barcode; 
          IDCodeParam.Value = sqlBarcode; 
          InsertID.Parameters.Add(IDCodeParam); 
          InsertID.CommandText = "INSERT INTO dbo.tbl_Barcode (Barcode)" + 
           " Values(@Barcode)"; 
          InsertID.ExecuteNonQuery(); 
          InsertID.Parameters.Clear(); 
         } 
        } 
       } 
       conn.Close(); 
      } 
     } 
    } 
} 

這裏是fnBarcodeScanner的代碼:

CREATE PROCEDURE [dbo].[fnBarcodeScanner] 
     @ip [nvarchar](20) 
    WITH EXECUTE AS CALLER 
    AS 
    EXTERNAL NAME [Telnet].[MinimalisticTelnet.Program].[Connect] 
    GO 

在這裏被觸發:

ALTER TRIGGER [dbo].[trg_Barcode] 
ON [dbo].[tbl_Barcode] 
AFTER INSERT 
AS 
    BEGIN 
     DECLARE @MVID  INT, 
       @P   VARCHAR(25), 
       @NewLane  VARCHAR(10), 
       @TC   INT, 
       @DID   INT, 
       @AD   DATE, 
       @AT   VARCHAR(18), 
       @TrayCount INT, 
       @DivertCount INT, 
       @ScanID  VARCHAR(50), 
       @PID   INT, 
       @cDivert  VARCHAR(8) 

     SET @ScanID = (SELECT Barcode 
        FROM tbl_Barcode)--Barcode Value 
     SET @MVID = (SELECT MVID 
        FROM tbl_Divert 
        WHERE Barcode = @ScanID)--JOT Version ID 
     SET @P = (SELECT PalletNbr 
       FROM tbl_Divert 
       WHERE Barcode = @ScanID)--Pallet Number 
     SET @PID = (SELECT PalletID 
        FROM tbl_Pallet_Verification 
         INNER JOIN tbl_Pallet_Mailing 
          ON tbl_Pallet_Verification.MailingID = tbl_Pallet_Mailing.MailingID 
        WHERE tbl_Pallet_Mailing.MVID = @MVID 
         AND tbl_Pallet_Verification.PalletNum = @P)--PAT Pallet ID 
     SET @AD = (Cast(CONVERT(VARCHAR(10), Getdate(), 110) AS DATE))--Today's Date 
     SET @AT = CONVERT(TIME, Getdate())--Current Time 
     SET @cDivert = (SELECT Divert 
         FROM tbl_Divert 
         WHERE Barcode = @ScanID) 
     SET @NewLane = (SELECT TOP 1 ID 
         FROM tbl_Tray_Lanes 
         WHERE LaneActive = -1 
          AND ID NOT IN(SELECT Divert 
              FROM tbl_Pallet_Lanes 
              WHERE DateCompleted IS NULL))--Find Open Lane 
     SET @TC = (SELECT Count(TrackerID) 
       FROM tbl_Divert 
       WHERE MVID = @MVID 
         AND PalletNbr = @P)--Tray Count 
     SET @TrayCount = (SELECT Count(TrackerID) 
         FROM tbl_Divert 
         WHERE Barcode = @ScanID)--Is Tray Found in Divert Table 
     SET @DivertCount = (SELECT Count(TrackerID) 
          FROM tbl_Divert 
          WHERE Barcode = @ScanID 
           AND Divert IS NOT NULL)--Verify Tray has not been scanned 

     --Add Date/Time to Tray Record. This will mark tray as scanned 
     SELECT TrackerID 
     FROM tbl_Divert 
     WHERE Barcode = @ScanID 
      AND Divert IS NULL 

     IF @@ROWCOUNT > 0 
     BEGIN 
      SET NOCOUNT ON; 

      IF @NewLane IS NOT NULL 
       BEGIN --Add Available lane to Lane Table and give tray record the LaneID 
        IF @TrayCount > 0 --Verify tray record exist 
        BEGIN 
         --IF @DivertCount = 0 --If not previously scanned 
         --Begin--Insert Lane Record 
         INSERT INTO tbl_Pallet_Lanes 
            (MVID, 
            PalletID, 
            PalletNbr, 
            Divert, 
            TrayCount, 
            DateStarted, 
            TimeStarted) 
         SELECT @MVID, 
           @PID, 
           @P, 
           @NewLane, 
           @TC, 
           @AD, 
           @AT 

         --Get LaneID 
         SET @DID = (SELECT ID 
            FROM tbl_Pallet_Lanes 
            WHERE MVID = @MVID 
              AND PalletNBR = @P) 

         --Add LaneID to tray record 
         UPDATE tbl_Divert 
         SET Divert = @NewLane, 
           DivertID = @DID 
         WHERE MVID = @MVID 
           AND PalletNbr = @P 
        --END 
        END 
       END 

      IF @NewLane IS NULL 
       BEGIN --If there is no open lane assign Lane 16. This will send the tray to end of tray tracker for 
        --manual pallet load. 
        UPDATE tbl_Divert 
        SET Divert = 16, 
         DivertID = 0 
        WHERE MVID = @MVID 
         AND Barcode = @ScanID 
       END 
     END 

     DELETE FROM tbl_Barcode --Clear barcode table 

     UPDATE tbl_Divert 
     SET Scanned = @AD, 
      ScanStatus = 1 --Scan Status Flags which Reader 
     WHERE Barcode = @ScanID 
    END 

由於尋求幫助。

+1

你對'tbl_Barcode'有觸發器嗎?它的設計目的是一次只處理一行? – HABO 2012-07-11 17:19:33

+1

只是爲了清理:你還應該在SqlCommand上有一個USING子句;你可以擺脫conn.Close()調用。 SqlConnection上的使用將爲您做到這一點。 – NotMe 2012-07-11 17:20:20

+1

任何引用完整性查詢是否會自動執行,可能導致此問題?您是否嘗試過使用查詢分析器查看SQL跟蹤?有時會執行比您預期更多的查詢。 – 2012-07-11 17:21:55

回答

0

您的代碼正在拋出異常。這導致SQL Server認爲你正從函數返回多個值。

您可能想要確切知道將什麼值傳遞給插入語句(如完整列表中所示)。我很想知道你是否有任何關鍵的碰撞問題。

你用來插入不像前一個條形碼的行看起來像你試圖避免這樣的事情。

+0

是的,我明白錯誤,我試圖弄清楚我的代碼如何導致這個錯誤。 – SaintWacko 2012-07-11 17:45:56

+0

@SaintWacko:我認爲你是誤解。代碼拋出* an *異常;然而,它正在投擲的那個正在被你所看到的那個壓倒。 – NotMe 2012-07-11 19:10:14

+0

哦,對不起,我明白你在說什麼。我有什麼方法可以找出真正的例外是什麼? – SaintWacko 2012-07-11 19:11:46