简体   繁体   中英

InnoDB: Copying a number of records along with their tag memberships

Foreign keys might be appropriate to this problem/solution. However, I have inherited this code and db, which do not use foreign keys, and so it would be difficult to add them. If absolutely necessary I can do it, but I'd prefer not to.

Let's pretend that I have a very simple set of tables in an InnoDB database that are used to store a bunch of jokes, each of which belongs to particular group and may have one or more tags associated with it. I am using PHP/MySQLi to do the work. Let's say the tables look like so:

GROUPS
id (int, primary, auto_inc)  |  group_name (varchar[64])
============================================================
1                               knock, knock jokes
2                               one-liners

JOKES
id (int, primary, auto_inc)  |  group_id (int)  |   joke_text (varchar[255])
=============================================================================
1                               1                   interrupting cow. inte-MOO!

TAGS
id (int, primary, auto_inc)  |  tag_text (varchar[255])
=============================================================================
1                               explicit
2                               hilarious

JOKE_TAGS
id (int, primary, auto_inc)  |  joke_id (int)   |   tag_id (int)
=============================================================================
1                               1                   1

Even though it makes no sense in the context of these jokes , let's just say that the user has the option to copy the jokes from one group to another. Thanks to users' help on this site, I have figured out that the easiest way to do that would be something like the following:

INSERT INTO jokes (group_id,joke_text)
SELECT '$dstGroupID', r2.joke_text FROM jokes AS j2
WHERE j2.group_id = '$srcGroupID';

That seems to work just fine. However, I am completely lost as to how I can efficiently copy over the tag memberships. For instance, if I was to copy the jokes from group.id=1 to group.id=2 (using the sample data shown above), I would want the JOKE_TAGS table to look like so:

JOKE_TAGS
id (int, primary, auto_inc)  |  joke_id (int)   |   tag_id (int)
=============================================================================
1                               1                   1
2                               2                   1

For the life of me, I simply cannot figure out a way to do this without throwing away the SQL above and simply iterating through every single joke that is being copied, with the logic looking something like this:

  • Pull out a joke's information
  • Pull out that joke's tag memberships
  • Insert a new record into JOKES with the pulled out info from above
  • Grab the id of the newly inserted joke
  • Insert a new record into JOKE_TAGS , using the id grabbed above

This is obviously WILDLY inefficient when compared to the 'copying' SQL listed above. If anyone can suggest a more efficient solution, I'd be most appreciative.

You're already using foreign keys, even if they're not being enforced. What you're describing is a fundamental change in your data structure. Going from 1:1 to 1:n: one joke existing in one group, to one join existing in MULTIPLE groups.

As such, the normal fix would be to move that group_id field out of the jokes table and into a link table:

jokes <-> joke_groups <-> groups

in which case, a simple "copy" would involve inserting a new record in the link table:

 (joke #1, group #7) // existing joke/group link
 (joke #1, group #3) // "copying" the joke into group #3

If you CAN'T change the schema to accomodate the change in structure, then you will have to manually copy the joke around:

 a) get contents of joke record
 b) insert copied data back into joke record to create a NEW joke
 c) get ID of new record
 d) copy all tags from old id, insert with new linkages to new joke's ID

normally this'd be as simple as a couple INSERT INTO ... SELECT FROM -type queries, but MySQL does not let you select from the same table as you're inserting into, so a round-trip through the client is required.

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