SQL Server 2008 - 无符号整数数据类型

11

我正在使用 SQL SERVER 2008,我的各个表中有许多 INT、SMALLINT 字段, 我知道它们都将是0或大于0的,即可以将它们视为无符号。

是否有一种简单的方法来创建/使用无符号数据类型,或者我是否需要按照以下文章中指定的方式创建类型->制定规则->使用已创建的类型呢?

http://www.julian-kuiters.id.au/article.php/sqlserver2005-unsigned-integer

如果这是在SQL中使用Unsigned的唯一方法,那么使用它是否有任何缺点/不利之处?


1
如果您的原因只是想确保该值大于等于零,则可以在列上使用简单的“CHECK”约束。 - Chris Diver
1
通过使用Unsigned,我们可以更好地利用内存/存储。这并不是为了确保值大于0或者不是这个原因,而纯粹是为了节省内存。 - user899055
2
看起来你正在尝试优化一些不应该优化的东西。让数据库管理系统自己管理内存,它非常擅长这个。 - Oded
我的表中将有成千上万行数据,其中一个列的值将在50000-60000范围内,使用无符号小整数是否是个好主意呢?此外,我还有另一种情况,可以使用无符号整数代替大整数。 - user899055
2
只需使用“整数”并添加“CHECK”约束或触发器来检查值。 - Oded
你链接的文章使用了已经被弃用的 rules。现在你也可以创建CLR UDTs。 - Martin Smith
3个回答

11
主要(而且相当关键)的缺点是你提供的链接似乎并不能做你想做的事情。它只是创建了一个新的整数类型,只能为正数,不提供使用无符号字段所带来的任何节省空间的好处(这似乎是你的主要目标)。也就是说,他们的unsignedSmallint的最大值与smallint的最大值相同,因此你仍然会浪费那些额外的位(但更多的是因为你不能插入负值)。
换句话说,他们的unsignedInt将不允许超过2^31-1的值。
我理解并欣赏,使用int32与int64在单个列上处理100百万行的存储值的节省约为380MB。也许你最好的方法是,在读取存储的值后,在视图内进行偏移,并且始终只从该视图中读取,在进行插入操作时,将该值添加-2^31。但问题在于,在插入之前会发生int32的解析,因此INSTEAD OF触发器将不起作用。(我不知道有没有办法使接受与拥有表不同类型的INSTEAD OF触发器)
因此,在这方面,你的唯一选择是使用存储过程来设置该值,然后可以使用视图或存储过程来获取该值:
create table foo
(fooA int)
GO

CREATE VIEW [bar]
AS
SELECT CAST(fooA AS BIGINT) + 2147483647 AS fooA
FROM foo
GO

CREATE PROCEDURE set_foo
    @fooA bigint
AS
BEGIN
    SET NOCOUNT ON;

    -- Insert statements for procedure here
    IF @fooA < 4294967296 AND @fooA >= 0
        INSERT INTO foo VALUES (@fooA - 2147483647)
    --ELSE
        -- throw some message here
END
GO

可以使用以下方式进行测试:

exec set_foo 123
exec set_foo 555
select * FROM bar
select * FROM foo
exec set_foo 0
exec set_foo 2147483648
exec set_foo 4147483648
select * FROM bar
select * FROM foo

你会看到返回的值是无符号的,然而返回的值是int64而不是unsigned32,所以你的应用程序需要将它们视为仍然是int64。

如果你有一个情况,在这种情况下从中获得了显着的提升(例如表中几乎每一列都比本来需要的大小大两倍),那么上述努力可能是值得的,否则我建议仍然使用bigint


3

如果要将有符号的smallint转换为无符号数字,请尝试以下操作:

CAST(yourSignedSmallInt AS int) & 0xffff

将有符号整数转换为无符号数字,请尝试使用以下方法:

CAST(yourSignedInt AS bigint) & 0xffffffff

例如,如果您的表字段x是smallint类型,并且希望返回无符号值,则可以尝试使用以下代码:
SELECT (CAST(x AS int) & 0xffff) FROM ... WHERE ....

3

适当的解决方案取决于你要解决的问题。如果这是一个身份字段,并且你的目标是为了将表格可以容纳的行数翻倍,而不需要在每一行中存储4个额外的字节来使用bigint,则只需将该字段种子值设置为-2,147,483,648而不是1。如果需要存储大于21.47亿的值,则选择更大的数据类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接