用于规范化现有(多对多)数据的SQL

时间:2013-02-07 10:50:42

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

要点:
请参阅下面的详细信息我正在将[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帖子和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表?

1 个答案:

答案 0 :(得分:4)

假设有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;

这是MS SQL Server的完全正常SQL Fiddle example。其他DBMS应该表现得相似。顺便说一下,你应该适当标记你的问题,以表明你的DBMS。