varchar列的行为类似于char列 - 为什么?

时间:2011-08-03 04:58:21

标签: .net linq-to-sql

我正在开发一个遗留应用程序(我的罪孽!),它始于Visual Basic 2.0(!),并已升级到Visual Basic 6.0,最近升级到.NET。

数据库服务器当前是SQL Server 2000(虽然我已将副本还原到本地SQL Server 2008 R2 Express实例,并且它在SQL Server 2000兼容模式下运行。)

该应用程序使用LINQ-to-SQL从数据库中检索实体。

一个特定的表定义为(为简洁起见,删除了其他列):

CREATE TABLE dbo.Bar_Code (
    Bar_Code varchar(40) NOT NULL,
    CONSTRAINT PK_BAR_CODE PRIMARY KEY CLUSTERED 
    (
         Bar_Code ASC
    )

它关联的LINQ-to-SQL实体被定义为服务器数据类型VarChar(40) NOT NULL


问题

当我在SQL Server Management Studio中执行以下SQL查询时:

SELECT MAX(LEN(Bar_Code))
FROM   dbo.Bar_Code

结果是 13

使用LINQ-to-SQL我得到了一些意想不到的结果:

// get maximum length of all barcodes
var maxLength = dataContext.Bar_Codes.Max(barCode => barCode.Bar_Code.Length);
// maxLength == 13

// get list of all barcodes
var list = dataContext.Bar_Codes.ToList();

var length = list[0].BarCode.Length;  // legnth = 13
var value = list[0].BarCode;          // value = "9316165196376"

var length = list[1].BarCode.Length;  // legnth = 13
var value = list[1].BarCode;          // value = "9316165196371"

var length = list[2].BarCode.Length;  // legnth = 40 <-- WTF?
var value = list[2].BarCode;          // value = "9317585001669                           "

因此,对于表中的某些值,它们表现为“正常” - 即varchar(40)应该如此,但是有些行的数据行为类似于char(40)列 - 例如作为上面的第三行。

我的猜测

在表格的有效期内,Bar_Code的定义已从char(40)更改为随后修改为varchar(40)。这将解释带有空格的某些行值的padidng。

SQL Server的LEN()函数将列视为varchar(40),因为所有行的最大长度为13。

当通过LINQ-to-SQL查找所有条形码的最大长度时,提供程序正在创建类似于上面的SQL查询的查询(这将解释类似的结果)。

由于某些原因,当通过LINQ-to-SQL查询数据时,在某些情况下,这些值被视为char(40) - 可能是在它们最初被定义为这样的时候?

我的问题

有谁知道我为什么会看到这种行为?如果/当列重新定义为char(40)时,为什么SQL Server没有“未填充”varchar(40)值?

为什么SQL Server的LEN()会忽略某些列的填充空格?此行为是否由某些数据库/查询选项控制?

为什么LINQ-to-SQL不遵守列类型和“unpad”值的VarChar(40)定义?

3 个答案:

答案 0 :(得分:1)

这是预期的行为。当表被声明为char(40)时,数据被填充,当它被更改为varchar(40)时,服务器别无选择,只能假设列中的数据有效(即您想要空格) 。看看这个sql代码:

LEN忽略尾随空格http://msdn.microsoft.com/en-us/library/ms190329.aspx

create table test (id int identity(1,1), example char(20));
insert into test (example) values ('1');
alter table test alter column example varchar(20);
insert into test (example) values ('2     ');
insert into test (example) values ('3');
select '[' + example + ']', LEN(example) from test;
drop table test;

结果

[1                   ]  1
[2     ]             1
[3]                   1

如果您不想要空格,请执行修剪尾随空格的更新,或执行rtrim。

答案 1 :(得分:0)

您可能想要检查下方的“空格”是否都是相同的字符。尝试将值转换为可以检查此信息以确定的类型。

我没有使用过SQL Server 2000,但也许CAST(Bar_Code AS binary)可以提供这些信息吗?

SQL Server 2000转换和转换参考: http://msdn.microsoft.com/en-us/library/aa226054(v=sql.80).aspx

答案 2 :(得分:0)

我对LINQ并不熟悉,对不起,但似乎它正在使用=&gt;的某种指针。符号。如果这是真的,它可能是没有正确终止字符串并运行到另一个“内存区域”,直到它遇到一个已知的终结器?我持怀疑态度只是因为如果是这种情况我会期望计数值发生变化,但这是需要考虑的事情。