简体   繁体   中英

SQL: vertically split table and create/populate keys, foreign key relationship

I would like to vertically split an existing (already filled with data).

Say my starting table ( trip ) looks like this:

  ID    Person        Age       Trip_to           Date      
 ...     Alice        21        Los Angeles       2015-04-01     
 ...     Bob          35        New York          2015-03-15   
 ...     Bob          35        Chicago           2015-03-20 
 ...     Bob          35        San Francisco     2015-03-29 
 ...     Carol        29        Miami             2015-03-30 
 ...     Carol        29        Boston            2015-04-05

I would like to split this table into two tables, as it should be, one each for person and trip .

When copying each unique person into a table person , I want the automatically created uniqueidentifier column in that table person.pId (the primary key) to be copied into a newly created uniqueidentifier column trip.personid in the original table and turn that into a foreign key. (I would then delete the trip.person and trip.age column from the original table, and have the data structured as I want them.)

I thought I could use a trigger for that when I insert the person rows into the new table, like so:

CREATE TRIGGER tr_person
        on person
        after INSERT
        as
        begin
       UPDATE Trip 
       SET personId=(SELECT i.pId from inserted i)
       WHERE person=(SELECT i.person from inserted i) and age=(SELECT i.age from inserted i)
END

However, I get this:

    Subquery returned more than 1 value. 
This is not permitted when the subquery follows =, !=, <, <= , >, >= 
or when the subquery is used as an expression.

Apparently the trigger only executes after all (potentially multiple!) inserts have been carried out, and by that time a query on inserted is no longer allowed for my SET statement.

I also thought about using an OUTPUT clause on the INSERT statement, but that wouldn't work either

Insert into person (Driver, Age)
OUTPUT inserted.pId INTO trip.personId WHERE trip.person=inserted.person AND trip.Age=inserted.Age
(Select DISTINCT Person, Age FROM Trip)

So I am wondering now, am going about this all wrong? Is there another way to automagically create the keys and relationships between the two newly split tables?

EDIT Desired result: Table trip:

  ID    Trip_to           Date            PersonId
 ...     Los Angeles       2015-04-01     xxxx1
 ...     New York          2015-03-15     xxxx2
 ...     Chicago           2015-03-20     xxxx2 
 ...     San Francisco     2015-03-29     xxxx2 
 ...     Miami             2015-03-30     xxxx3 
 ...     Boston            2015-04-05     xxxx3

Table person

  pId    Person       Age         
 xxxx1   Alice        21         
 xxxx2   Bob          35              
 xxxx3   Carol        29 

(The ID fields should all be uniqueidentifiers, of course)

Here is an idea:

First, you insert all distinct Person from Trip table to Person table:

CREATE TABLE Person(
    pID UNIQUEIDENTIFIER PRIMARY KEY,
    Person VARCHAR(10),
    Age     INT
)

INSERT INTO Person
    SELECT 
        NEWID(), Person, Age
    FROM(
        SELECT DISTINCT Person, Age FROM Trip
    )t

Then, add a new FK column to Trip table PersonId which references pId from the Person table:

ALTER TABLE Trip 
    ADD PersonId UNIQUEIDENTIFIER 
    FOREIGN KEY(PersonId) REFERENCES Person(pId)

Then, UPDATE the newly added FK column with values from Person table using a JOIN on Person and Age :

UPDATE t
    SET PersonId = p.pID
FROM Trip t
INNER JOIN Person p
    ON p.Person = t.Person
    AND p.Age = t.Age

Finally, you can drop Person and Age from Trip table:

ALTER TABLE Trip DROP COLUMN Person
ALTER TABLE Trip DROP COLUMN Age

RESULT

Person

pID                                  Person     Age
------------------------------------ ---------- -----------
35815766-1634-45FF-A3F6-8194B43F3F65 Alice      21
8EB3A7CC-CED1-4DBC-98B0-99D325BC7F67 Bob        35
D0EDCEA8-3825-4693-9352-BF7A04AEFCB2 Carol      29

Trip

ID                                   Trip_to              Date       PersonId
------------------------------------ -------------------- ---------- ------------------------------------
77357A57-FAAE-43DE-923E-219038B8641E Los Angeles          2015-04-01 35815766-1634-45FF-A3F6-8194B43F3F65
C1B64E81-D30A-46A9-A868-1D92C4B64B8C New York             2015-03-15 8EB3A7CC-CED1-4DBC-98B0-99D325BC7F67
21F3614A-8E76-4A64-8A0B-815D5343FC26 Chicago              2015-03-20 8EB3A7CC-CED1-4DBC-98B0-99D325BC7F67
E1DB1926-4268-4BFA-B5E0-DA603DA8E1B7 San Francisco        2015-03-29 8EB3A7CC-CED1-4DBC-98B0-99D325BC7F67
F50E45E6-E689-444B-96C1-F936CA6F3D2A Miami                2015-03-30 D0EDCEA8-3825-4693-9352-BF7A04AEFCB2
C2FA7073-79D7-42E8-B2C8-6EEDBC374002 Boston               2015-04-05 D0EDCEA8-3825-4693-9352-BF7A04AEFCB2

Side note: You should not be storing the Age of the person. Instead, store the birthdate and compute the age on the fly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM