데이터베이스를 설계할 때 참/거짓 값을 여러 개 저장하는 선호되는 방법은 무엇입니까?
제목에 명시된 것처럼 데이터베이스를 설계할 때 참/거짓 값을 하나의 값(예: "Y/N:" 또는 "0/1")으로 저장하는 여러 열을 가진 테이블을 처리하는 선호되는 방법은 무엇입니까?마찬가지로 서로 다른 데이터베이스(예: Oracle 및 SQL Server) 간에 발생할 수 있는 몇 가지 문제가 열 처리 방식에 영향을 미칠 수 있습니까?
SQL Server
, 어있BIT
0 할 수 , 는 있지만 할 수는 없습니다.MIN
또는MAX
.
Oracle
당신은 그냥 사용합니다.NUMBER
또는CHAR(1)
.
MySQL
그리고.PostgreSQL
모든 으로 모든데이유암형변가로환능으로 변환할 수 .BOOLEAN
.
모두 두시템지를 지원합니다.BOOLEAN
사용할 수 있는 입니다.WHERE
또는ON
절:
SELECT *
FROM mytable
WHERE col1
은 불한것능가에서 합니다.SQL Server
그리고.Oracle
(당신은 거기에 어떤 종류나 술어가 있어야 합니다.)
MySQL
,BOOLEAN
는 의동입니다어의 입니다.TINYINT(1)
.
PostgreSQL
(스토리지 측면에서는) 그렇지만 논리적으로는 다른 유형으로 암시적으로 변환할 수 없습니다.
제 경험으로는 'Y'나 'N'보다는 char(1)가 더 좋습니다.0과 1을 사용하는 것은 내가 이미 얼마나 많은 맥주를 마셨는지에 따라 약간 혼란스러울 수 있고 C++ 메인() 기능은 성공 시 0을 반환합니다.ENUM 및 BIT 유형은 가치보다 더 큰 문제입니다.
MySQL을 롭습니다.information_schema
VARCHAR(3)를 사용하여 'YES' 또는 'NO'를 나타냅니다.
예:
information_schema.USER_PRIVILEGES (
...
IS_GRANTABLE VARCHAR(3) NOT NULL DEFAULT ''
)
부울 데이터 유형 대신 부울 값을 저장하는 다른 데이터 모델을 고려할 수 있으며, 이는 다음과 같은 경우에 특히 적합할 수 있습니다.
- 예/아니오 열이 많은 경우.
- 앞으로 예/아니오 열을 더 추가해야 할 경우.
- yes/no 값이 자주 변경되지 않는 경우.
사용자 권한을 정의하는 것은 위의 일반적인 예일 수 있습니다.다음 표를 고려합니다.
Table "Users": (user_id, name, surname, country)
Table "Permissions": (permission_id, permission_text)
Table "Users_Permissions": (user_id, permission_id)
Permissions
표 사용자에게 적용 가능한 모든 권한을 정의할 수 있습니다.은 행추야합니다해가에 해야 할 입니다.Permissions
각 yes/no 속성에 대한 표입니다.이렇게 하면 데이터베이스 스키마를 수정할 필요 없이 나중에 새 권한을 쉽게 추가할 수 있습니다.
모델을 하면 위모델사면다음할을당여하값을 TRUE다니냅나를 .user_id
permission_id
에 시대에Users_Permissions
테이블. 그렇지 않으면 기본적으로 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
이점
- 인덱싱: 의 인덱스를 사용하여 특정 사실을 쉽게 쿼리할 수 있습니다.
- 공간: 잘못된 값이 많은 경우 기본 규칙에 따라 공간이 절약됩니다.
- 정규화됨:사실은 그들 자신의 표에서 정의됩니다.
Permissions
그리고.Users_Permissions
더 할 수 .각 사실에 대한 더 많은 정보를 쉽게 저장할 수 있습니다.
단점들
- 쿼리:단순 쿼리에는 JOIN이 필요합니다.
- 거짓으로 설정:값을 false로 설정하려면 행을 삭제해야 합니다.
Users_Permissions
표).그렇지 않으면 다음에서 '삭제됨' 플래그를 사용할 수 있습니다.Users_Permissions
테이블 - 권한이 수정된 시간 및 사용자와 같은 감사 추적에 대한 정보를 저장할 수도 있습니다.행을 삭제하면 이 정보를 저장할 수 없습니다.
사용 중인 특정 데이터베이스 엔진에 적합한 모든 것을 사용합니다.데이터베이스를 처리해야 하는 인터페이스입니다.데이터베이스에 대한 코드 측 인터페이스가 충분히 모듈화된 경우, 기본 데이터베이스에서 다른 부울 형식을 처리하는 것은 단순한 한 줄 변경에 불과합니다.
저는 "Y/N" 값이 "1/0" 값보다 더 의미 있다고 생각합니다.Oracle을 사용하면 데이터베이스 엔진에서 최대한 데이터를 검증할 수 있도록 다음 작업을 수행할 수 있습니다.
- 열을 char(1)로 정의합니다.
- 가능한 값이 "in"('Y', 'N')으로 제한되는 확인 제약 조건 추가
- 비즈니스 규칙과 일치하는 경우, 이 규칙을 무효화하지 마십시오. 이렇게 하면 SQL에서 'Y'가 아닌 모든 항목의 값이 'N'이라고 암시적으로 가정할 때 문제를 방지할 수 있습니다.
DBMS가 MySQL과 같은 부울 데이터 유형을 지원하는 경우 이를 사용합니다.Oracle처럼 그렇지 않으면 일반적으로 Y 또는 N 값이 있는 char(1)를 사용합니다.후자의 경우에는 Java, C++ 또는 어떤 부울 형식이든 Y/N에서 Y/N으로 변환하기 위한 몇 가지 함수를 작성하는 것이 좋습니다.이것은 꽤 사소한 함수이지만 Y나 N 이외의 null이나 값과 같은 경우를 처리해야 할 것이고 당신은 그것을 지속적으로 하기를 원합니다.
비트 연산으로 플래그를 단일 변수로 패킹하지 않을 것입니다.예, 이렇게 하면 디스크 공간을 절약할 수 있지만, 가격은 훨씬 더 복잡하고 오류가 발생할 가능성이 높습니다.만약 당신의 DBMS가 비트 연산을 지원하지 않는다면 -- 그리고 저는 그런 일을 해본 적이 없기 때문에, 저는 어떤 일을 하고 싶은지, 만약 있다면 -- 당신은 그런 플래그를 기준으로 선택하거나 정렬하는 데 정말 어려움을 겪을 것입니다.물론, 다른 기준을 충족하는 모든 레코드를 검색한 다음 적절한 플래그 값을 가진 레코드를 호출 코드에서 제거할 수 있습니다.하지만 레코드의 일부만 원하는 플래그 값을 가지고 있고 다른 많은 레코드를 조인하는 쿼리가 있다면 어떻게 될까요?"select employee.name , select employee pay에서 sum(pay.mount)을 사용하여 직원이 가입한 급여의 합계(pay.mount)를 사용합니다.executive=true and pay.sshot=true".where 절을 사용하면 매우 적은 수의 레코드를 검색할 수 있습니다.그렇지 않으면 전체 데이터베이스를 검색할 수 있습니다.
요즘은 디스크 공간이 저렴하기 때문에 디스크 절약은 중요하지 않습니다.만약 여러분이 정말로 엄청난 수의 깃발들을 가지고 있다면 -- 레코드당 수백 또는 수천 개의 깃발들처럼 -- 저는 그것들을 포장하는 경우가 있을 것이라고 생각합니다.하지만 그것은 제가 선택한 디자인 목록보다 훨씬 아래에 있을 것입니다.
편집: "SQL boolean"을 "Java boolean"으로 변환하는 클래스 작성에 대해 자세히 설명하겠습니다.어떤 언어든 마찬가지이지만, 예를 들어 자바를 사용하겠습니다.
DBMS에 부울 형식이 내장되어 있으면 Java를 사용하여 ResultSet.getBoolean()으로 부울 변수로 직접 읽을 수 있습니다.
하지만 만약 여러분이 문자 "Y"나 "N"으로 저장해야 한다면, 여러분은 그것을 문자열로 읽어야 합니다.따라서 다음과 같은 클래스를 선언하는 것이 타당합니다.
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);
}
}
그런 다음 "MyBoolean flag=new MyBoolean(rs.getString("flag))"을 사용하여 데이터베이스에서 부울을 쉽게 선택할 수 있습니다."rs.setString("flag", flag.toString();"을 사용하여 데이터베이스에 씁니다.
그리고 물론 다른 부울적인 것들이 필요하다면 필요한 다른 논리를 클래스에 추가할 수 있습니다.어떤 목적으로 부울을 T/F, Yes/No, On/Off 등으로 표시하려면 유사한 코드를 반복적으로 쓰는 대신 String 변형(TFSring 또는 String(값, 참 텍스트, 거짓 텍스트) 또는 기타 항목에 대체 항목을 추가하면 됩니다.
열을 추가하는 대신 다른 테이블을 만드는 것이 좋습니다.끝까지 들어봐요...
이름이 지정된 테이블이 있다고 가정합니다.Customer
:
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... */
이것은 멋지고 간단합니다.이 스레드의 많은 사람들은 구문이 다양한 데이터베이스에서 잘 작동하도록 하기 위해 이 열이 어떤 데이터 유형이어야 하는지를 선택하는 데 좋은 조언을 제공합니다.
대안: 별도의 표 작성
는추대신하에 다른 Customer
다음을 저장하는 별도의 테이블을 만들 것입니다.CustomerID
검색 가능한 모든 고객의.
CREATE TABLE Customer
(
CustomerID NUMBER,
Name VARCHAR(100)
)
CREATE TABLE SearchableCustomer
(
CustomerID NUMBER
)
의 고객이 검색 가능한 것으로 간주됩니다.CustomerID
합니다.SearchableCustomer
table.는 다음과 이제 고객 검색을 위한 쿼리는 다음과 같습니다.
SELECT CustomerID, Name
FROM Customer
WHERE Name LIKE '%TheCustomerNameIAmLookingFor%'
AND CustomerID IN (SELECT CustomerID FROM SearchableCustomer)
이 전략은 RDBMS 간에 매우 쉽게 전송됩니다.
- 찾기는 검색가고다사다용니합음을 합니다.
IN
절JOIN
- 을 검색 한 상태로 만드는 은 다을사검설가정로능을 합니다.
INSERT
- 상태로 만드는 은 고을검만방법을 합니다.
DELETE
놀라운 혜택
이 원하는 수 .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' */
당신의 검색 질의는 전혀 변하지 않습니다! :D 제 경험상, 이것은 엄청난 유연성으로 이어졌습니다.
비트 열은 일반적으로 적어도 SQL Server에서 T/F 또는 Y/N 유형 값을 나타내는 데 사용됩니다.데이터베이스 순수주의자는 비트 열이 "하드웨어에 너무 가깝기 때문에" 데이터베이스에 위치가 없다고 말할 수 있지만, Joe Celko입니다.
"내 테이블에서 선택 * col1
SQL Server 및 Oracle에서는 불가능합니다(어떤 종류의 용어나 술어가 있어야 함)."
이는 Oracle 및 SQL Server가 실제로 얼마나 터무니없고 우스꽝스러운 혐오스러운 존재인지 보여주는 것일 뿐입니다.
col1이 Boolean 유형으로 선언되면 "col1"이라는 표현은 술어입니다.
WHERE 절의 의미론에서 표현식이 true 값으로 평가되어야 하고 일부 열이 true 값 유형으로 선언되면 "WHERE that-column"이 허용되고 지원되어야 합니다.마침표.무능한 평범한 돌팔이를 위해 저자를 폭로하지 않는 모든 시스템.
일반적으로 BIT/BOOL 값을 전혀 사용하지 않고 이 작업을 수행합니다.대신에 저는 세 개의 테이블을 가질 것입니다.우리가 프로젝트 관리 시스템을 가지고 있다고 가정해 보겠습니다. 그리고 이 프로젝트들은 많은 속성을 가지고 있습니다.
그리고 우리는 테이블을 가지고 있습니다.
프로젝트.프로젝트_ID(INT),이름(VARCHAR) 기여하다속성_ID(INT),이름(VARCHAR) 프로젝트 특성_Rel프로젝트_ID(INT),속성_ID(INT)
프로젝트 속성이 참인지 거짓인지는 ProjectAttribute_Rel에 해당하는 줄이 있는지 여부에 따라 달라집니다.
일반적으로 속성_을 처리합니다.코드에 ID가 있으므로 프로젝트의 속성을 읽을 때(프로젝트가 있는 것으로 추정됨)_ID), 다음을 수행합니다(PHP가 임의로 예제로 사용됨).
$arrAttributes = array();
$oQuery = mysql_query('
SELECT Attribute_ID
FROM ProjectAttribute_Rel
WHERE Project_ID = '.addslashes($iProjectId).'
');
while ($rowAttribute = mysql_fetch_assoc($oQuery)) {
$arrAttributes[] = $rowAttribute['Attribute_ID'];
}
이때 $arrAttributes에 프로젝트 속성이 존재하는지 여부를 확인하여 프로젝트 속성이 참인지 여부를 확인할 수 있습니다.PHP에서 이것은 다음과 같습니다.
if (in_array($arrAttributes, $iAttributeId)) {
// Project attribute is true!
}
또한 이 접근 방식을 사용하면 업데이트할 때, 삽입할 때(SELECT *가 코드가 나쁘기 때문에) 다시 선택할 때, 너무 많은 속성이 나열되지 않도록 모든 정렬 스턴트를 수행할 수 있습니다.이는 사용 가능한 특성을 찾기 위해 항상 테이블 속성을 반복적으로 검색할 수 있기 때문입니다. 따라서 속성을 추가하고 이런 방식으로 작업을 수행하면 속성을 추가/편집/삭제하는 작업이 거의 없습니다.속성 자체가 코드가 아닌 데이터베이스에 정의되어 있기 때문에 SQL을 변경할 필요가 없을 가능성이 높습니다.
이게 도움이 되길 바랍니다.
언급URL : https://stackoverflow.com/questions/2200063/when-designing-databases-what-is-the-preferred-way-to-store-multiple-true-fal
'programing' 카테고리의 다른 글
두 번째 및 세 번째 노드에 대한 HAroxy 연결은 첫 번째 노드에만 있어야 합니다. (0) | 2023.08.18 |
---|---|
도커 빌드 "Can't resolve 'archive.ubuntu.com '" apt-get이 아무것도 설치하지 못함 (0) | 2023.08.18 |
jQuery를 사용하여 선택한 옵션 ID 가져오기 (0) | 2023.08.13 |
Amazon EC2 :- Mariadb를 설치할 수 없습니다. (0) | 2023.08.13 |
Excel 스프레드시트에서 열이 누락됨 (0) | 2023.08.13 |