在@Joe的答案中VARCHAR(27)
讨论的技术方面和建议的解决方法之外(使用列),我质疑OP所表达的“ 需要创建[a]宽的非规格化表”,除非存在一些奇怪的技术要求,所有这些列必须在单个表中,我建议/建议根据需要将它们分布在尽可能多的“同级”表中。同级表是以下表:
- 彼此一对一的关系
- 都具有完全相同的主键,
- 只有一个
IDENTITY
列(对其他列没有FK)
- 其余的有一个外键(在PK列上),该外键指向具有
IDENTITY
在这里,您将逻辑行拆分为两个或多个物理表。但这本质上就是规范化,以及关系数据库旨在处理的内容。
在这种情况下,由于确实需要将两个INNER JOIN
表放在一起(通常但并非总是如此,除非所有SELECT
查询都使用所有列,但这种情况通常不会发生),因此您确实会因复制PK而占用一些额外的空间,并增加一些查询的复杂性。或创建显式交易处理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的情况下,每页存储更多字段,具体取决于您的值。