如何从多个可为空的列中创建备用键

时间:2019-10-28 16:40:56

标签: sql-server database-design

我有一个包含三个表的数据库,分别称为SaleStoreHubStore的每个实例都引用Hub的实例,尽管在Hub表中可能没有引用Store的实例。在大多数情况下,Sale的实例将引用Store的实例(因此可以映射到Hub的实例。)但是在某些情况下,Sale将直接引用Hub表。

此关系模型如下:商店由中心存储(商店和中心都是位置),并且大多数销售发生在商店中,但它们也可以在中心发生。

在不存在Sale-Hub关系的简化版本中,我可以轻松地使StoreID成为Sale表的主键的一部分,是我在这里想要做的,除了StoreID偶尔会为空(当销售发生在中心而不是商店时)

因此,Sale表中的示例可能如下所示:

SaleID    SaleDate    StoreID    HubID    Quantity
     1  2012-05-16          1     NULL         100
     2  2014-09-27          2     NULL          99
     3  2018-02-01       NULL        9          30
     4  2019-11-12         17     NULL         207

StoreHub表将包括位置信息以及一些商店和中心特定字段。

问题是如何处理为Sale表创建一个好的备用键(SaleID是我的替代主键。)从理论上讲,应该根据日期和位置确定销售。但是我有两个位置字段,并且它们都是可为空的。我想知道是否可以使用唯一索引来处理此问题?还是可以以某种方式使用检查约束?还是中间位置表?

此外,作为后续操作,假设我还有一个SuperHub表(想象HubSuperHub就是StoreHub。)如果我想向SuperHubID表中添加Sale字段,这将如何影响事情?使用3个以上可为空的字段时,不检查约束/唯一索引是否开始失控?

这可能是ERD的样子:

Possible ERD

编辑:为澄清起见,鉴于“位置信息”是在几个不同的表之间分割的,因此,我试图找出将位置信息作为Sale表的备用键的一部分的最佳方法。 Sale表的主键只是代理键SaleID。)尝试将所有位置表包括在备用键中会导致Null出现在键中(请参阅Sale中的示例表格。)解决此问题的最佳方法是什么?

编辑2:好的,这里还有一些澄清。我包括表格定义等。

--Table Defs
CREATE TABLE Sale (
SaleID int NOT NULL IDENTITY(1, 1),
SaleDate date NOT NULL,
StoreID int NULL,
HubID int NULL,
Quantity int NOT NULL);
-- StoreID and HubID are nullable since a sale can occur at one or the other
-- Is there a better way to organize this?
-- @PeterHe mentioned Category/Subcategory model

CREATE TABLE Store (
StoreID int NOT NULL IDENTITY(1, 1),
StoreNumber int NOT NULL,
Customer nvarchar(20) NOT NULL,
Address nvarchar(50) NOT NULL,
HubID int NOT NULL);

CREATE TABLE Hub (
HubID int NOT NULL IDENTITY(1, 1),
HubNumber int NOT NULL,
Customer nvarchar(20) NOT NULL,
Address nvarchar(50) NOT NULL);

--PKs
ALTER TABLE Sale 
    ADD CONSTRAINT PK_Sale PRIMARY KEY CLUSTERED (SaleID);

ALTER TABLE Store 
    ADD CONSTRAINT PK_Store PRIMARY KEY CLUSTERED (StoreID);

ALTER TABLE Hub  
    ADD CONSTRAINT PK_Hub PRIMARY KEY CLUSTERED (HubID);

--FKs
ALTER TABLE Sale 
    ADD CONSTRAINT FK_Sale_Store 
        FOREIGN KEY (StoreID) REFERENCES Store (StoreID)
            ON UPDATE NO ACTION
            ON DELETE NO ACTION;

ALTER TABLE Sale 
    ADD CONSTRAINT FK_Sale_Hub 
        FOREIGN KEY (HubID) REFERENCES Hub (HubID)
            ON UPDATE NO ACTION
            ON DELETE NO ACTION;

ALTER TABLE Store 
    ADD CONSTRAINT FK_Store_Hub 
        FOREIGN KEY (HubID) REFERENCES Hub (HubID)
            ON UPDATE NO ACTION
            ON DELETE NO ACTION;

--AKs
ALTER TABLE Store
    ADD CONSTRAINT AK_Store UNIQUE (StoreNumber, Customer);

ALTER TABLE Hub
    ADD CONSTRAINT AK_Hub UNIQUE (HubNumber, Customer);

ALTER TABLE Sale
    ADD CONSTRAINT AK_Sale UNIQUE (SaleDate, StoreID, HubID); 
    --issue here is StoreID and HubID are nullable since sale could occur at either

1 个答案:

答案 0 :(得分:1)

最好将一个实体定义为包括所有可以进行销售的组织,例如sale_org(   sale_org_id int不为null,   sale_org_type tinyint也不为null,-1,存储; 2,花鼓,3,超级花鼓   地址 ... ) 您仍然可以使用Store和Hub等表(无地址)来定义关系。或仅一个表用于层次结构sale_org_hierarchy定义关系:sale_org_id和parent_sale_org_id

销售表仅引用store_hierarchy表。