왜 열거 형을 DB에 저장 하시겠습니까?


69

내가 좋아하는 질문의 숫자를 보았다 DB에 열거를 저장하는 방법에 대한 조언을 요청. 하지만 그렇게 하는지 궁금 합니다. 그래서 내가 기업이 있다고하자 PersonA의 gender필드 및 Gender열거. 그런 다음 내 개인 테이블에는 열 성별이 있습니다.

정확성을 강화 gender해야하는 명백한 이유 외에도 애플리케이션에 이미 가지고있는 것을 맵핑하기 위해 추가 테이블 을 작성 해야하는 이유를 알 수 없습니다 . 그리고 나는 그 복제를 좋아하지 않습니다.



1
정기적으로 변경 될 수있는 데이터를 다른 곳에 저장 하시겠습니까? 모든 옵션을 생각했을 수도 있지만 누군가가 와서 새 옵션을 추가하려는 경우 어떻게해야합니까? 하드 코딩 된 목록을 조정할 준비가 되셨습니까? 누군가가 성별을 남성이나 여성 이외의 다른 것으로 제시하고 싶을 수도 있습니다 (예 : 성관계).
JB King

4
@JBKing ... Facebook의 성별 목록을 살펴보십시오.

13
데이터베이스에서 성별 표현 문제에 대한 고전적인 텍스트를 연결하는 데 도움을 줄 수는 없습니다 .
9000

3
고객이 "기괴한 텀블러"인 경우 최소한 비즈니스를 유지하려는 경우 자신의 요구에 맞는 것을 만들 수있는 데이터베이스 스키마를 작성해야합니다.
Steven Burnap

답변:


74

개념과 기대치가 적은 다른 예를 들어 봅시다. 여기에 열거 형이 있으며 버그의 우선 순위입니다.

데이터베이스에 어떤 가치를 저장하고 있습니까?

그래서, 저장 될 수있는 'C', 'H', 'M', 및 'L'데이터베이스입니다. 또는 'HIGH'등등. 이것은 문자열 형식의 데이터에 문제가 있습니다. 알려진 유효한 값 세트가 있으며 데이터베이스에 해당 세트를 저장 하지 않으면 작업하기가 어려울 수 있습니다.

왜 코드에 데이터를 저장합니까?

당신이있어 List<String> priorities = {'CRITICAL', 'HIGH', 'MEDIUM', 'LOW'};나 코드에서 그 효과에 뭔가. 즉,이 데이터를 올바른 형식으로 다양하게 매핑했습니다 (모든 캡을 데이터베이스에 삽입하지만으로 표시합니다 Critical). 코드도 현지화하기가 어렵습니다. 아이디어의 데이터베이스 표현을 코드에 저장된 문자열에 바인딩했습니다.

이 목록에 액세스해야하는 곳이라면 어디에서나 코드 복제 또는 상수가 많은 클래스가 필요합니다. 어느 것도 좋은 옵션이 아닙니다. 또한 이 데이터를 사용할 수 있는 다른 응용 프로그램 (다른 언어로 작성 될 수 있음)을 잊지 말아야합니다 . Java 웹 응용 프로그램에는 Crystal Reports 보고 시스템이 사용되고 Perl 배치 작업이 데이터를 공급합니다. 보고 엔진은 유효한 데이터 목록을 알고 있어야합니다 ( 'LOW'우선 순위 로 표시된 것이없고 보고서에 유효한 우선 순위인지 알아야하는 경우). 배치 작업에는 유효한 데이터에 대한 정보가 있습니다. 가치는.

가설 적으로, 당신은 할 수 "우리는 단일 언어 가게입니다 - 모든 자바로 작성된 것입니다"라고이 정보를 포함하는 하나의 .jar이 -하지만 지금은 당신을 의미 응용 프로그램을 긴밀하게 서로 연결되어 그 .JAR이 포함 자료. 변경 사항이있을 때마다 웹 응용 프로그램과 함께보고 부분과 배치 업데이트 부분을 해제해야하며 해당 부분 이 모든 부분에서 원활하게 진행 되기를 바랍니다 .

상사가 다른 우선 순위를 원하면 어떻게됩니까?

당신의 상사가 오늘 왔어요 새로운 우선 순위가 있습니다- CEO. 이제 모든 코드를 변경 하고 다시 컴파일하고 재배치해야합니다.

