Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 在设计数据库时,存储多个真/假值的首选方法是什么?_Sql Server_Oracle_Database Design_Query Optimization - Fatal编程技术网

Sql server 在设计数据库时,存储多个真/假值的首选方法是什么?

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。使用对您正在使用的特定数据库引擎有意义的任何东西。需要处理它的是数据库的接口。如果数据库的代

如标题中所述,在设计数据库时,处理具有多列且仅将真/假值存储为单个或值(例如“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。枚举和位类型的麻烦比它们的价值还多

值得注意的是,MySQL
information\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
    表中)。否则,您可以在
    Users\u Permissions
    表中使用“deleted”标志,该标志还允许您存储审核跟踪的信息,例如权限修改的时间和修改人。如果删除该行,将无法存储此信息

我通常在没有位/布尔值的情况下执行此操作。相反,我要三张桌子。假设我们有一个项目管理系统,它有很多项目,这些项目有很多属性

然后我们有表格:

Project - Project_ID (INT), - Name (VARCHAR) Attribute - Attribute_ID (INT), - Name (VARCHAR) ProjectAttribute_Rel - Project_ID (INT), - Attribute_ID (INT) 此时,您可以通过检查$ArraAttribute中是否存在项目的属性来检查该属性是否为true。在PHP中,这将是:

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' */