How I Seamlessly Merged Two Tasks Pro™ Databases

I’ve long maintained two Tasks Pro databases. This made little sense—even though one of them ostensibly had lots of people helping me out in my hobby involved, I was the main one using it. I finally got to neglecting the hobby database, to lots of bad effects. BAD effects. So I decided to merge them. This took some planning and some execution, so I wrote it up as I did it as a tutorial for someone else crazy enough to make the same move. 🙂


First, I backed up both databases. Makes sense, no? Folks forget that, though. So, back up your stuff, man.

Next, I went into the secondary source database—the one I’d be merging from, not the one I’d be merging into. Here’s what I had to fix:

  • Overlapping users.
  • Overlapping groups.
  • Overlapping tasks.

The first two are fairly simple. If the overlap isn’t going to cause an issue—if user #1 in both databases is the same, as it is in my case—just delete that user in the target db, but don’t delete anything else to do with that user. For any users that overlap and aren’t the same person, you do need to change that user. Assign them a new ID but otherwise leave them the same. In my case, my friend Bryan was user #2 in my hobby db, but my work user [tied to my work email address, because there are a lot of tasks for work that I’ll only do at work, so it makes sense to have the two users] was that same #2 in the personal db. I looked for the next hole in the tp_users table to see where I could slot Bryan in, and that was #7.

Fixing Users

Here’s where all you have data that may need updating:

  1. tp_favorites: user_id. This was pretty simple: UPDATE tp_favorites SET user_id = 7 WHERE user_id = 2;.
  2. tp_files: added_by and modified_by. Again, the SQL is pretty simple: UPDATE tp_files SET added_by = 7 WHERE added_by = 2; UPDATE tp_files SET modified_by = 7 WHERE modified_by = 2;.
  3. tp_mailboxes: I have no entries here at all. The relevant fields appear to be task_creator, task_owner, creator, and modifier, but since I have no data for the table, I can’t confirm that without digging into the PHP. Alex can feel free to correct me. [I actually need to think about the mailboxes functionality: I’ve got to think that using it for incoming bug reports might be a good idea.]
  4. tp_tasks: creator and modifier. I think you can guess what the SQL looks like: UPDATE tp_tasks SET creator = 7 WHERE creator = 2; UPDATE tp_tasks SET modifier = 7 WHERE modifier = 2;.
  5. tp_templates: creator and modifier come up yet again. UPDATE tp_templates SET creator = 7 WHERE creator = 2; UPDATE tp_templates SET modifier = 7 WHERE modifier = 2;.
  6. tp_user_groups: user_id. UPDATE tp_user_groups SET user_id = 7 WHERE user_id = 2;.
Fixing Groups

As easy as fixing users was, fixing groups was even easier. I had only two groups in the target database—one for work and one for my music stuff. I have a lot more ideas for groups, but I’ve been holding off on those because I wanted to get the merger done first. So that meant any group labeled #1 or #2 in the source db needed to be changed. Predictably, I had both. So group #1 in the source db became group #5, and group #2 became group #8. Here’s how that got fixed with SQL:

  1. tp_task_groups: UPDATE tp_task_groups SET group_id = 5 WHERE group_id = 1; UPDATE tp_task_groups SET group_id = 8 WHERE group_id = 2;.
  2. tp_user_groups: UPDATE tp_user_groups SET group_id = 5 WHERE group_id = 1; UPDATE tp_user_groups SET group_id = 8 WHERE group_id = 2;.

See, I told you that was easy.

Fixing Tasks

