为什么SQL Server在插入之前应用RTRIM?

问题描述 投票:1回答:5

我在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)

sql sql-server unique-key character-trimming
5个回答
3
投票

CHARVARCHAR

这可能与列创建时ANSI_PADDING设置有关。如果ANSI_PADDING设置为OFF,则插入列时会自动修剪VARCHAR列。当定义允许CHAR值时,NULL可能会有点棘手,但通常它总是将列填充为列的最大长度。所以,简而言之,你可能想要VARCHAR列与ANSI_PADDING设置ON

请记住,在创建列时会应用ANSI设置,因此您必须删除并重新创建表或至少使用列来完成此操作。

正如其他人所说,依靠隐藏或空白字符来区分表中的键通常是一个非常糟糕的主意。导入失败的事实可能意味着除了尾随空格之间存在差异之外的其他事情 - 可能这是源系统中的错误数据,当您导入它时应该纠正这些数据,这样您就不会遇到问题。第一名。对待问题,而不是症状;)

此外,这可能听起来像个人偏好,但由于我们不再在列名限制为8个字符的日子里,您可能希望对列名更具描述性,而不是PfxBse等。拼写单词并具有描述性。我发现这使得开发和调试变得更加容易。我意识到你正在转换一个遗留系统,所以也许很难(或者目前不可能)这样做,但如果可以,那么我会强烈建议它。

如果您需要更多信息,请参阅ANSI_PADDING文档的链接:https://docs.microsoft.com/en-us/sql/t-sql/statements/set-ansi-padding-transact-sql


1
投票

在此链接中:

https://support.microsoft.com/en-gb/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

1
投票

我真的不建议我提出的建议。但是,您可以使用显式的unique索引和计算列来完成您想要的任务。

请注意,字符串末尾的空格通常会被忽略。这被认为是一件好事,因为我们没有看到它们。 WYSIWYG(你看到的是你得到的)通常是一种合理的方法。例如,LEN()以及比较时,字符串末尾的空格将被忽略。

但是,你仍然可以通过附加一个字符并减去来计算长度。因此,以下内容将允许您将最后的空格计为单独的不同值:

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

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

Here是一个SQL小提琴,它说明了这一点。当然,您需要单独删除列上的唯一约束。


0
投票

你的表定义是什么? (即什么数据类型)

它可能更适合您使用NVARCHAR数据类型

请参阅here,因为它解释了为什么VARCHAR类型使用ANSI标准并忽略这些数据类型末尾的空白


0
投票

比较基于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


-----
© www.soinside.com 2019 - 2024. All rights reserved.