如何定义来自不同来源的表之间的关系?

Posted

技术标签:

【中文标题】如何定义来自不同来源的表之间的关系?【英文标题】:How to define relationships between tables from differnt sources? 【发布时间】:2016-11-09 20:17:02 【问题描述】:

我需要对两个主要系统进行全面检修。从 BI 的角度来看,我创建了一些基线表,“用户”、“CRM 详细信息”、“电话详细信息”等。

我在理解表之间的关系是如何形成时遇到问题。

我将用户列表放入“用户”表中,并且需要在“电话详细信息”表中执行相同操作。我如何建立一种关系,它从用户中知道“约翰史密斯”=电话中的“约翰史密斯”?

我预计用户表中的键列将是“Id”,因此电话表中的“UserId”是“UserId”,但 UserId 是如何最终出现在 Telephony 表中的?

到目前为止我的代码:

CREATE TABLE Users
(
    Id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    Forename  NVARCHAR(50),
    Surname   NVARCHAR(50),
    Location  CHAR(50),
    Email     NVARCHAR(320),
    SCD_Start SMALLDATETIME,
    SCD_Stop  SMALLDATETIME,
    IsActive  BIT
)

INSERT INTO Users (Forename,Surname,Location,SCD_Start,SCD_Stop,IsActive)
VALUES ('Test1','Test1','TestL1','2016-11-08',NULL,1)
,('Test2','Test2','TestL2','2016-11-08',NULL,1)
,('Test3','Test3','TestL3','2016-11-08',NULL,1)
,('Test4','Test4','TestL4','2016-11-08',NULL,1)
,('Test5','Test5','TestL5','2016-11-08',NULL,1)
,('Test6','Test6','TestL6','2016-11-08',NULL,1)

CREATE TABLE Telephony
(
    Id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    Forename    NVARCHAR(50),
    Surname     NVARCHAR(50),
    OfficePhone VARCHAR(22),
    MobilePhone VARCHAR(22),
    SCD_Start   SMALLDATETIME,
    SCD_Stop    SMALLDATETIME,
    IsActive    BIT
)

【问题讨论】:

从电话表中删除名字和姓氏。这要求冗余和不一致。假设 Users 表中的 Id 是唯一性,将其用作 Telephony 表中的外键。可能重命名每个表中的 Id 列以表示更多含义(IE.UserId,TelephonyId) 根据以前的经验,Telephony DB 可以包含稍有不同的名称。用户表中的“Dan”和电话表中的“Daniel”。考虑到这一点,我应该将它们作为“TelForename”“TelSurname”还是其他方法包含在“用户”表中? 啊...抱歉...忘记您是从不同的来源获得这些的。 如果两个来源之间没有共同的唯一性,您可能无法了解它们之间的关系。 您的问题不清楚。请将 1. 如何编写查询何时需要 u.fname = t.fname 和 u.sname=t.sname 与 2. 如何确定给定每个表中的一行是否指代同一个人(或就此而言,一个表中的两行)来自 3. 如何添加前面给出的 id 列。 【参考方案1】:

对于这种特殊情况,您需要在 Telephony 表中引入一个外键来引用 Users 表中的 Id。

CREATE TABLE Telephony
        (Id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
        UserId int FOREIGN KEY REFERENCES Users(Id)
        Forename    NVARCHAR(50),
        Surname     NVARCHAR(50),
        OfficePhone VARCHAR(22),
        MobilePhone VARCHAR(22),
        SCD_Start   SMALLDATETIME,
        SCD_Stop    SMALLDATETIME,
        IsActive    BIT
)

一般来说,如果您更熟悉设计软件而不是设计数据库,那么深入研究领域建模和代码优先原则可能是个好主意。

【讨论】:

太好了,谢谢。我是一名 SAS 开发人员,但我也知道 SQL。基本上我现在必须从头开始创建一个数据集市。我不是软件、网络或其他数据库设计师,所以我对它如何工作的理解仅基于我在大型银行中看到它的运作方式。我明白你的帖子是什么意思,但我仍然有一个问题,一旦我将所有同事提交到“用户”表并开始向“电话”表提交信息,它如何“知道”用户 ID 信息?手动加载而不是通过任何前端加载,我认为这是我的问题。 使用 IDENT_CURRENT('Users') 插入行后,您可以获得当前身份。【参考方案2】:

基本上,只需在电话中添加与用户中的 ID 的类型 (INT) 匹配的另一列 - 可以将其称为 UserId(通常我会在它前面加上“f”,fUserId 只是这样一目了然提醒我它是和FK 而不是其他值)。然后运行这个命令:

alter table Telephony with check add constraint FK_Telephony_UserId foreign key(UserId)
references Users (Id)

现在添加到 Telephony 的任何记录必须具有匹配的 UserId。使用用户 ID 值进行查询,您只会得到他们的号码。

就是这样。

