簡體   English   中英

為什么SQL Server在插入之前應用RTRIM?

[英]Why does SQL Server apply RTRIM before Insert?

我在Pfx,Bse和Sfx列上有一個帶有唯一鍵的表。 在插入數據時,在我看來SQL Server在內部應用RTRIM並導致我的Sfx列出現問題,該列在第二行中有空格。 是否可以防止此RTRIM或我缺少什么?

INSERT INTO Part (Seq, Pfx, Bse, Sfx, Stat, Desc, Cr_date, Cr_User)
SELECT 1 SEQ, '2R83' AS PFX, '6477' BSE, 'AA' SFX, 1 STAT, 'SPLIT MASS FLYWHEEL' DESCR, GETDATE() CR_DT, 'USERID' CR_US 
UNION ALL
SELECT 2, '2R83', '6477', 'AA ', 1, 'SPLIT MASS FLYWHEEL', GETDATE(), 'USERID';

錯誤消息似乎並沒有修剪數據並保留了空間。

違反UNIQUE KEY約束'NNMP0672'。 重復的鍵值為(2R83,6477,AA)

CHAR還是VARCHAR列?

這可能與創建列時的ANSI_PADDING設置有關。 如果將ANSI_PADDING設置為OFF則將VARCHAR列插入列時會自動對其進行修剪。 CHAR定義為允許NULL值時,可能會有些棘手,但總的來說,它總是將列填充為該列的最大長度。 因此,簡而言之,您可能希望將ANSI_PADDING設置為ON VARCHAR列。

請記住,ANSI設置在創建列時適用,因此您必須刪除並重新創建表或至少創建列才能完成此操作。

就像其他人所說的那樣,通常依靠隱藏字符或空格字符來區分表中的鍵是一個非常糟糕的主意。 此處導入失敗的事實可能意味着其他原因,除了尾隨空格存在差異之外-也許這是源系統中的錯誤數據,在導入時應予以糾正,這樣您就不會再遇到問題了。第一名。 治療問題,而不是症狀;)

同樣,這聽起來像是個人喜好,但由於我們不再需要將列名限制為8個字符,所以您可能希望對列名進行更多描述,而不是PfxBse等。拼出單詞並進行描述。 我發現這使開發和調試更加容易。 我意識到您正在轉換舊系統,因此可能很難(或目前無法執行),但是如果可以的話,我強烈建議您這樣做。

如果需要更多信息,這是指向ANSI_PADDING文檔的鏈接: https : //docs.microsoft.com/zh-cn/sql/t-sql/statements/set-ansi-padding-transact-sql

在此鏈接中:

https://support.microsoft.com/zh-CN/help/316626/inf-how-sql-server-compares-strings-with-trailing-spaces

它說,為了比較兩個不同長度的字符串,較短的字符串用空格填充,因此,第一行中的“ AA”變為“ AA”以進行比較。

例:

create table dbo.Strings (
    ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
    S_VC VARCHAR(100) NULL
)

insert strings (S_VC)
values  ('Robert '),
        ('Robert')

select  ID, S_VC, datalength(S_VC) Data_Len, len(S_VC) [Len]
from    strings

select  *
from    strings s1 inner join strings s2
        on s1.S_VC = s2.S_VC

我真的不建議我要提出的建議。 但是,您可以通過使用顯式unique索引和計算列來完成所需的操作。

請注意,通常會忽略字符串末尾的空格。 這被認為是一件好事,因為我們看不到它們。 所見即所得所見即所得 )通常是一種合理的方法。 例如,對於LEN()以及比較而言,將忽略字符串末尾的空格。

但是,您仍然可以通過添加字符並減去來計算長度。 因此,以下內容將使您可以在結尾計數處留出空格作為單獨的不同值:

alter table t add s_len as (len(s + 'x') - 1);

create unique index t_s_slen on t(s, s_len);

是一個SQL Fiddle,它說明了這一點。 當然,您需要僅刪除列上的唯一約束。

您的表定義是什么? (即什么數據類型)

使用NVARCHAR數據類型可能更適合您

參見此處 ,因為它解釋了為什么VARCHAR類型使用ANSI標准並忽略這些數據類型末尾的空白

比較基於rtrim,但它們有所不同

declare @tV table (name varchar(10) primary key);
insert into @tV values ('bob'), ('alice'), ('ted'), ('al '), (' al');
select *, len(name) as ln, DATALENGTH(name) as dl
from @tV;

    name       ln          dl
---------- ----------- -----------
 al        3           3
al         2           3
alice      5           5
bob        3           3
ted        3           3

您可以使用_來填充空格

set nocount on;
declare @al1 varchar(10) = 'al';
declare @al2 varchar(10) = 'al ';
select @al1, len(@al1), DATALENGTH(@al1), left((rtrim(@al1) + '____'), DATALENGTH(@al1))
     , @al2, len(@al2), DATALENGTH(@al2), left((rtrim(@al2) + '____'), DATALENGTH(@al2));
select 'equal' where  @al1 = @al2;
select 'not equal' where  @al1 <> @al2;
select 'equal' where  @al1 = @al2;
select 'equal' where  left((rtrim(@al1) + '____'), DATALENGTH(@al1)) = left((rtrim(@al2) + '____'), DATALENGTH(@al2));

---------- ----------- ----------- -------------- ---------- ----------- ----------- --------------
al         2           2           al             al         2           3           al_


-----
equal


---------


-----
equal


-----

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM