为什么SQL Server在插入之前应用RTRIM?
我有一个在Pfx、Bse和Sfx列上具有唯一键的表。 在插入数据时,在我看来,SQLServer似乎在内部应用RTRIM,并导致我的Sfx列出现问题,该列在第二行中有一个空格。是否有可能防止这种RTRIM或我遗漏了什么为什么SQL Server在插入之前应用RTRIM?,sql,sql-server,unique-key,character-trimming,Sql,Sql Server,Unique Key,Character Trimming,我有一个在Pfx、Bse和Sfx列上具有唯一键的表。 在插入数据时,在我看来,SQLServer似乎在内部应用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 F
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';
错误消息似乎没有修剪数据并保留空间
违反唯一密钥约束“NNMP0672”。重复键值是2R83、6477、AA您的表定义是什么?什么数据类型 使用NVARCHAR数据类型可能更适合您
请参阅,因为它解释了为什么VARCHAR类型使用ANSI标准并忽略这些数据类型末尾的空白您的表定义是什么?什么数据类型 使用NVARCHAR数据类型可能更适合您 请参阅,因为它解释了为什么VARCHAR类型使用ANSI标准并忽略这些数据类型末尾的空格,请参见此链接: 它说,为了比较两个不同长度的字符串,较短的字符串用空格填充,因此第一行中的“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
在此链接中:
它说,为了比较两个不同长度的字符串,较短的字符串用空格填充,因此第一行中的“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
我真的不推荐我将要提出的建议。但是,您可以通过使用显式的唯一索引和计算列来实现所需的功能 请注意,字符串末尾的空格通常被忽略。这被认为是一件好事,因为我们没有看到他们。你看到的往往是你得到的,这是一个合理的方法。例如,对于LEN和比较,字符串末尾的空格将被忽略 但是,您仍然可以通过追加字符和减法来计算长度。因此,以下内容将允许在结尾处使用空格作为单独的不同值:
alter table t add s_len as (len(s + 'x') - 1);
create unique index t_s_slen on t(s, s_len);
是一个SQL提琴,它在实际中说明了这一点。当然,您需要仅删除列上的唯一约束。我真的不推荐我将要提出的建议。但是,您可以通过使用显式的唯一索引和计算列来实现所需的功能 请注意,字符串末尾的空格通常被忽略。这被认为是一件好事,因为我们没有看到他们。你看到的往往是你得到的,这是一个合理的方法。例如,对于LEN和比较,字符串末尾的空格将被忽略 但是,您仍然可以通过追加字符和减法来计算长度。因此,以下内容将允许在结尾处使用空格作为单独的不同值:
alter table t add s_len as (len(s + 'x') - 1);
create unique index t_s_slen on t(s, s_len);
是一个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
-----
比较基于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
-----
列是CHAR还是VARCHAR
这可能与创建列时的ANSI_填充设置有关。如果ANSI_PADDING设置为OFF,则在插入到列中时会自动修剪VARCHAR列。当CHAR被定义为允许空值时,它可能有点棘手,但通常它总是将列填充为列的最大长度。因此,简而言之,您可能需要启用ANSI_填充的VARCHAR列
请记住,ANSI设置在创建列时适用,因此必须删除并重新创建表或至少是列才能完成此操作
不过,正如其他人所说,依靠隐藏字符或空白字符来区分表中的键通常是一个非常糟糕的主意。在这里,导入失败的事实可能意味着除了尾随空格之间存在差异之外,还有其他原因-可能这是源系统中的错误数据,在导入时应予以更正,以便从一开始就不会出现问题。治疗问题,而不是症状
此外,这听起来可能是个人偏好,但由于我们不再是列名限制为8个字符的时代,您可能希望列名更具描述性,而不是Pfx、Bse等。请拼出单词并进行描述性。我发现这使得开发和调试更加容易。我意识到您正在转换一个遗留系统,所以现在可能很难或不可能这样做,但如果您可以,我强烈建议您这样做
如果您想了解更多信息,这里有一个指向ANSI_PADDING文档的链接:列是CHAR还是VARCHAR
这可能与当时的ANSI_填充设置有关
创建列的时间。如果ANSI_PADDING设置为OFF,则在插入到列中时会自动修剪VARCHAR列。当CHAR被定义为允许空值时,它可能有点棘手,但通常它总是将列填充为列的最大长度。因此,简而言之,您可能需要启用ANSI_填充的VARCHAR列
请记住,ANSI设置在创建列时适用,因此必须删除并重新创建表或至少是列才能完成此操作
不过,正如其他人所说,依靠隐藏字符或空白字符来区分表中的键通常是一个非常糟糕的主意。在这里,导入失败的事实可能意味着除了尾随空格之间存在差异之外,还有其他原因-可能这是源系统中的错误数据,在导入时应予以更正,以便从一开始就不会出现问题。治疗问题,而不是症状
此外,这听起来可能是个人偏好,但由于我们不再是列名限制为8个字符的时代,您可能希望列名更具描述性,而不是Pfx、Bse等。请拼出单词并进行描述性。我发现这使得开发和调试更加容易。我意识到您正在转换一个遗留系统,所以现在可能很难或不可能这样做,但如果您可以,我强烈建议您这样做
如果您想了解更多信息,这里有一个指向ANSI_PADDING文档的链接:您真的需要能够将'AA'和'AA'存储为不同的值吗?我觉得这不是个好主意。即使你能说服数据库允许它。这可能会在将来导致非常令人沮丧的维护问题。好问题。我正在将数据从旧版oracle DB迁移到sql server。还有其他类似description的专栏,让我觉得应该加载这些数据。希望这是有意义的。@rsreji,SQL Server在比较字符串值时会忽略尾随空格,这样无论是否存储尾随空格,都会出现重复的键冲突。@rsreji如果我遇到这个问题,我会非常怀疑原始记录(带尾随空格)输入不正确。您可以尝试完全按照最初存储的方式加载它,但它可能真正需要的是对数据进行重复解析。是的,我将尝试看看是否可以处理数据。谢谢。您真的需要能够将“AA”和“AA”存储为不同的值吗?我觉得这不是个好主意。即使你能说服数据库允许它。这可能会在将来导致非常令人沮丧的维护问题。好问题。我正在将数据从旧版oracle DB迁移到sql server。还有其他类似description的专栏,让我觉得应该加载这些数据。希望这是有意义的。@rsreji,SQL Server在比较字符串值时会忽略尾随空格,这样无论是否存储尾随空格,都会出现重复的键冲突。@rsreji如果我遇到这个问题,我会非常怀疑原始记录(带尾随空格)输入不正确。您可以尝试完全按照最初存储的方式加载它,但它可能真正需要的是对数据进行重复解析。是的,我将尝试看看是否可以处理数据。谢谢。数据类型=varchar。nvarchar不会加倍使用我的磁盘吗?此表包含大约10 mil行。对于char/varchar数据类型,不一定是double,但接近double。如果你有整数和小数,那么它们不会受到影响。增加数据库的大小是另一个问题:Data type=varchar。nvarchar不会加倍使用我的磁盘吗?此表包含大约10 mil行。对于char/varchar数据类型,不一定是double,但接近double。如果你有整数和小数,那么它们不会受到影响。增加数据库的大小是另一个问题:这是不正确的,值将存储在额外的空间中,请使用DATA_LENGTH查看此操作。@MJH您是正确的。在删除之前,让我考虑一个解决方案。这是不正确的,值将存储在额外的空间中,请使用DATA_LENGTH查看此操作。@MJH您是正确的。在删除.Varchar数据类型之前,让我考虑一个解决方案。感谢您提供有关填充设置的信息,我们将与我们的数据建模师一起对此进行检查。我确实花了时间来缩小这个问题的范围。关于列名,我在提交问题之前缩短了它们。@rsreji右填充是SQL更不直观的特征之一。ANSI SQL 92要求在比较之前将字符串填充到相同的长度。即使保留了尾随空格,abc和abc仍然被视为相等的ARCHAR数据类型。感谢您提供有关填充设置的信息,我们将与我们的数据建模师一起对此进行检查。
我确实花了时间来缩小这个问题的范围。关于列名,我在提交问题之前缩短了它们。@rsreji右填充是SQL更不直观的特征之一。ANSI SQL 92要求在比较之前将字符串填充到相同的长度。即使保留了尾随空格,abc和abc仍然被视为相等