【讨论】:

感谢您的回复。我想我可能需要退后一步——最终我开始意识到,我的问题是我填充这些表的方法。 “用户”将通过从 CSV 导入数据来填充。 “电话”当然需要包含与用户相关的数据......所以我在这里的查询是如何在不亲自输入数据的情况下做到这一点?这是需要存储过程或其他东西以便同时更新两个表的地方吗? 另一种方法是先不要创建 FK,只需要结构和导入,整理并确保 ID 匹配,然后声明 FK - 这样约束就不会妨碍您 好的,所以我的理解基本上是通过 CSV 将我的导入到两个表中,假设现在两个表都有 100 人,幸运的是没有人有相同的名字。每个表都有一个简单的 Id,我想从用户获取 Id 到 Telephony 中的 UserId。我的问题是 如何 将该 ID 获取到 UserId?我是否加入指定名称作为键的表?还是我在这里遗漏了一些基本的东西,例如加载到用户中的每条记录都必须并行加载到电话中,因此 Id 到 UserId 的合并会自动发生? 好吧,如果名称是唯一的,那么加入应该可以工作。从各种来源导入时,我经常不得不想出创建解决方案 - 有时很难让事情匹配;) 那么一个合法的解决方案是将两个表实际连接在一起并在找到匹配用户时更新 UserId 字段?【参考方案3】:

按名称识别

大概在你的两个表中

PRIMARY KEY (forename, surname);

您必须决定何时用户行中的名称与电话中的某些行代表同一个人。也许是

Users.forename = Telephony.forename AND Users.surname = Telephony.forename

这是一个data cleansing/cleaning/scrubbing 问题。无论如何,假设有一个条件...

一张表代表一种关系。如果它是基本表或元数据表,DBA/设计人员会告诉您关系。如果是查询的结果,查询会告诉您关系。

因此,当您有一个涉及两个表的查询并且表中的行按名称引用人员并且您希望由两行命名的人员引用相同的人时,您将要求 ... 添加到查询中。

添加 ID

我们分配唯一 ID 来引用实体 for many reasons。例如,因为您不想更改名称的许多地方,否则当一个人更改其姓名时会出现该名称。例如,这样您的查询可以只涉及 id 上的相等而不是多列。例如,通过使用较小的(整数)标识符而不是较大的(varchar)标识符,您可以减少实现空间(在表和索引中)和时间(在比较和索引中),但代价是增加实现空间(更多表)和时间(更多连接)。例如,您可以将许多名字与同一个人相关联。请注意,任何设计决策都需要权衡取舍。

假设您想要 id:首先每个 SQL Server: how to add new identity column and populate column with ids? 为每个表添加一个 id 列“并且该列将被创建并自动填充”。如果您从没有 id 的表开始:

ALTER TABLE Users ADD Id INT IDENTITY(1,1) PRIMARY KEY
ALTER TABLE Telephony ADD Id INT IDENTITY(1,1) PRIMARY KEY

然后根据Update a table using JOIN in SQL Server? 将每个电话 id 设置为上面每个“...”具有相同名称的用户 id:

UPDATE t
SET t.Id = u.Id
FROM Users as u
INNER JOIN Telephony as t
WHERE ...

现在您不需要或不希望在 Telephony 中使用名称:

DROP FORENAME, SURNAME FROM Telephony

声明外键

“关系”(表之间)也用于“外键约束”。您需要从 Telephony 到 Users 的 FK。你可能需要 id。但是查询不需要约束。 (元数据有一个关系表“从表 TF 列列表 LF 到表 TT 列列表 LT 有一个 fk”,也可以表示为“表 TF 列列表 LF 的值列表显示为表 TT 列列表的值列表LT".) 最终电话,

FOREIGN KEY (forename, surname) REFERENCES Users (forename, surname);

对于新表,

FOREIGN KEY (Id) REFERENCES Users (Id)

附言

约束实际上不是关系,它是元数据关系的实例,即参与元数据关系的某些值的一种情况。它陈述了关于基表中的值的事实。但同时,因为每个基表都保存着满足某种应用关系的行,所以它根据它所提到的基表的应用关系,陈述了每个应用情况的一个事实。当表 T 表示表示为 E_T 的关系时,FK 约束tf (c) REFERENCES tt (c) 表示,“对于所有其他列的某些值,E_tf 意味着 E_tt”。

【讨论】:

以上是关于如何定义来自不同来源的表之间的关系?的主要内容,如果未能解决你的问题,请参考以下文章

MariaDB 根据列值连接来自不同数据库的表

如何内部连接来自不同数据上下文的表? [复制]

使用 Play with Scala 和 Slick 在不同文件上的表之间建立一对多关系

如何合并 SQL Server 中具有映射到通用描述的不同列标题的表?

如何连接来自两个不同 PDO 对象的表?

如何将不同数据上下文的表进行内部连接?[重复]