'테이블에 열거'접근 방식을 사용하면 열거 목록을 새로운 우선 순위로 업데이트합니다. 목록을 가져 오는 모든 코드는 데이터베이스에서 가져옵니다.

거의 독립적 인 데이터

우선 순위를 사용하면 워크 플로에 대한 정보를 포함하거나이 우선 순위를 설정할 수있는 사람 또는 다른 사람을 포함 할 수있는 다른 테이블 의 데이터 키 가 있습니다.

성별은 사용의 대명사로 연결되는 링크가 있습니다 약간의 질문에 언급 한 바와 같이 성별에 다시 가서 he/his/him하고 she/hers/her... 당신은 코드 자체에 그 하드 코딩하지 않도록합니다. 그리고 그 다음 당신의 상사로 와서 당신은 당신이있어 추가해야합니다 'OTHER'(간단하게하는) 성별 당신이이 성별을 관계 할 필요가 they/their/them... 그리고 당신의 상사는 페이스 북 그래, 음 ...이 무엇을보고있다.

열거 형 테이블이 아닌 문자열 형식의 데이터 비트로 제한함으로써 이제는 데이터와 다른 비트 간의 관계를 유지하기 위해 해당 문자열을 다른 여러 테이블에서 복제해야했습니다.

다른 데이터 스토어는 어떻습니까?

어디에 저장하든 동일한 원칙이 존재합니다.

  • priorities.prop우선 순위 목록 이있는 파일이있을 수 있습니다 . 특성 파일에서이 목록을 읽습니다.
  • 에 대한 항목 이있는 문서 저장소 데이터베이스 (예 : CouchDB )가 있고 JavaScript로 유효성 검증 기능enums작성할 수 있습니다 .

    {
       "_id": "c18b0756c3c08d8fceb5bcddd60006f4",
       "_rev": "1-c89f76e36b740e9b899a4bffab44e1c2",
       "priorities": [ "critical", "high", "medium", "low" ],
       "severities": [ "blocker", "bad", "annoying", "cosmetic" ]
    }
    
  • 약간의 스키마가있는 XML 파일을 가질 수 있습니다.

    <xs:element name="priority" type="priorityType"/>
    
    <xs:simpleType name="priorityType">
      <xs:restriction base="xs:string">
        <xs:enumeration value="critical"/>
        <xs:enumeration value="high"/>
        <xs:enumeration value="medium"/>
        <xs:enumeration value="low"/>
      </xs:restriction>
    </xs:simpleType>
    

핵심 아이디어는 동일합니다. 데이터 저장소 자체는 유효한 값 목록을 저장하고 적용해야하는 곳입니다. 여기에 배치하면 코드와 데이터에 대해 추론하기가 더 쉽습니다. chritical데이터 스토어에서 무엇을 받고 있는지 알기 때문에 매번 가지고있는 것을 방어 적으로 확인하는 것에 대해 걱정할 필요가 없습니다 . 데이터 스토어가 다른 방법으로 전송할 것으로 예상하는 것과 정확하게 일치하며 유효한 값 목록을 데이터 스토어에 쿼리 할 수 ​​있습니다.

테이크 아웃

유효한 값 세트는 코드 가 아니라 data 입니다. 당신은 위해 노력 할 필요 DRY 코드 -하지만 중복의 문제는 당신이 중복된다는 점이다 데이터를 오히려 데이터로 그 자리를 존중하고,이를 데이터베이스에 저장하는 것보다, 코드에서.

코드를 데이터에 연결 하지 않았기 때문에 데이터 스토어에 대해 여러 응용 프로그램을보다 쉽게 ​​작성할 수 있으며 데이터 자체에 긴밀하게 연결된 모든 것을 배포해야하는 인스턴스를 피할 수 있습니다 .

CEO우선 순위를 추가 할 때 전체 응용 프로그램을 다시 테스트 할 필요가 없기 때문에 응용 프로그램을 쉽게 테스트 할 수 있습니다. 우선 순위의 실제 값에 관심이있는 코드가 없기 때문입니다.

코드와 데이터를 서로 독립적으로 추론 할 수 있으므로 유지 관리시 버그를 쉽게 찾고 수정할 수 있습니다.


