9

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

有没有一种简单的方法来创建/使用无符号数据类型,或者我必须创建类型->制定规则->使用创建的类型;如以下文章中所述?

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

如果这是在 SQL 中使用 Unsigned 的唯一方法,那么使用它有什么缺点/缺点吗?

4

3 回答 3

11

主要的(也是相当关键的)缺点是,您提供的链接似乎并没有真正做到您认为的那样。

它只是创建一个只能为正数的新整数类型,它不会为您提供任何空间节省,否则会因使用无符号字段而导致(这似乎是您的主要目标)。也就是说,它们的最大值unsignedSmallint与 的最大值相同smallint,因此您仍然会浪费这些额外的位(但更是如此,因为您不能插入负值)。

也就是说,它们unsignedInt不允许超过 2^31-1 的值。

我理解并欣赏在 1 亿行中,在单个列上使用 int32 与 int64 节省的空间约为 380MB。也许你最好的方法是处理这个问题是在你读取它之后偏移你的存储值,理想情况下是在一个视图中并且只从那个视图中读取,然后在执行插入时将 -2^31 添加到值..但问题是 int32 的解析发生在插入之前,因此INSTEAD OF触发器将不起作用..(我不知道有什么方法可以制作一个接受与拥有表不同类型的 INSTEAD OF 触发器)

相反,在这方面您唯一的选择是对set值使用存储过程,然后您可以使用视图或存储过程来取回值:

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来。

于 2011-09-01T09:10:25.503 回答
3

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

CAST(yourSignedSmallInt AS int) & 0xffff

要将有符号整数转换为无符号数字,请尝试

CAST(yourSignedInt AS bigint) & 0xffffffff

例如,如果您的表字段 x 是一个 smallint 并且您想返回该unsigned值,那么请尝试

SELECT (CAST(x AS int) & 0xffff) FROM ... WHERE ....
于 2014-06-11T14:24:43.427 回答
2

适当的解决方案取决于您要解决的问题。如果这是一个身份字段,并且您的目标是将表可以容纳的行数增加一倍,而无需为每行存储 4 个额外字节以使用 bigint,那么只需将该字段设置为 -2,147,483,648 而不是 1。如果您需要存储大于 21.47 亿的值,然后使用更大的数据类型。

于 2013-04-03T19:57:27.370 回答