Sql server 在设计数据库时,存储多个真/假值的首选方法是什么?
如标题中所述,在设计数据库时,处理具有多列且仅将真/假值存储为单个或值(例如“Y/N:或“0/1”)的表的首选方法是什么?同样,不同数据库(例如Oracle和SQL Server)之间是否会出现一些问题这可能会影响列的处理方式?位列通常用于表示T/F或Y/N类型的值,至少在SQL Server中是这样。尽管数据库纯粹主义者可能会告诉您,位列在数据库中没有位置,因为它们“太接近硬件”“-Joe Celko。使用对您正在使用的特定数据库引擎有意义的任何东西。需要处理它的是数据库的接口。如果数据库的代码端接口已充分模块化,则只需简单的一行更改即可处理底层数据库中的不同布尔类型。在Sql server 在设计数据库时,存储多个真/假值的首选方法是什么?,sql-server,oracle,database-design,query-optimization,Sql Server,Oracle,Database Design,Query Optimization,如标题中所述,在设计数据库时,处理具有多列且仅将真/假值存储为单个或值(例如“Y/N:或“0/1”)的表的首选方法是什么?同样,不同数据库(例如Oracle和SQL Server)之间是否会出现一些问题这可能会影响列的处理方式?位列通常用于表示T/F或Y/N类型的值,至少在SQL Server中是这样。尽管数据库纯粹主义者可能会告诉您,位列在数据库中没有位置,因为它们“太接近硬件”“-Joe Celko。使用对您正在使用的特定数据库引擎有意义的任何东西。需要处理它的是数据库的接口。如果数据库的代
SQL Server
中,有位
数据类型。您可以在那里存储0或1,比较值,但不运行MIN
或MAX
在Oracle
中,只需使用NUMBER
或CHAR(1)
在MySQL
和PostgreSQL
中,任何数据类型都可以隐式转换为BOOLEAN
这两个系统都支持布尔
数据类型,您可以在WHERE
或ON
子句中按原样使用该数据类型,而不使用运算符:
SELECT *
FROM mytable
WHERE col1
,这在SQL Server
和Oracle
中是不可能的(您需要有某种类型或谓词)
在MySQL
中,BOOLEAN
是TINYINT(1)
的同义词
在
PostgreSQL
中(就存储而言),但从逻辑上讲,它不能隐式转换为任何其他类型。根据我自己的经验,我更喜欢用char(1)表示“Y”或“N”。使用0和1可能有点混淆,这取决于我喝了多少啤酒,C++主()函数在成功时返回0。枚举和位类型的麻烦比它们的价值还多
值得注意的是,MySQLinformation\u schema
使用VARCHAR(3)表示“是”或“否”
例如:
information_schema.USER_PRIVILEGES (
...
IS_GRANTABLE VARCHAR(3) NOT NULL DEFAULT ''
)
代替布尔型数据类型,您可能需要考虑另一种存储布尔值的数据模型,这在以下情况下特别适用:
- 当您将有许多“是/否”列时
- 将来可能需要添加更多“是/否”列时
- 当是/否值不经常更改时李>
Table "Users": (user_id, name, surname, country)
Table "Permissions": (permission_id, permission_text)
Table "Users_Permissions": (user_id, permission_id)
在权限
表中,您将定义所有可能适用于用户的权限。您必须为每个yes/no属性向Permissions
表中添加一行。正如您可能已经注意到的,这使得将来添加新权限非常容易,而无需修改数据库模式
在上述模型中,您可以通过在Users\u Permissions
表中为user\u id
分配Permissions\u id
来指示真实值。否则,默认情况下它将为FALSE
例如:
Table "Permissions"
permission_id text
-----------------------------------
1 "Read Questions"
2 "Answer Questions"
3 "Edit Questions"
4 "Close Questions"
Table "Users_Permissions"
user_id permission_id
-----------------------------------
1 1
1 2
1 3
2 1
2 3
优势
- 索引编制:您可以轻松使用上的索引查询特定事实
- 空间:当您有许多错误值时,默认约定会节省空间
- 规范化:事实在其各自的表中定义(在
和权限
表中)。您可以轻松存储关于每个事实的更多信息用户权限
- 查询:简单查询需要连接
- 设置为False:要将值设置为False,您必须删除一行(从
表中)。否则,您可以在Users\u Permissions
表中使用“deleted”标志,该标志还允许您存储审核跟踪的信息,例如权限修改的时间和修改人。如果删除该行,将无法存储此信息Users\u Permissions
if (in_array($arrAttributes, $iAttributeId)) {
// Project attribute is true!
}
这种方法还允许您执行各种特技,以避免在更新、再次选择(因为select*在代码中不好)、插入等时列出过多的属性。这是因为您可以始终循环表属性以查找可用的属性,因此,如果您添加一个表属性并以这种方式执行操作,那么添加/编辑/删除属性就很简单了。很可能您的SQL甚至不需要更改,因为属性本身是在数据库中定义的,而不是在代码中定义的
希望这有帮助。如果您的DBMS支持布尔数据类型,如MySQL,请使用它。如果它不象Oracle一样,我通常使用一个带有Y或N值的字符(1),在后一种情况下,编写一个函数来转换java或C++或任何类型的布尔类型到y/n,这样就避免了冗余代码来完成这一点是个好主意。这是一个非常简单的函数,但它必须处理null或Y或N以外的值等情况,并且您希望始终如一地这样做 我绝对不会用位操作将标志打包到单个变量中。是的,这将节省一些磁盘空间,但价格要高得多的复杂性和出错的机会。如果您的DBMS没有
if (in_array($arrAttributes, $iAttributeId)) {
// Project attribute is true!
}
class MyBoolean
{
boolean value;
final static MyBoolean TRUE=new MyBoolean(true), FALSE=new MyBoolean(false);
public MyBoolean(boolean b)
{
value=b;
}
public MyBoolean(String s)
{
if (s==null)
return null;
else if (s.equals("Y"))
return MyBoolean.TRUE;
else
return MyBoolean.FALSE;
}
public static String toString(MyBoolean b)
{
if (b==null)
return null;
else if (b.value)
return "Y";
else
reutrn "N";
}
public String toString()
{
return toString(this);
}
}
CREATE TABLE Customer
(
CustomerID NUMBER,
Name VARCHAR(100)
)
CREATE TABLE Customer
(
CustomerID NUMBER,
Name VARCHAR(100),
Searchable BOOLEAN /* or CHAR(1) or BIT... */
)
SELECT CustomerID, Name
FROM Customer
WHERE Name LIKE '%TheCustomerNameIAmLookingFor%'
AND Searchable = TRUE /* or 'Y' or 0... */
CREATE TABLE Customer
(
CustomerID NUMBER,
Name VARCHAR(100)
)
CREATE TABLE SearchableCustomer
(
CustomerID NUMBER
)
SELECT CustomerID, Name
FROM Customer
WHERE Name LIKE '%TheCustomerNameIAmLookingFor%'
AND CustomerID IN (SELECT CustomerID FROM SearchableCustomer)
CREATE VIEW SearchableCustomer AS
SELECT CustomerID
FROM Customer
WHERE Name LIKE 'S%' /* For some reason, management only cares about customers whose name starts with 'S' */