청구서 수신 주소 모범 사례를 주문 테이블에 저장


10

누군가 CustomerLocation 테이블에 대한이 사용자의 답변을 이해하도록 도와 줄 수 있습니까 ? 주문 테이블에 주소를 저장하는 좋은 방법을 원합니다.

내가 찾고있는 것은 주소를 설정하여 편집 할 때 고객이 주소를 업데이트하거나 이전한다는 사실에 영향을받지 않습니다.

내 스키마는 다음과 유사합니다.

 Person           |EntityID|
 EntityAddress    |EntityID|AddressID|
 Address          |AddressID|AddressType|AddressLine1|AddressLine2|
 Order            |OrderID|BillingAddressID|

답변:


16

개념적으로 말하자면 비즈니스 환경에서 주문주소 는 밀접하게 관련되어있는 아이디어 이지만 사실상 각각 고유 한 적용 가능한 속성 (또는 속성)과 제약 조건이있는 두 개의 개별 엔티티 유형입니다.

따라서 이전에 의견에서 언급했듯이 @Erik에 동의하며 다른 요소 중에서 선언하는 데이터베이스의 논리적 레이아웃을 구성해야합니다.

  • 주소 정보 를 유지하기위한 하나의 개별 테이블 ;
  • 고객 별 세부 정보 를 유지하는 하나의 테이블 ;
  • 주문 데이터 포인트 를 묶는 하나의 테이블 ; 과
  • 고객주소 간의 연관에 관한 사실을 포함하는 하나의 테이블 ;

아래 예를 들어 보겠습니다.

설명 IDEF1X 다이어그램

그림은 천 단어의 가치가 있으므로 그림 1 에 표시된 IDEF1X 다이어그램을 만들어 내 제안에 의해 열린 가능성을 보여줍니다.

그림 1-고객, 주문 및 주소 설명 IDEF1X 다이어그램

고객 , 주소 및 관련 협회

입증 된 바와 같이, 엔티티 유형 고객 a주소 사이의 다 대다 (M : N) 카디널리티 비율과의 연관성을 묘사했습니다 . 아시다시피 고객 은 시간이 지남에 따라 또는 여러 개의 주소 를 동시에 유지할 수 있고 여러 고객 이 동일한 주소 를 공유 할 수 있기 때문에이 접근 방식은 미래의 유연성을 제공합니다 .

특정 주소 는 일대 다 (1 : M) 고객이 여러 가지 방법으로 사용할 수 있습니다 . 예를 들어, 그것은으로 정의 할 수 있습니다 물리적 및 / 또는이를 설정할 수 있습니다 배송 및 / 또는에 대한 청구 . 아마도 동일한 Address 인스턴스가 앞에서 언급 한 각 목적을 동시에 수행 할 수 있거나 다른 Address 발생이 나머지 용도를 커버하는 동안 두 가지 용도를 처리 할 수 ​​있습니다 .

a 일부 비즈니스 환경에서 고객 개인 또는 조직 (수퍼 타입 ​​하위 유형 구조에 대한 이 답변에서 자세히 설명한대로 약간 다른 배치를 암시하는 상황) 일 수 있지만 간단한 예를 제공하려는 목적으로 결정했습니다. 그 가능성을 여기에 포함시키지 마십시오. 데이터베이스에서 해당 상황을 처리해야하는 경우 이전 링크의 게시물에 해당 요구 사항을 해결하는 방법이 표시됩니다.

주문 , 주소 , 고객 주소주소 역할

일반적으로 주문 에는 두 가지 종류의 주소 만 필요합니다 . 하나는 배송 용 이고 다른 하나는 청구 용 입니다. 이러한 방식으로, 동일한 Address 인스턴스 는 개별 Order에 대한 두 역할 을 모두 채울 수 있지만 각 역할 은 각각의 특성 (예 : ShippingAddressId 또는 BillingAddressId)으로 표시 됩니다.

