我在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
可能会有点棘手,但通常它总是将列填充为列的最大长度。所以,简而言之,你可能想要VARCHAR
列与ANSI_PADDING
设置ON
。
请记住,在创建列时会应用ANSI设置,因此您必须删除并重新创建表或至少使用列来完成此操作。
正如其他人所说,依靠隐藏或空白字符来区分表中的键通常是一个非常糟糕的主意。导入失败的事实可能意味着除了尾随空格之间存在差异之外的其他事情 - 可能这是源系统中的错误数据,当您导入它时应该纠正这些数据,这样您就不会遇到问题。第一名。对待问题,而不是症状;)
此外,这可能听起来像个人偏好,但由于我们不再在列名限制为8个字符的日子里,您可能希望对列名更具描述性,而不是Pfx
,Bse
等。拼写单词并具有描述性。我发现这使得开发和调试变得更加容易。我意识到你正在转换一个遗留系统,所以也许很难(或者目前不可能)这样做,但如果可以,那么我会强烈建议它。
如果您需要更多信息,请参阅ANSI_PADDING
文档的链接:https://docs.microsoft.com/en-us/sql/t-sql/statements/set-ansi-padding-transact-sql
在此链接中:
它说为了比较两个不同长度的字符串,较短的字符串用空格填充,因此第一行中的'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
索引和计算列来完成您想要的任务。
请注意,字符串末尾的空格通常会被忽略。这被认为是一件好事,因为我们没有看到它们。 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小提琴,它说明了这一点。当然,您需要单独删除列上的唯一约束。
比较基于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
-----