在 SQLServer 数据库中使用单行配置表。不好吗?

在开发购物车应用程序时,我发现需要根据管理员的偏好和要求保存设置和配置。这些信息可以是来自公司信息、发货帐户 ID、 PayPal API 密钥、通知首选项等的任何信息。

在关系数据库系统中创建一个表来存储单行似乎非常不合适。

存储这些信息的适当方式是什么?

注意: 我的 DBMS 是 SQL Server 2008,编程层是用 ASP.NET (C #)实现的。

48670 次浏览

我不确定单行是配置的最佳实现。每个形态项目有一行两列(configName,configValue)可能更好,尽管这需要将所有值强制转换为字符串并返回。

无论如何,对全局配置使用单一行没有坏处。将其存储在 DB (全局变量)中的其他选项更糟糕。您可以通过插入第一个配置行来控制它,然后禁用表上的插入以防止出现多行。

您应该创建一个包含信息类型和信息值(至少)的列的表。这样就避免了每次添加新信息时都必须创建新列。

就个人而言,我会把它存储在一个单一的行,如果这是什么工作。将它存储在 SQL 表中是否过度了?也许吧,但这样做并没有真正的害处。

一种常见的方法是使“ properties”表类似于属性文件。在这里,你可以存储所有的应用程序常量,或者不那么常量的东西,你只需要有左右。

然后,您可以根据需要从这个表中获取信息。同样,当您发现需要保存其他设置时,可以将其添加到。这里有一个例子:

Property _ entry _ table

[id, scope, refId, propertyName, propertyValue, propertyType]
1, 0, 1, "COMPANY_INFO", "Acme Tools", "ADMIN"
2, 0, 1, "SHIPPING_ID", "12333484", "ADMIN"
3, 0, 1, "PAYPAL_KEY", "2143123412341", "ADMIN"
4, 0, 1, "PAYPAL_KEY", "123412341234123", "ADMIN"
5, 0, 1, "NOTIF_PREF", "ON", "ADMIN"
6, 0, 2, "NOTIF_PREF", "OFF", "ADMIN"

这样你就可以存储你所拥有的数据,以及你明年将会拥有但还不知道的数据:)。

在这个例子中,作用域和 refId 可以用于后端的任何需要。因此,如果 PropertyType“ ADMIN”的作用域为0 refId 2,那么您就知道它的首选项是什么。

当有一天,您需要在这里存储非管理信息时,属性类型就会出现。

注意,不应该以这种方式存储购物车数据,也不应该进行查找。但是,如果数据是特定于 系统的,那么您当然可以使用这种方法。

例如: 如果你想存储你的 数据库版本,你应该使用这样一个表。这样,当您需要升级应用程序时,您可以检查属性表,以查看客户端的软件版本。

关键是您不希望将其用于与购物车相关的事情。将业务逻辑保存在定义良好的关系表中。Properties 表仅供系统信息使用。

正如您所猜测的,除了最简单的情况之外,将所有配置参数放在一行中有许多缺点。这是个坏主意。

存储配置和/或用户首选项类型信息的一种方便方法是使用 XML 。许多 DBMS 支持 XML 数据类型。XML 语法允许您随着配置的发展扩展描述配置的“语言”和结构。XML 的一个优点是它对层次结构的隐式支持,例如允许存储小的配置参数列表,而不必使用编号后缀来命名这些参数。XML 格式的一个可能的缺点是,搜索和通常修改这些数据并不像其他方法那样直接(没有什么复杂的,但不是那么简单/自然)

如果您希望保持更接近于 的关系模型,那么可能需要的就是 < strong > 实体-属性-价值模型 ,通过它,各个值存储在一个表中,这个表通常看起来像:

EntityId     (foreign key to the "owner" of this attribute)
AttributeId  (foreign key to the "metadata" table where the attribute is defined)
StringValue  (it is often convenient to have different columns of different types
IntValue      allowing to store the various attributes in a format that befits
them)

其中 AttributeId 是一个表的外键,其中定义了每个可能的 Attribute (在您的例子中是“配置参数”) ,比如