주문 은 두 개의 다중 속성 FOREIGN KEY 를 통해 CustomerAddress 연관 엔티티 유형을 통해 Address 와 연결됩니다 .

  • ( CustomerNumber , ShippingAddressId ) 및 ( CustomerNumber , BillingAddressId ),

둘 다 CustomerAddress 다중 속성 PRIMARY KEY를 가리키는

  • ( CustomerNumber , AddressId )

… (a) 주문 인스턴스는 (b) 해당 주문을 한 특정 고객 과 이전에 연결된 주소 발생 과 (c) 무작위로 고객이 아닌 - 관련 주소 .

(1) 주소 및 (2) CustomerAddress 연관에 대한 히스토리

주소 정보 를 수정할 수있는 가능성을 제공하려면 모든 데이터 변경 사항을 추적해야합니다. 이런 방식으로 Address 는 자신의 AddressHistory 를 유지하는“감사 가능한”엔티티 유형 으로 묘사 했습니다 .

고객주소 간의 연결 특성 도 하나 이상의 수정을 겪을 수 있기 때문에 CustomerAddressHistory 엔티티 유형 으로 인해 이러한 연결을 "감사 가능한"것으로 취급 할 수있는 가능성도 설명했습니다 .

이와 관련하여 Q & A No. 1Q & A 번호 데이터베이스에서 시간적 기능을 활성화 하는 것과 관련 하여 2 는 실제로 관련이 있습니다.

예시적인 SQL-DDL 논리 레이아웃

결과적으로 위에서 표시하고 설명한 다이어그램의 관점에서, 나는 다음과 같은 논리 수준 배열을 선언했습니다 (정확도로 요구 사항을 충족하도록 조정할 수 있음).

-- You should determine which are the most fitting 
-- data types and sizes for all your table columns 
-- depending on your business context characteristics.

-- Also, you should make accurate tests to define the 
-- most convenient INDEX strategies based on the exact 
-- data manipulation tendencies of your business domain.

-- As one would expect, you are free to utilize 
-- your preferred (or required) naming conventions. 

CREATE TABLE Customer (
    CustomerNumber      INT      NOT NULL,
    SpecificAttribute   CHAR(30) NOT NULL,
    ParticularAttribute CHAR(30) NOT NULL,  
    CreatedDateTime     DATETIME NOT NULL,
    -- 
    CONSTRAINT Customer_PK PRIMARY KEY (CustomerNumber)
);

CREATE TABLE Address (
    AddressId           INT      NOT NULL,
    SpecificAttribute   CHAR(30) NOT NULL,
    ParticularAttribute CHAR(30) NOT NULL,  
    CreatedDateTime     DATETIME NOT NULL,  
    -- 
    CONSTRAINT Address_PK PRIMARY KEY (AddressId)
);

CREATE TABLE CustomerAddress (
    CustomerNumber  INT      NOT NULL,  
    AddressId       INT      NOT NULL,
    IsPhysical      BIT      NOT NULL,
    IsShipping      BIT      NOT NULL,  
    IsBilling       BIT      NOT NULL,
    IsActive        BIT      NOT NULL,
    CreatedDateTime DATETIME NOT NULL,  
    -- 
    CONSTRAINT CustomerAddress_PK           PRIMARY KEY (CustomerNumber, AddressId),
    CONSTRAINT CustomerAddressToCustomer_FK FOREIGN KEY (CustomerNumber)
        REFERENCES Customer (CustomerNumber),
    CONSTRAINT CustomerAddressToAddress_FK  FOREIGN KEY (AddressId)
        REFERENCES Address  (AddressId)  
);