Here is the hard one. You’re merging two databases, and chances are that the main data—task IDs—are gonna be the same. :sigh: Fear not! The easy solution is pretty simple.

  1. Look in the target db [where you’re merging into] and find its largest task ID. In my case, the next autoindex was 43,621. This told me an easy, easy, easy fix: increment every tasks in the source database by 50,000. This guaranteed that all tasks in the source db would be 50,000+, while all tasks in the target db would be <50,000. [This presumes that you could have a user working in the target db at the time. If I’d been very close to 50,000, I might have gone to 55,000 or something—well, I wouldn’t have had to, because in the target db, I own both users. But this is how you might have to do it.]
  2. The MySQL documentation for the UPDATE statement gives this example: UPDATE t SET id = id + 1 ORDER BY id DESC;. That’s smart code execution: it does the update to the largest ID first, which prevents situations where your offsets would overlap. Consider a situation where you’re using an offset of 1000 but have 4,000+ tasks in the source db. When you update task 1,732, it’ll become 2.732—and could mean that two tasks have the same ID! Bad juju, man!.

So let’s look at what has to get changed, and what SQL does it, shall we?

  1. tp_tasks: UPDATE tp_tasks SET id = id + 50000 ORDER BY id DESC; UPDATE tp_tasks SET parent = parent + 50000 ORDER BY parent DESC WHERE parent > 0; UPDATE tp_tasks SET template = template + 50000 ORDER BY template DESC; UPDATE tp_tasks SET recur_source = recur_source + 50000 ORDER BY recur_source DESC;. It is okay to take a deep breath before kicking this one off and exhaling when it’s done. Take a note of how many rows there are in tp_tasks before you start; you should get the same number of affected rows for the first two, but the template and recur_source are going to be far smaller because those are used less often. If you recur a lot of tasks—and I do!—you’ll see a lot of rows affected.
  2. tp_favorites: UPDATE tp_favorites SET task_id = task_id + 50000 ORDER BY task_id DESC;. This is an easy one because it’s just at two-column table. Note that, at this point, you’ve edited both columns with UPDATEs, but having done so separately. You could, if you wanted, combine both the statements into one query setup if you want. I’ve shown it this way here because of how I’ve done this, and because I’ve written this tutorial as I’ve done the updates.
  3. tp_files: UPDATE tp_files SET task_id = task_id + 50000 ORDER BY task_id DESC; UPDATE tp_files SET id = id + 50000 ORDER BY id DESC;. As with tp_templates below, you’ve got an id here that you also need to offset. I’ve chosen to offset that by the 50000 number because, well, it’s easy.
  4. tp_task_groups: UPDATE tp_task_groups SET task_id = task_id + 50000 ORDER BY task_id DESC;.
  5. tp_templates: UPDATE tp_templates SET task_id = task_id + 50000 ORDER BY task_id DESC; UPDATE tp_templates SET id = id + 50000 ORDER BY id DESC;. Now, you may have balked at my tp_tasks statement where I changed the template line, and you may be balking here that I’m changing the id of the templates table. Does this have to happen by the $id_offset? No, not really. Admittedly, you could look up how many templates are in the target db and offset it by that amount. That said, it’s just a number. As long as you’re consistent, you’re okay.


Now you’ve prepped the source database for merging. If you do a SQL dump of that data at this point, everything you have is guaranteed to not overwrite anything in the target database. Still, you better have backed up the data, dammit. Why? Simple: you could have made a mistake somewhere. You could have overlooked something. Backups mean never having to say that you’re sorry.

Here’s how I did the merge:

  • tp_config: I ignored it. This is a task, user, and group-independent table. There is no sense in editing any data in this table at all.
  • tp_favorites: I ran the MySQL dump on the table, pared the data down to only the INSERT statements. I had a handful of favorites, so I did this all in phpMyAdmin’s browsers, never downloading an SQL file locally.
  • tp_files: I dumped from MySQL and imported via phpMyAdmin, but with a lot of files, this will be problematic. If that table is large for you, use mysqldump and mysql -u[user] -p[password] [database] < tp_files.sql on the command line. Save yourself the frustration.
  • tp_groups: This was done as tp_favorites was.
  • tp_tasks: This was done as tp_files was. Again, doing the insert via the command line might be the way to go.
  • tp_task_groups: This was done as tp_files was because of the size.
  • tp_users: This was done as tp_favorites was.
  • tp_user_groups: This was done as tp_favorites was.

Hopefully that will guide you as you progress. If you need advice or have questions, leave a comment.