1

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

4

5 回答 5

3

是列CHAR还是VARCHAR

这可能与ANSI_PADDING创建列时的设置有关。如果ANSI_PADDING设置为,OFFVARCHAR在插入列时会自动修剪列。CHAR当它被定义为允许值时可能会有点棘手NULL,但通常它总是将列填充为列的最大长度。因此,简而言之,您可能需要VARCHAR带有ANSI_PADDINGset的列ON

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

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

此外,这听起来像是个人喜好,但由于我们不再处于列名限制为 8 个字符的时代,您可能希望列名更具描述性,而不是Pfx,Bse等。出来并具有描述性。我发现这使开发和调试变得更加容易。我意识到您正在转换旧系统,因此可能很难(或目前不可能)这样做,但如果可以的话,我强烈建议您这样做。

ANSI_PADDING以下是有关是否需要更多信息的文档链接: https ://docs.microsoft.com/en-us/sql/t-sql/statements/set-ansi-padding-transact-sql

于 2018-03-04T14:58:50.443 回答
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);

是一个说明这一点的 SQL Fiddle。当然,您需要单独删除列上的唯一约束。

于 2018-03-04T14:26:42.877 回答
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
于 2018-03-04T14:14:09.873 回答
0

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

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

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

于 2018-03-04T14:11:07.077 回答
0

Comparison is based on rtrim but they are different

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

You could use this to pad the space with _

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


-----
于 2018-03-04T14:32:30.060 回答