6
논리 를 변경하지 않고 코드에 열거 형 값을 추가 할 수 있다면 (그리고 현지화 된 디스플레이가 아닌 경우), 먼저 추가 열거 형 값이 필요한지 의심 스럽습니다. 또한 간단한 SQL 쿼리로 데이터베이스 백업을 쉽게 쿼리하여 문제를 분석 할 수있는 능력을 평가할만큼 오래되었지만 요즘 ORM을 사용하면 기본 데이터베이스를 전혀 보지 않고도 매우 잘 수행 할 수 있습니다. 나는 여기서 현지화 (대명사)에 대한 요점을 이해하지 못합니다. 물론 데이터베이스에는 없어야하지만 일종의 리소스 파일이 있어야합니다.
Voo

1
@Voo 대명사는 이 열거 형 값과 관련된 다른 데이터 의 예입니다 . 데이터가 테이블에 없으면 문자열 형식의 값에 적절한 FK 제약 조건이 없어야합니다. 리소스 파일에 대명사 (이와 같은)가있는 경우 데이터베이스와 파일이 연결되어 있습니다 (데이터베이스를 업데이트하고 파일을 재배치). 재배치 할 필요없이 관리자 인터페이스를 통해 즉시 수정 가능한 레드 마인 열거를 고려하십시오 .

1
... 또한 데이터베이스는 폴리 글롯 데이터 저장소라는 것을 기억하십시오. 한 언어로 ORM의 일부로 유효성 검증을 수행해야하는 경우, 사용중인 다른 언어로 유효성 검증을 복제해야합니다 (최근에 Python이 데이터를 데이터베이스로 푸시하는 Java 프론트 엔드를 사용했습니다) -Java ORM 및 Python 시스템은 사물에 동의해야합니다. 데이터베이스 ( 'enum'테이블을 사용하여 데이터베이스를 강제 실행함으로써 해당 계약 (유효한 유형)가 가장 쉽게 구현됩니다).

2
@Voo 열거 형의 Redmine 사용법은 bugzilla 와 동일합니다. "가장 중요한 표에는 시스템의 모든 버그가 포함되어 있습니다. 심각도 및 우선 순위와 같은 모든 열거 형 값을 포함하여 다양한 버그 속성으로 구성되어 있습니다." -자유 형식의 텍스트 필드가 아니며,이 알려져 있고 열거 가능한 세트 중 하나 인 값입니다. 그것은 아닌 컴파일 시간을 열거,하지만 여전히 enumish. Mantis 도 참조하십시오 .

1
사람들이 Enum을 절대로 사용해서는 안된다는 것이 요점입니다. 명확하지 않았다.
niico

18

다음 중 쿼리를 읽을 때 실수를 일으킬 가능성이 더 높은 것은 무엇입니까?

select * 
from Person 
where Gender = 1

또는

select * 
from Person join Gender on Person.Gender = Gender.GenderId
where Gender.Label = "Female" 

사람들은 열거 형 테이블을 읽기 쉽기 때문에 SQL에서 열거 형 테이블을 만듭니다. SQL 작성 및 유지 관리 오류가 줄어 듭니다.

에서 성별을 직접 문자열로 만들 수 Person있지만 사례를 시도하고 시행해야합니다. 또한 DB가 얼마나 최적화 하는가에 따라 문자열과 정수의 차이로 인해 테이블 ​​및 쿼리 시간에 대한 스토리지 적중률을 높일 수 있습니다.


5
그러나 우리는 테이블을 결합합니다. 내 엔터티에 두 개의 열거 형이 있으면 간단한 쿼리를 위해 세 개의 테이블을 조인합니다.
user3748908

11
@ user3748908-그래서? 조인은 DB가 능숙하고 대안은 적어도이 경로를 선택한 사람들의 눈에는 나빠집니다.
Telastyn

8
@ user3748908 : 데이터베이스는 실제로 조인을 수행 할뿐만 아니라 일관성을 유지하는 데에도 좋습니다. 일관성을 적용하면 한 테이블의 열을 다른 식별 행에서 가리키고 "이 열의 값은 해당 테이블의 식별자 중 하나 여야합니다."라고 말할 때 정말 효과적입니다.
Blrfl

2
이것은 모두 사실이지만 성능상의 이유로 조인을 희생해야하는 경우가 많습니다. 내가 틀리게하지 마라 나는 이런 타입의 디자인과 결합에 관한 것이지만 때때로 성능 때문에 조인이 필요하지 않다는 것을 알게되면 세상이 끝나지 않을 것이라고 생각한다.
JonH