CREATE TABLE MyOrder (
    CustomerNumber      INT      NOT NULL,  
    OrderNumber         INT      NOT NULL,
    ShippingAddressId   INT      NOT NULL,
    BillingAddressId    INT      NOT NULL,    
    SpecificAttribute   CHAR(30) NOT NULL,
    ParticularAttribute CHAR(30) NOT NULL,  
    OrderDate           DATE     NOT NULL,
    CreatedDateTime     DATETIME NOT NULL,  
    -- 
    CONSTRAINT Order_PK                  PRIMARY KEY (CustomerNumber, OrderNumber),
    CONSTRAINT OrderToCustomer_FK        FOREIGN KEY (CustomerNumber)
        REFERENCES Customer        (CustomerNumber),
    CONSTRAINT OrderToShippingAddress_FK FOREIGN KEY (CustomerNumber, ShippingAddressId)
        REFERENCES CustomerAddress (CustomerNumber, AddressId),
    CONSTRAINT OrderToBillingAddress_FK  FOREIGN KEY (CustomerNumber, BillingAddressId)
        REFERENCES CustomerAddress (CustomerNumber, AddressId)          
);

CREATE TABLE AddressHistory (
    AddressId           INT      NOT NULL,
    AuditedDateTime     DATETIME NOT NULL,
    SpecificAttribute   CHAR(30) NOT NULL,
    ParticularAttribute CHAR(30) NOT NULL,  
    CreatedDateTime     DATETIME NOT NULL,  
    -- 
    CONSTRAINT AddressHistory_PK          PRIMARY KEY (AddressId, AuditedDateTime),
    CONSTRAINT AddressHistoryToAddress_FK FOREIGN KEY (AddressId)
        REFERENCES Address  (AddressId)    
);

CREATE TABLE CustomerAddressHistory (
    CustomerNumber  INT      NOT NULL,  
    AddressId       INT      NOT NULL,
    AuditedDateTime DATETIME NOT NULL,    
    IsPhysical      BIT      NOT NULL,
    IsShipping      BIT      NOT NULL,  
    IsBilling       BIT      NOT NULL,
    IsActive        BIT      NOT NULL,
    CreatedDateTime DATETIME NOT NULL,  
    -- 
    CONSTRAINT CustomerAddressHistory_PK                  PRIMARY KEY (CustomerNumber, AddressId, AuditedDateTime),
    CONSTRAINT CustomerAddressHistoryToCustomerAddress_FK FOREIGN KEY (CustomerNumber, AddressId)
        REFERENCES CustomerAddress (CustomerNumber, AddressId)
);

살펴 보려면 SQL Server 2017에서 실행 되는이 db <> 바이올린에서 테스트했습니다 .

History테이블

귀하의 질문에서 다음과 같은 발췌 내용이 매우 중요합니다.

내가 찾고있는 것은 주소를 설정하여 편집 할 때 고객이 주소를 업데이트하거나 이전한다는 사실에 영향을받지 않습니다.

AddressHistoryCustomerAddressHistory보장의 테이블 원조 주문 에 의해 영향을받지 않습니다 주소 모든 "이전"행이 각각 유지해야한다로 변경 History테이블과 필요에 조회 할 수 있습니다. 이 두 테이블에 대한 UPDATE 및 DELETE 조작은 금지되어야합니다 (히스토리 변경을 시도하면 법적으로 부정적인 영향을 줄 수 있음).

간격 에 둘러싸인 값 사이에 포함 AddressHistory.CreatedDateTime하고 AddressHistory.AuditedDateTime전체의 약자 기간 특정 "과거"그 동안 Address행, "현재"또는 "효과" "현재"간주되었다. CustomerAddressHistory행 에도 비슷한 고려 사항이 적용됩니다 .

CustomerAddress.IsActiveBIT (boolean)에 열이 어떤 것인지 지적 의미 Address행에 의해 "가능"인 Customer행의 여부; 예를 들어, '거짓'으로 설정된 경우 고객 이 더 이상 해당 주소를 사용하지 않으므로 새 주문에 사용할 수 없다는 사실을 전달합니다 .


참고 : 반면에, 나는 새로운 주문 이 발효 될 때마다 주소 정보가 (때로는 반복적으로) 입력되어야 하며 과거 주문에 사용 된 주소 가 지워지지 않는 시스템을 보았습니다 (따라서) 주문은 영향을받지 않는 주소 )로 변경됩니다.

이 작업 과정에는 많은 양의 중복성이 결정적으로 포함될 수 있지만 비즈니스 도메인의 정확한 정보 요구 사항에 따라 작동 할 수 있으므로 장단점도 평가할 수 있습니다.


