SQL SERVER –关系数据库中的枚举


关系数据库中的枚举 这是关系数据库中非常基础的一门学科,但是却常常没有被很好地理解,有时实现得很差。当然,有很多方法可以做到这一点,但我只集中讨论两种情况,一种是“正确的方法”,而另一种肯定是错误的方法。

这个概念 假设我们的数据库中有表Person。人物具有属性/字段,例如名字,姓氏,生日等等。然后是一个字段,告知人的婚姻状况,让我们以相同的方式命名。婚姻状况。

现在,MaritalStatus是一个枚举。在C#中,我肯定会使用诸如Single,InRelationship,Married,Divorced之类的值进行枚举。现在出现了问题,SQL没有枚举。

错误的方法 我认为,这绝对是错误的方法。它有一个优势。当您执行简单的SELECT查询时,您将立即看到枚举的描述,而不必处理神秘的值。缺点也很多,其中之一就是数据库碎片。

考虑一下(我故意将所有索引和约束都排除在查询之外)。

CREATE TABLE [dbo].[Person] (
[Firstname] NVARCHAR(100),
[Lastname] NVARCHAR(100),
[Birthday] datetime,
[MaritalStatus] NVARCHAR(10)
)

您在表中有nvarchar(20)字段,用于告知婚姻状况。显而易见的问题是,如果创建的新值不适合20个字符,该怎么办?您必须要来改变桌子。还有其他问题,但我留给读者考虑。

正确的方法 这是我在许多项目中完成此操作的方式。该模型仍然存在一个问题,但是可以根据需要在应用程序层或使用CHECK约束进行缓解。

首先,我将创建一个命名空间表,该表告诉枚举的名称。我也将添加一行。我也将在这里编写所有索引和约束。

CREATE TABLE [CodeNamespace] (
[Id] INT IDENTITY(1, 1),
[Name] NVARCHAR(100) NOT NULL,
CONSTRAINT [PK_CodeNamespace] PRIMARY KEY ([Id]),
CONSTRAINT [IXQ_CodeNamespace_Name] UNIQUE NONCLUSTERED ([Name])
)
GO

INSERT INTO [CodeNamespace] SELECT 'MaritalStatus'
GO

然后,我创建一个表,其中包含实际值以及对命名空间表的引用,以便将值分组到不同的命名空间下。我也会在这里添加几行。

CREATE TABLE [CodeValue] (
[CodeNamespaceId] INT NOT NULL,
[Value] INT NOT NULL,
[Description] NVARCHAR(100) NOT NULL,
[OrderBy] INT,
CONSTRAINT [PK_CodeValue] PRIMARY KEY CLUSTERED ([CodeNamespaceId], [Value]),
CONSTRAINT [FK_CodeValue_CodeNamespace] FOREIGN KEY ([CodeNamespaceId]) REFERENCES [CodeNamespace] ([Id])
)
GO
-- 1 is the 'MaritalStatus' namespace
INSERT INTO [CodeValue] SELECT 1, 1, 'Single', 1
INSERT INTO [CodeValue] SELECT 1, 2, 'In relationship', 2
INSERT INTO [CodeValue] SELECT 1, 3, 'Married', 3
INSERT INTO [CodeValue] SELECT 1, 4, 'Divorced', 4
GO

现在,在CodeValue表中有四列。CodeNamespaceId告知名称空间值属于哪个名称。值告诉在Person表中使用的枚举值(我将在下面显示如何完成此操作)。说明说明该值的含义。您可以使用此列,例如,UI组合框中的列。OrderBy指示在UI中显示值时是否需要以某种方式对值进行排序。

这又是带有正确列的Person表。我将在此处添加一行以显示枚举的使用方式。

CREATE TABLE [dbo].[Person] (
[Firstname] NVARCHAR(100),
[Lastname] NVARCHAR(100),
[Birthday] datetime,
[MaritalStatus] INT
)
GO
INSERT INTO [Person] SELECT 'Marko', 'Parkkola', '1977-03-04', 3
GO

现在我刚才说过,这有一个问题。MaritalStatus列与CodeValue表没有任何数据库强制关系,因此您可以在此字段中输入您喜欢的任何值。我已经在应用程序层中解决了这个问题,方法是从CodeValue表中选择所有值,然后将它们放入组合框/下拉列表中(“值”字段为值,“描述”为文本),以便最终用户不能输入任何非法值。当然,我还将在数据访问层中检查输入的值。

我在“错误的方式”部分中说过,这样做有一个好处。实际上,使用简单的视图即可在这里获得相同的好处,该视图已绑定了架构,因此您可以根据需要对其进行索引。

CREATE VIEW [dbo].[Person_v] WITH SCHEMABINDING
AS
SELECT p.[Firstname], p.[Lastname], p.[BirthDay], c.[Description] MaritalStatus
FROM [dbo].[Person] p
JOIN [dbo].[CodeValue] c ON p.[MaritalStatus] = c.[Value] JOIN [dbo].[CodeNamespace] n ON n.[Id] = c.[CodeNamespaceId] AND n.[Name] = 'MaritalStatus'
GO
-- Select from View
SELECT *
FROM [dbo].[Person_v] GO

enum1.jpg


原文链接:https://codingdict.com/