3
성능상의 이유로 @JonH 참조 테이블에 조인을 삭제 해야하는 경우 더 큰 서버를 구입하거나 많은 수의 하위 쿼리를 통해 술어를 푸시하려고하지 않아야합니다 (내가하는 일을 알고 있다고 가정합니다). 참조 테이블은 DB를 시작한 후 몇 초 내에 캐시에 있어야하는 것들입니다.
Ben

10

사람들이 아직 언급하지 않았다는 것을 믿을 수 없습니다.

외래 키

데이터베이스에 열거를 유지하고 열거 값이 포함 된 테이블에 외래 키 추가함으로써 보장 더 코드 이제까지 그 열에 대한 잘못된 값을 입력 없다고합니다. 이는 데이터 무결성에 도움이되며 열거 형 테이블이 있어야하는 가장 확실한 이유입니다.


문제는 5 줄 정도이며 "정확성을 강화해야하는 명백한 이유 외에"라고 명확하게 명시되어 있습니다. OP가 분명하고 다른 정당성을 찾고 있다고 말했기 때문에 아무도 그것을 언급하지 않았습니다. PS : 나는 당신에게 동의합니다. 충분한 이유입니다.
user1007074

6

나는 당신과 동의하는 캠프에 있습니다. 코드에 Gender 열거 형을 유지하고 데이터베이스에 tblGender를 유지하면 유지 관리 시간에 문제가 발생할 수 있습니다. 이 두 엔티티는 동일한 값을 가져야하며 따라서 하나의 변경 사항도 다른 하나의 변경 사항을 가져야한다는 것을 문서화해야합니다.

그런 다음 열거 형 값을 저장 프로 시저에 전달해야합니다.

create stored procedure InsertPerson @name varchar, @gender int
    insert into tblPeople (name, gender)
    values (@name, @gender)

그러나 이러한 값을 데이터베이스 테이블에 보관하면 어떻게 할 것인지 생각하십시오.

create stored procedure InsertPerson @name varchar, @genderName varchar
    insert into tblPeople (name, gender)
    select @name, fkGender
    from tblGender
    where genderName = @genderName --I hope these are the same

관계형 데이터베이스는 조인을 염두에두고 구축 되었으나 어떤 쿼리를 더 쉽게 읽을 수 있습니까?


다음은 또 다른 예제 쿼리입니다.

create stored procedure SpGetGenderCounts
    select count(*) as count, gender
    from tblPeople
    group by gender

이것을 이것과 비교하십시오 :

create stored procedure SpGetGenderCounts
    select count(*) as count, genderName
    from tblPeople
    inner join tblGender on pkGender = fkGender
    group by genderName --assuming no two genders have the same name

다음은 또 다른 예제 쿼리입니다.

create stored procedure GetAllPeople
    select name, gender
    from tblPeople

이 예에서는 결과의 성별 셀을 int에서 enum으로 변환해야합니다. 그러나 이러한 변환은 쉽습니다. 이것을 이것과 비교하십시오 :

create stored procedure GetAllPeople
    select name, genderName
    from tblPeople
    inner join tblGender on pkGender = fkGender

열거 형 정의를 데이터베이스에서 유지하려는 아이디어로 갈 때 이러한 쿼리는 모두 작고 유지 관리가 쉽습니다.


1
그래도 성별이 아니었다면? 저는 우리가 성별 인 분야 에 너무 매달리고 있다고 생각 합니다. OP가 "우선 순위 필드가있는 엔터티 버그가 있다고 가정하겠습니다."라고 대답 한 경우 어떻게됩니까?

4
@MichaelT 가능한 "priority"값의 목록은 최소한 데이터의 일부와 같은 정도로 코드의 일부입니다. 다양한 우선 순위에 대한 그래픽 아이콘이 보입니까? 당신은 그들이 데이터베이스에서 뽑힐 것으로 기대하지 않습니까? 그리고 이와 같은 것들은 테마와 스타일을 지정할 수 있으며 여전히 DB에 저장된 동일한 범위의 값을 나타냅니다. 어쨌든 데이터베이스에서 변경할 수는 없습니다. 동기화 할 프리젠 테이션 코드가 있습니다.
Eugene Ryabtsev

1