AttributeId  (Primary Key)
Name
AttributeType     (some code  S = string, I = Int etc.)
Required          (some boolean indicating that this is required)
Some_other_fields   (for example to define in which order these attributes get displayed etc...)

最后,EntityId 允许您识别“拥有”这些不同属性的某个实体。在您的情况下,如果您只需要管理一个配置,那么它可以是 UserId,甚至可以是隐式的。

除了允许可能的配置参数列表随着应用程序的发展而增长之外,EAV 模型还将“元数据”(meta data) ,即属于 Attribute 本身的数据放在数据表中,从而避免了配置参数存储在单行中时常见的列名硬编码。

单行可以很好地工作,甚至可以使用强类型:

show_borders    bit
admin_name      varchar(50)
max_users       int

一个缺点是它需要一个模式更改(alter table)来添加一个新设置。一种替代方法是正常化,最终得到的表是这样的:

pref_name       varchar(50) primary key
pref_value      varchar(50)

它有弱类型(所有类型都是 varchar) ,但是添加一个新设置只是添加一行,您只需要使用数据库写访问就可以做到这一点。

我过去用过两种方法——一个行表和一个键/值对表——每种方法都有正面和负面的影响。

单行

  • 正值: 值存储在正确的类型中
  • 正面: 在代码中更容易处理(由于上述原因)
  • 正值: 默认值可以分别给予每个设置
  • 否定: 添加新设置需要更改架构
  • 否定: 如果有很多设置,表可以变得非常宽

键/值对

  • 正面: 添加新设置不需要更改架构
  • 正面: 表模式很窄,新设置使用了额外的行
  • 否定: 每个设置都有相同的默认值(空/空?)
  • 否定: 所有内容都必须存储为字符串(即 nvarchar)
  • 否定: 在处理代码中的设置时,必须知道设置的类型并进行强制转换

到目前为止,单行选项是最容易使用的选项。这是因为您可以在数据库中以正确的类型存储每个设置,而不必在代码中存储设置的类型及其查找键。

我使用这种方法关心的一件事是在“特殊”单行设置表中有多行。我通过(在 SQLServer 中)克服了这个问题:

  • 添加默认值为0的新位列
  • 创建检查约束以确保该列的值为0
  • 在位列上创建唯一约束

这意味着表中只能存在一行,因为位列的值必须为0,但是由于惟一约束,只能有一行具有该值。

在规范化方法中添加新的配置参数时,当然不必更改模式,但是仍然可能需要更改代码来处理新值。

在部署中添加一个“ alter table”似乎并不是对单行方法的简单性和类型安全性的很大折衷。

Key 和 Value 对类似于可以存储配置设置的.NetApp.Config。

因此,当你想要检索值时,你可以这样做:

SELECT value FROM configurationTable
WHERE ApplicationGroup = 'myappgroup'
AND keyDescription = 'myKey';

您可以在不进行转换的情况下进行键/值对,方法是为每个主要类型添加一列,并且添加一列告诉您数据位于哪一列中。

所以你的桌子看起来应该是这样的:

id, column_num, property_name, intValue, floatValue, charValue, dateValue
1, 1, weeks, 51, , ,
2, 2, pi, , 3.14159, ,
3, 4, FiscYearEnd, , , , 1/31/2015
4, 3, CompanyName, , , ACME,

它使用更多的空间,但最多只是使用几十个属性。您可以使用 column _ num 值之外的 case 语句来拉取/连接右边的字段。

对不起,我几年后才来。但不管怎样,我做的是简单有效的。我只是创建了一个包含三个()列的表:

ID-int (11)

Name-varchar (64)

值-文本

在创建、更新或读取新的配置列之前,我要做的是序列化“值”!这样我就可以确定类型(好吧,php 是:)

例如:

B: 0; 表示 BOOLEAN (错误)

B: 1; 表示 BOLEAN (真实)

I: 1988; 代表 NT

S: 5: “ Kader”; 表示5个字符长度的 是的TRING

我希望这有所帮助:)

键列为 varchar,值列为 JSON。1是数字,而 "1"是字符串。truefalse都是布尔型的。你也可以有对象。