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:
JOKES
with the pulled out info from above 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.