【问题标题】:SQL to normalize existing (many-to-many) dataSQL 规范化现有(多对多)数据
【发布时间】:2013-01-22 20:17:28
【问题描述】:

总结:
详情见下文。为了便于阅读,我将[unanswered] 多对多问题复制到顶部:

    Given the "Input" table, what is the SQL to generate the 3rd "Output"
    table (Person_plays_Instrument)?



当前输入(1 个表格):

OriginalTable:
PersonId PersonName Instrument_1 Instrument_2 Instrument_3 MailingAddress HomePhone
--------|----------|------------|------------|------------|--------------|------------
1        Bob        Violin       Viola        Trumpet      someplace      111-111-1111
2        Suzie      Cello        Flute        <null>       otherplace     222-222-2222
3        Jim        Violin       <null>       <null>       thirdplace     333-333-3333

所需的输出(3 个表):

Person:
Id Name   MailingAddress HomePhone
--|------|--------------|------------
1  Bob    someplace      111-111-1111
2  Suzie  otherplace     222-222-2222
3  Jim    thirdplace     333-333-3333

Instrument:
Id Name
--|-------
1  Violin
2  Cello
3  Viola
4  Flute
5  Trumpet

Person_plays_Instrument:
PersonId InstrumentId
--------|------------
1        1
1        3
1        5
2        2
2        4
3        1

详情:

我有一个单一的平面 SQL 表,它最初是一个电子表格。我想让它正常化。我将把它分成每个表的 1 个问题。

问题 1 和 2 已回答,但我将保留它们以防其他人发现它们有帮助。

问题:

问题 #1[answered]
如何生成 Person 表?

答案 #1
This 精彩的帖子让我成功了 2/3。对于一对多表,我已经准备好了。代码如下:

[add autonumber field to OriginalTable, name it PersonId]
[create empty Person table with Id, Name, MailingAddress, HomePhone fields]

INSERT INTO Person (Id, Name, MailingAddress, HomePhone)
  SELECT o.PersonID, o.PersonName, o.MailingAddress, o.HomePhone
  FROM OriginalTable as o
  WHERE o.PersonName Is Not Null;

问题 #2[attempted](@Branko 在接受的答案中提供了更好的版本
如何生成 Instrument 表?

答案 #2
再次,一对多。起初,多列让我难过。
解决方案分为两部分:

  • 我只需要对每一列重复一次 INSERT 命令。
  • 使用 this post 和 IN 运算符,我可以每次检查以确认我没有插入该值。

代码如下:

[create empty Instrument table with Id[autonumber], Name fields]

INSERT INTO Instrument (Name)
  SELECT Distinct o.Instrument_1
  FROM OriginalTable as o
  WHERE o.Instrument_1 Is Not Null
  AND o.Instrument_1 Not In (SELECT Name from Instrument);

INSERT INTO Instrument (Name)
  SELECT Distinct o.Instrument_2
  FROM OriginalTable as o
  WHERE o.Instrument_2 Is Not Null
  AND o.Instrument_2 Not In (SELECT Name from Instrument);

INSERT INTO Instrument (Name)
  SELECT Distinct o.Instrument_3
  FROM OriginalTable as o
  WHERE o.Instrument_3 Is Not Null
  AND o.Instrument_3 Not In (SELECT Name from Instrument);

问题 #3[unanswered]
如何生成 Person_plays_Instrument 表?

【问题讨论】:

  • OriginalTable.PersonID吗?
  • 是的,对不起。我在“[将自动编号字段添加到 OriginalTable,将其命名为 PersonId]”位中提到了它。实际上,我故意将其从示例中删除,因为添加自动编号字段是我在 Q#1 中链接到的答案帖子中的主要步骤之一。回想起来,这让事情变得更加混乱。为了清楚起见,我将对其进行编辑

标签: sql sqlite ms-access many-to-many normalization


【解决方案1】:

假设有OriginalTable.PersonID,您没有向我们展示,但您自己的答案#1 暗示了它,答案#3 可以简单地表示为:

INSERT INTO Person_plays_Instrument (PersonId, InstrumentId)
SELECT PersonID, Instrument.Id
FROM
    OriginalTable
    JOIN Instrument
        ON OriginalTable.Instrument_1 = Instrument.Name
        OR OriginalTable.Instrument_2 = Instrument.Name
        OR OriginalTable.Instrument_3 = Instrument.Name;

顺便说一句,有一种更简洁的方式来表达答案#2

INSERT INTO Instrument (Name)
    SELECT *
    FROM (
        SELECT o.Instrument_1 I
        FROM OriginalTable as o
        UNION
        SELECT o.Instrument_2
        FROM OriginalTable as o
        UNION
        SELECT o.Instrument_3
        FROM OriginalTable as o
    ) Q
    WHERE I IS NOT NULL;

这里有一个完全可用的SQL Fiddle example 用于 MS SQL Server。其他 DBMS 的行为应该类似。顺便说一句,您应该适当地标记您的问题以指示您的 DBMS。

【讨论】:

  • 我对这个答案感到敬畏。它完全按照预期工作。此外,SQL Fiddle 的链接和我的答案#2 的改进代码也很漂亮。不能感谢你。只希望我有多个投票按钮:)
  • 作为后续:我重新标记了您建议的方式。我还想再次感谢您的 SQL Fiddle 示例的彻底性。我通常是一个java程序员;仍然是一个 SQL 新手。在过去的 10 分钟里,我从您的示例中学到了更多关于 SQL 的知识,而不是在一周的教程网站和谷歌搜索中。再次感谢!
  • @Bukov 不客气!但是我仍然没有看到任何标签,例如sql-serveroraclepostgresqlmysql...
  • @Bukov (a) 这只是 MS SQL Server 语法的一个特点——它要求命名所有子查询(即使该名称并未真正在任何地方使用)。其他 DBMS 可能允许您省略它。
  • @Bukov (b) WHERE 子句存在于 outer 查询的级别,因此它适用于从内部查询返回的所有行 - 查看括号 ( 和) 有组织。换句话说:首先内部查询将所有行合并在一起,然后外部查询从所有这些行中过滤掉 NULL。您可以通过在内部查询中重复 WHERE 3 次来达到相同的效果(此时您可以完全省略外部查询),但是如果您不必重复某些内容,为什么要重复呢?
猜你喜欢
  • 2018-03-24
  • 1970-01-01
  • 2013-04-19
  • 2011-04-05
  • 2016-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-04
相关资源
最近更新 更多