来自两个不同表中的任一个的参考密钥

时间:2011-08-14 12:57:50

标签: sql database-design reference


我有以下两个表:

employees(id, name, address, designation, salary, phone, email...)

business_men(id, business_type, business_name, turn_over, phone, email,...)

现在我有另一张桌子clients。我的客户可以是employeebusiness_man类型。 所以我有如下的客户端表:

Clients(id, code_number, type, reference_id)

类型字段可以存储'employee'或'business_man',而reference_id是Type字段中提到的表的id。在许多地方,整个应用程序都使用客户端的ID。

我的问题是:

  1. 我做得对吗?
  2. 有更好/更有效的方法吗?
  3. 如何使用单个SQL查询获取客户端的完整详细信息(给定客户端ID)?

4 个答案:

答案 0 :(得分:3)

enter image description here

请注意,ClientID只是PersonID的角色名称(ClientID = PersonID)。

有了这个,你现在可以创建几个视图,让生活更轻松,这里有一些你可以使用的视图:

  • 员工
  • 商人
  • 客户
  • EmployeeClients
  • BusinessClients

答案 1 :(得分:2)

我们使用的略微不同的方法是创建一个抽象实体表。其目的是为所有具体实体提供唯一的序列号。简化示例如下 entity structure

--CREATE SCHEMA user893847

CREATE TABLE user893847.BASE_ENTITY
(
    entity_id int identity(1,1) NOT NULL PRIMARY KEY
)

CREATE TABLE user893847.EMPLOYEE
(
    entity_id int NOT NULL PRIMARY KEY
,   name_first varchar(30) NOT NULL
,   name_last varchar(30) NOT NULL
)

CREATE TABLE user893847.BUSINESS_PERSON
(
    entity_id int NOT NULL PRIMARY KEY
,   company_name varchar(30) NOT NULL
)

CREATE TABLE user893847.ADDRESS
(
    entity_id int NOT NULL
,   address_line1 varchar(70) NOT NULL
)

我们的插入方法将插入BASE_ENTITY表并捕获生成的id值。具体表(employee,business_person)会将结果id存储为PK。其中一个主要原因是我们的业务,营销,可以让我们移动实体表,因为我们了解更多关于他们或重新分类个人。如果实体478在整个域中是“相同的”,我们发现它简化了逻辑。由于在每个表中重新定义了一个数字,而不是必须根据设计中的类型进行查询,所以您只查询连接到表,如果行返回,则 该类型。

-- your query
SELECT 
    C.*
,   E.*
    -- build out a null set of colums for business men
,   NULL AS id
,   NULL AS business_type
FROM
    Clients C 
    INNER JOIN 
        Employees E 
        ON E.id = C.reference_id 
WHERE 
    C.type = 'employees'
UNION ALL

SELECT 
    C.*
    -- repeat the build out for faking the employee columns
,   NULL AS id
,   NULL AS name
,   ...
,   BM.* 
FROM 
    Clients C 
    INNER JOIN 
        business_men BM 
        ON BM.id = C.reference_id 
WHERE 
    C.type = 'employees'



-- my aproach
SELECT 
    C.*
,   E.*
    -- build out a null set of colums for business men
,   NULL AS id
,   NULL AS business_type
,   ...
FROM
    Clients C 
    INNER JOIN 
        Employees E 
        ON E.id = C.reference_id 
UNION ALL

SELECT 
    C.*
    -- repeat the build out for faking the employee columns
,   NULL AS id
,   NULL AS name
,   ...
,   BM.* 
FROM 
    Clients C 
    INNER JOIN 
        business_men BM 
        ON BM.id = C.reference_id 

如果您对设计有疑问,请与我们联系

答案 2 :(得分:1)

在单个查询中执行此操作不应该是主要目标,您应该考虑正确的设计和适当的规范化级别的表。

基本上 - 查询应该适合设计但不能相反。

尝试这种方式,创建以下表格:

-- all common fields for any user (user can be in one group in one time)
USERS(Id, GroupId, Name, Phone, Address)

--User groups like Employee, BusinessMan
USER_GROUPS(Id, Name)

-- The Permanent employees accounting information
ACCOUNTING_PERMANENT(Id, UserId, Designation, Salary)

-- The Business man accounting information
-- Perhaps you can use PE ('private employment') instead 'Business Man'
ACCOUNTING_BUSINESS(Id, UserId, Name, TurnOwer, BusinessType)

如果某个企业可以由许多PE(业务人员)拥有,则再创建一个表并从UserId表中删除ACCOUNTING_BUSINESS

-- Relation between USERS and ACCOUNTING_BUSINESS tables
USERS_BUSINESS(Id, UserId, BusinessId)

答案 3 :(得分:-1)

你的设计很好。

如果employeebusiness_man之间存在许多共同元素,那么您可能需要引入sllev所暗示的超类型/子类型模型。如果没有很多共性,那么超类型/子类型模型可能对概念模型有用,但对于物理模型则不切实际。

您在设计中所做的是隐式使用一种超类型/子类型,其中除了您调用的code_number和集成标识符({{1}之外,员工和商务人员之间没有共同属性。 }})。您的分区属性为Clients.id

要简化单个查询中的信息检索,请定义一个视图,该视图提供Clients.typeEmployees之间的联接的UNION以及ClientsBusiness_Men之间的联接

这将为您提供看起来像一个扁平的表,同时包含两种类型的客户端。