데이터 검색

의 "현재", "현재"또는 "유효"버전 주소 발생이있는 행으로 포함되어야 Address테이블하지만 이전의 "상태"를 선택한 주소 로부터 AddressHistory(또는 행 CustomerAddressHistory) 테이블은 간단하고, 월 SQL 코딩 기술을 향상시키는 흥미로운 연습이 되십시오.

개별의 "마지막 버전으로 두 번째"검색 할 경우, 주석에서 언급 한 상황 중 하나에 대하여 Address그 FROM 행을 AddressHistory, 당신은 계정에 걸릴해야 MAX(AddressHistory.AuditedDateTime)하고, AddressHistory.AddressId특정 일치 Address.AddressId손에서 값입니다.

이와 관련하여 (적어도 관계형 데이터베이스를 구축 할 때는) 먼저 해당하는 개념 스키마 (해당 비즈니스 규칙에 따라 )를 정의한 후 후속 논리 DDL 배열 을 선언 하는 것이 매우 편리합니다 . 시간이 지남에 따라 진화 할 수있는 이러한 기본 요소의 안정적이고 안정적인 버전을 확보 한 후에는 (INSERT, UPDATE, DELETE 및 SELECT 작업 또는 이들의 조합을 통해) 조작하는 가장 좋은 방법을 분석하고 결정해야합니다. 데이터 관련.

최종 사용자의 인식, 견해 및 응용 프로그램 지원

분명히, 외부 추상화 레벨에서, 주소 정보는 (최종 사용자에 의해) Order의 일부로 인식되며 , 그에 아무런 문제가 없지만, 모델러가 중요한 부분을 설계해야한다는 의미는 아닙니다. 그런 문제의 데이터베이스. 이 시점에서, 예를 들어, "전체" 주문을 인쇄해야하는 경우 (매우 타당 함) 몇몇 JOIN 연산자와 WHERE 절의 도움을 받아 주문형 주문을 "재생산"할 수 있습니다 (유효 기간 관련 고려 사항 포함) 등) 은 향후 소비에 대한 관점 에서 고정되어 관련 결과 프로그램을 관련 응용 프로그램에 전송하여 필요에 따라 형식을 향상시킬 수 있습니다.

물론, 주문 이 시행 될 때 응용 프로그램도 매우 도움이 될 것입니다 . 예를 들어 데스크톱 / 모바일 앱 창 또는 웹 페이지는 다음을 수행 할 수 있습니다.

  • 관련 고객 이 "사용 가능"으로 설정 한 주소 만 표시합니다 (를 통해 ).CustomerAddress.IsActive
  • 고객 이 청구 서비스에 사용하도록 설정 한 모든 주소 를 함께 나열합니다 (를 통해 ). 과CustomerAddress.IsBilling
  • 고객 이 운송 서비스를 위해 정의한 모든 주소 를 그룹화합니다 (를 통해 ).CustomerAddress.IsShipping

이러한 방식으로 GUI에서의 모든 관련된 프로세스 (즉, 컴퓨터 시스템의 외부 추상화 레벨)를 용이하게한다.


추천 독서

사운드 데이터베이스 문헌에 대한 몇 가지 포인터를 요청했습니다 (이제 주석에서 삭제). 따라서에 관해서는 이론적 소재, 내가보기 엔 당신이 쓴 모든 일을 읽을 것을 조언 박사 EF 커드 하는 튜링 상 , 물론,받는 사람 및 단독 발신자관계형 데이터 모델 (어쩌면 지금보다 관련성이 어느 때보를). 이 목록 에는 그의 영향력있는 기사와 논문 포함되어 있습니다.

상기 목록에 포함되지 않은 두 가지 중요한 작품은, 정확하게, 자신의 ACM 튜링 상 강의는받을 수 있습니다 생산성을위한 실용 재단 : 관계형 데이터베이스를 1981 년, 그의 책은 원화 데이터베이스 관리를위한 관계형 모델 : 버전 2 , 출판 되었음 1990 년.

