Помимо технических аспектов и предлагаемого обходного пути (с использованием VARCHAR(27)
столбцов), обсуждаемых в ответе @ Joe , я подвергаю сомнению « необходимость создания широкой денормализованной таблицы», как это выражено в OP, если не существует какого-то странного технического требования, что все эти столбцы должно быть в одной таблице, я бы посоветовал / рекомендовал распределить их по столько раз, сколько необходимо. Родственные таблицы - это таблицы, которые:
- иметь отношения 1 к 1 друг с другом,
- все имеют один и тот же первичный ключ,
- только один имеет
IDENTITY
колонка (и нет ФК для других)
- остальные имеют внешний ключ (в столбце PK), указывающий на PK таблицы, которая имеет
IDENTITY
Здесь вы разбиваете логическую строку на две или более физических таблицы. Но это по сути то, что нормализация в любом случае, и какие реляционные базы данных предназначены для обработки.
В этом сценарии вам потребуется некоторое дополнительное пространство, используемое при дублировании PK, и некоторая дополнительная сложность запросов из-за необходимости INNER JOIN
объединения таблиц (часто, но не всегда, если все SELECT
запросы не используют все столбцы, но обычно это не происходит) или создать явную транзакцию INSERT
или UPDATE
их вместе (DELETE
может быть обработано с помощьюON DELETE CASCADE
набор на FK).
ОДНАКО вы получаете преимущества от наличия надлежащей модели данных с правильными родными типами данных и без хитрости, которая может привести к непредвиденным последствиям в дальнейшем. Даже если использоватьVARCHAR(27)
позволяет работать на техническом уровне, прагматически я не думаю, что хранение десятичных дробей как строк отвечает интересам вашего проекта.
Итак, если вам «нужна» только одна таблица из-за того, что вы не понимаете, что один логический объект не должен быть физически представлен в одном контейнере, то не пытайтесь заставить все это объединить в одну таблицу, когда она будет работать изящно через несколько столов.
Пример ниже иллюстрирует основную концепцию:
НАСТРОИТЬ
CREATE TABLE tempdb.dbo.T1
(
[ID] INT NOT NULL IDENTITY(11, 2) PRIMARY KEY,
[Col1] VARCHAR(25),
[Col2] DATETIME NOT NULL DEFAULT (GETDATE())
);
CREATE TABLE tempdb.dbo.T2
(
[ID] INT NOT NULL PRIMARY KEY
FOREIGN KEY REFERENCES tempdb.dbo.T1([ID]) ON DELETE CASCADE,
[Col3] UNIQUEIDENTIFIER,
[Col4] BIGINT
);
GO
CREATE PROCEDURE #TestInsert
(
@Val1 VARCHAR(25),
@Val4 BIGINT
)
AS
SET NOCOUNT ON;
BEGIN TRY
BEGIN TRAN;
DECLARE @InsertedID INT;
INSERT INTO tempdb.dbo.T1 ([Col1])
VALUES (@Val1);
SET @InsertedID = SCOPE_IDENTITY();
INSERT INTO tempdb.dbo.T2 ([ID], [Col3], [Col4])
VALUES (@InsertedID, NEWID(), @Val4);
COMMIT TRAN;
END TRY
BEGIN CATCH
IF (@@TRANCOUNT > 0)
BEGIN
ROLLBACK TRAN;
END;
THROW;
END CATCH;
SELECT @InsertedID AS [ID];
GO
ТЕСТОВОЕ ЗАДАНИЕ
EXEC #TestInsert 'aa', 454567678989;
EXEC #TestInsert 'bb', 12312312312234;
SELECT *
FROM tempdb.dbo.T1
INNER JOIN tempdb.dbo.T2
ON T2.[ID] = T1.[ID];
Возвращает:
ID Col1 Col2 ID Col3 Col4
11 aa 2017-07-04 10:39:32.660 11 44465676-E8A1-4F38-B5B8-F50C63A947A4 454567678989
13 bb 2017-07-04 10:41:38.180 13 BFE43379-559F-4DAD-880B-B09D7ECA4914 12312312312234
DECIMAL(26, 8) NULL
полей в таблицу, без сжатия страниц или десятичного сжатия. При включении vardecimal, но не сжатии страниц, накладные расходы превышают 1 K. Существует внешняя вероятность, что вы сможете хранить больше полей на странице без vardecimal, в зависимости от ваших значений.