2014-09-12 63 views
2

我有這個疑問:當沒有INSERT語句時,爲什麼會出現「字符串或二進制數據會被截斷錯誤」?

USE [SomeDatabase]; 
GO 

DECLARE @percentageValue decimal(15,4) = 1.50; 

SELECT a.ID, a.Amount, a.Status 
FROM [dbo].ATable as a   
INNER JOIN [dbo].BTable as b 
    ON a.LinkToB = b.ID 
INNER JOIN [OtherDatabase].[dbo].CTable as value 
    ON value.[Key] = CONCAT(N'APrefixAboutThisLongThatsNecessaryBecauseDontAsk',b.AltID) 
WHERE a.Status = N'SomeStatus' 
AND a.Amount > (COALESCE(TRY_CONVERT(DECIMAL(15,2), value.Value), 0)*@percentageValue); 
GO 

(節錄保密的實際列名)

而且我得到了傳統: 「消息8152,級別16,狀態10,第3行 字符串或二進制數據將被截斷。「 錯誤。 Google告訴我,我正在嘗試將某些東西插入太小的列中,這很有道理。

然而,這不是一個INSERT操作(這實際上是我的查詢的所有SQL),所以我不能爲我的生活檢測截斷髮生在哪裏或爲什麼。我認爲這是Transact-SQL的問題,但最奇怪的問題是,儘管出現錯誤,我仍然從查詢中獲得結果。

根據要求,這裏是表格模式的相關部分。

USE [SomeDatabase] 

CREATE TABLE [dbo].[ATable](
    [ID] [uniqueidentifier] NOT NULL, 
    [Amount] [decimal](15, 2) NOT NULL, 
    [Status] [nvarchar](32) NOT NULL, 
    [LinkToB] [uniqueidentifier] NOT NULL, 
CONSTRAINT [PK_TableA] PRIMARY KEY CLUSTERED 
(
    [ID] ASC 
)) 
GO 

CREATE TABLE [dbo].[BTable](
    [ID] [uniqueidentifier] NOT NULL, 
    [AltID] [uniqueidentifier] NOT NULL 
CONSTRAINT [PK_TableA] PRIMARY KEY CLUSTERED 
(
    [ID] ASC 
)) 
GO 

USE [OtherDatabase] 
GO 

CREATE TABLE [dbo].[CTable](
    [ID] [uniqueidentifier] NOT NULL, 
    [Key] [nvarchar](100) NOT NULL, 
    [Value] [nvarchar](max) NOT NULL) 
CONSTRAINT [PK_TableC] PRIMARY KEY CLUSTERED 
(
    [ID] ASC 
) 
+1

'Key'列的大小是多少? – Deepshikha 2014-09-12 17:16:19

+0

你可以試着發佈** BTable **和** CTable **的模式嗎? – 2014-09-12 17:21:32

+0

也deworde你有一個表的別名「t」,t.Status和t.Amount的引用,但沒有定義t別名。不是問題的一部分,而是令人困惑。 – Dbloch 2014-09-12 17:57:30

回答

6

好,這個事實證明,一旦你知道的祕密是有趣的,但顯而易見的。

正如評論(和架構)中所述,value.Value是一個nvarchar(max)。這是傳統的鍵值反模式來存儲您不想存儲在特定位置的數據。現在,我們在此列運行try_convert(爲nvarchar(MAX)),但是這很好,因爲

ON Key = N'SomethingSpecific' 

條款將意味着它只能運行在try_convert重點= N'SomethingSpecific」行,對不對?

對不對?

沒有。

根據表中的數據,執行計劃可以選擇try_convert列中的每個值。並且nvarchar(max)中的一行超出了try_convert參數的容量。因此,崩潰。這也解釋了爲什麼我得到所有我期待的結果,它正在評估這些結果,然後在我預期忽略的數據行上發生崩潰。

更好的是,不相關的數據或結構變化可以改變執行計劃的行爲,所以這個錯誤可以非常容易地消失,給出更多/更少的數據,對結構進行較小的更改以及一次調試過程,我很確定空格

那麼最簡單的解決方案是什麼?將配置值單獨分配給變量try_convert,然後使用它。

而且任何人設計數據庫或寫入數據庫代碼:

  • 不會操作SQL中的數據類型WHERE子句
  • 不要使用一個列來存儲很大的不同的數據類型和編寫複雜的轉換例程處理問題
  • 確實使用了正確的數據類型爲您的數據和治療額外的表用正確的數據類型爲好
  • 記住,SQL函數經常做引擎蓋
  • 下插入式操作
+0

我喜歡你的經驗教訓部分。 – HLGEM 2014-09-15 14:13:47

+0

@HLGEM在我的防守中,我繼承了一到三個。四對我來說雖然。 – deworde 2014-09-15 14:17:33

0

的笑容讓這個嘗試

USE [SomeDatabase]; 
GO 

DECLARE @percentageValue decimal(15,4) = 1.50; 
DECLARE @prefix nvarchar(max) = N'APrefixAboutThisLongThatsNecessaryBecauseDontAsk'; 

SELECT a.ID, a.Amount, a.Status 
FROM [dbo].ATable as a   
INNER JOIN [dbo].BTable as b 
    ON a.LinkToB = b.ID 
INNER JOIN [OtherDatabase].[dbo].CTable as value 
    ON value.[Key] = CONCAT(@prefix,b.AltID) 
WHERE a.Status = @status 
AND a.Amount > (COALESCE(TRY_CONVERT(DECIMAL(15,2), value.Value), 0)*@percentageValue); 
GO 
+0

不錯的主意,但事實證明並非如此。 – deworde 2014-09-15 07:42:16

相關問題