개념 설계 앞, 정보 모델링을위한 통합 정의 (IDEF1X는) 미국이 1993 년 12 월 표준으로 정의 된 심각 추천 기술입니다 국립 표준 기술 연구소 (NIST).


1
죄송합니다. 게시물이 오래되었다는 것을 알고 있습니다. 왜 MyOrder에서 REFERENCES 주소 (주소 ID)를 참조하고 있습니까? 왜 CustomerAddress가 아닙니까?
Shadrix

1
걱정하지 않으며, 좋은 캐치 : 사실, 모두 MyOrder.ShippingAddressIdMyOrder.BillingAddressId에 대한 참조를해야합니다 CustomerAddress.AddressId(그리고에 Address.AddressId); 이런 식으로 하나 개의 보장하지만은 것을 주문 독점적과 연관 될 수 있습니다 주소 (들) 이전에 연결된 고객 것을 만들어 주문 . 다이어그램은이 배열을 제안하므로 DDL이 더 정확합니다. 설명을 요청 해 주셔서 감사합니다.
MDCCL

2
@Shadrix 방금보고 싶은 경우에 대비하여 게시물을 편집했습니다.
MDCCL

@MDCCL History테이블 에 UPDATE 및 DELETE가 없다고 말했을 때 테이블 과 동일해야 Address합니까? 고객이 무언가를 주문한 다음 우편 번호 또는 도시 만 한 필드 만 변경하면 어떻게됩니까? 기존 주소를 삽입 History한 다음 Address테이블에 새로 삽입해야 합니다.
Mike Ross

1
OTOH, 고객 이 주어진 주소 에 대한 하나 이상의 정보를 변경하고자하는 경우, (a) Address수정이 이루어질 때까지“현재” 해당 행이 AddressHistory테이블에 삽입되고 또한 (b) ) 해당 Address행이 새 값으로 업데이트됩니다. 이 프로세스를 트랜잭션 내에서 단일 작업 단위로 수행하는 것이 유리합니다.
MDCCL

3

이 답변은 의견에서 질문으로 편집되었습니다.

한 가지 해결책은 주문 테이블의 주소 테이블에 FK를 사용하는 것입니다. 그러면 주문에 사용 된 주소가 표시되고 사용자의 현재 주소와 주소가 분리됩니다.

이 작업을 수행하려면 새 주소를 삽입하고 해당 새 주소를 User 테이블에 연결해야합니다. 이것은 주소가 한 번 작성되고 편집은 최종 사용자에게 환영이라는 것을 의미합니다. 연결을 사용자 테이블에서 타임 스탬프가있는 연결 테이블로 이동하여 사용자가 연결된 모든 주소의 기록을 효과적으로 저장할 수 있습니다. 그러면 편집 / 주소 기록이 제공되고 주소 테이블에서 변경 불가능한 데이터가 유지됩니다.

@MDCCL 은 다음 같이 말했습니다.

[주문 관련 데이터를 유지하기위한 하나의 테이블과 주소 정보를 유지하기위한 다른 테이블을 갖는 데이터베이스 구조를 구성해야합니다. 그리고이 두 엔티티 유형 사이의 다 대다 관계를 나타내는 테이블을 확실히 가질 수 있습니다. 사용자가 자신의 주소 속성을 변경할 수 있다면 그러한 수정 사항을 추적해야하므로 해당을 활성화해야합니다 AddressHistory. 이 게시물 은 후자의 측면과 관련 있습니다.

MDCCL은 또한 여기에서 사용자의 현재 주소를 찾는 방법에 대한 개요를 제공했습니다.

최신 버전의 기록 테이블을 가져 오려면 MAX(AuditedDateTime)해당 의 기록 테이블을 고려해야합니다 AddressId. 첫 번째 단계는 가능한 최상의 개념 및 논리적 배열을 모델링 / 설계하는 것이고, 두 번째 단계는 데이터를 삽입, 업데이트, 삭제 및 선택하는 적절한 방법을 찾는 것입니다.

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