데이터 분석에 사용할 수있는 이유로 성별 테이블을 작성합니다. 데이터베이스에서 모든 남성 또는 여성을 조회하여 보고서를 생성 할 수 있습니다. 데이터를 볼 수있는 방법이 많을수록 추세 정보를 더 쉽게 찾을 수 있습니다. 분명히 이것은 매우 간단한 열거이지만 세계 또는 국가와 같은 복잡한 열거의 경우 특수 보고서를 쉽게 생성 할 수 있습니다.


1

먼저 데이터베이스를 하나의 응용 프로그램에서만 사용할지 또는 여러 응용 프로그램에서 사용할 수 있는지 여부를 결정해야합니다. 경우에 따라 데이터베이스는 응용 프로그램의 파일 형식에 지나지 않습니다 (SQLite 데이터베이스는 이와 관련하여 종종 사용될 수 있음). 이 경우 열거 형 정의를 테이블로 복제하는 비트가 종종 좋을 수 있으며 더 의미가 있습니다.

그러나 여러 응용 프로그램이 데이터베이스에 액세스 할 가능성을 고려하자마자 열거 형의 테이블이 상당히 합리적입니다 (다른 답변은 더 자세한 이유에 대해 설명합니다). 고려해야 할 다른 것은 당신이나 다른 개발자가 원시 데이터베이스 데이터를보고 싶을 것입니다. 그렇다면 다른 응용 프로그램 사용으로 간주 될 수 있습니다 (실험실 게이지가 원시 SQL 인 경우).

데이터베이스에 테이블뿐만 아니라 코드 (깨끗한 코드 및 컴파일 시간 검사를 위해)에 열거 형이 정의되어 있으면 단위 테스트를 추가하여 두 가지가 동기화되어 있는지 확인하는 것이 좋습니다.


1

코드에서 비즈니스 로직을 구동하는 데 사용되는 코드 열거 형이있는 경우 위에서 / 아래에 자세히 설명 된 여러 가지 이유로 DB의 데이터를 나타내는 테이블을 작성해야합니다. 다음은 DB 값이 코드 값과 동기화되도록하는 몇 가지 팁입니다.

  1. 테이블의 ID 필드를 ID 열로 만들지 마십시오. 필드로 ID 및 설명을 포함하십시오.

  2. 표에서 다른 값을 사용하면 개발자가 값이 반 정적 / 코드 열거 형임을 알 수 있습니다. 다른 모든 조회 테이블 (일반적으로 사용자가 값을 추가 할 수있는 위치)에는 일반적으로 LastChangedDateTime 및 LastChangedBy가 있지만 열거 형 관련 테이블에 값을 갖지 않으면 개발자가 변경할 수 있음을 기억하는 데 도움이됩니다. 이것을 문서화하십시오.

  3. 열거의 각 값이 해당 테이블에 있고 해당 값만 해당 테이블에 있는지 확인하는 확인 코드를 만듭니다. 빌드 후 실행되는 응용 프로그램 "상태 테스트"를 자동화 한 경우 여기에서 수행하십시오. 그렇지 않은 경우 응용 프로그램이 IDE에서 실행될 때마다 응용 프로그램 시작시 코드가 자동으로 실행되도록하십시오.

  4. DB 내부에서 동일한 작업을 수행하는 프로덕션 SQL 스크립트를 작성하십시오. 올바르게 작성하면 환경 마이그레이션에도 도움이됩니다.


0

누가 데이터에 액세스하는지에 따라 다릅니다. 응용 프로그램이 하나만 있다면 괜찮을 것입니다. 데이터웨어 하우스 또는보고 시스템에 추가하는 경우 그들은 그 코드가 무엇을 의미하는지, 인간이 할 수있는 코드 버전이 무엇인지 알아야합니다.

일반적으로 형식 테이블은 코드에서 열거 형으로 복제되지 않습니다. 캐시 된 목록에 유형 테이블을로드 할 수 있습니다.

Class GenderList

   Public Shared Property UnfilteredList
   Public Shared Property Male = GetItem("M")
   Public Shared Property Female = GetItem("F")

End Class

종종 유형이왔다 갔다합니다. 새 유형이 추가 된 날짜가 필요합니다. 특정 유형이 언제 제거되었는지 알 수 있습니다. 필요할 때만 표시하십시오. 고객이 성별로 '전 환자'를 원하지만 다른 고객은 원하지 않는 경우 어떻게해야합니까? 이 모든 정보는 데이터베이스에 가장 잘 저장됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.