SQL Server 2008-целочисленные типы данных без знака

Я использую SQL SERVER 2008, у меня есть несколько полей INT, SMALLINT в моих различных таблицах, и я знаю, что все они будут 0 или больше 0, т. е. я могу взять их без знака.

есть ли простой способ создания / использования неподписанных типов данных или мне нужно будет создать тип - >сделать правило - >использовать созданный тип; как указано в следующей статье?

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

Если это единственный способ использовать Unsigned в SQL, есть ли какой-либо недостаток/недостаток его использования?

3 ответов


основным (и довольно критическим) недостатком является то, что кажется, что ссылка, которую вы предоставляете, на самом деле не делает то, что вы думаете.

он просто делает новый целочисленный тип, который может быть только положительным, он не дает вам экономии места, которая в противном случае была бы результатом использования поля без знака (что, похоже, является вашей главной целью). то есть, что максимальное значение их unsignedSmallint будет такой же, как максимальное значение для smallint, поэтому вы все еще были бы тратить эти дополнительные биты (но тем более, что вы не можете вставлять отрицательные значения).

то есть, что их unsignedInt не допускает значений выше 2^31-1.

Я понимаю и ценю, что в 100 миллионов строк экономия от использования int32 vs int64 на одном столбце составляет около 380 МБ. Возможно, лучший способ для вас сделать это-обработать это, чтобы компенсировать сохраненное значение после его чтения, в идеале в пределах представления и только когда-либо читать из этого представления, а затем при выполнении вставка добавить -2^31 к значению.. Но проблема в том, что синтаксический анализ для int32 происходит до вставки so INSTEAD OF триггеры не работают.. (Я не знаю, как сделать вместо триггера, который принимает разные типы к таблице владельцев)

вместо этого ваш единственный вариант в этом отношении-использовать хранимые процедуры для set значение, вы можете использовать представление или сохраненный proc, чтобы вернуть значение:

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 вместо.


чтобы преобразовать подписанный smallint в беззнаковое число, попробуйте следующее:

CAST(yourSignedSmallInt AS int) & 0xffff

чтобы преобразовать signed int в беззнаковое число, попробуйте

CAST(yourSignedInt AS bigint) & 0xffffffff

например, если поле таблицы x является smallint и вы хотите вернуть unsigned значение затем попробовать

SELECT (CAST(x AS int) & 0xffff) FROM ... WHERE ....

соответствующее решение зависит от проблемы, которую вы пытаетесь решить. Если это поле идентификатора, и ваша цель состоит в том, чтобы удвоить количество строк, которые может содержать таблица, не сохраняя 4 дополнительных байта с каждой строкой для использования bigint, а затем просто засеять поле в -2,147,483,648, а не 1. Если вам нужно хранить значения больше 2,147 миллиарда, перейдите к большему типу данных.