Reputation: 140
I'm transferring data from db to another. The original table has the following structure (where key contact
is boolean):
+------------+-----------+-------------+
| contact_id | school_id | key_contact |
+------------+-----------+-------------+
| 1 | 1 | 1 |
| 2 | 2 | 0 |
| 3 | 2 | 1 |
| 4 | 2 | 1 |
| 5 | 3 | 0 |
+------------+-----------+-------------+
I'd like to get it into the following shape where display_order
is a composite unique index with school_id
:
+------------+-----------+---------------+
| contact_id | school_id | display_order |
+------------+-----------+---------------+
| 1 | 1 | 1 |
| 2 | 2 | 3 |
| 3 | 2 | 1 |
| 4 | 2 | 2 |
| 5 | 3 | 1 |
+------------+-----------+---------------+
And the logic is if key_contact = 1
then display_order
should be 1, unless a contact_id
with the same school_id
already has a display_order
with the value of 1, then it should insert the next incrementally available value that would be unique to the school_id
. I'd then like to insert all contacts where key_contact = 0
assigning the next available key_contact
integer unique to the school_id
.
I've created a unique index for the two columns:
UNIQUE KEY `contact_school_display_order_school_id_unique` (`display_order`,`school_id`)
I've tried using INSERT... ON DUPLICATE KEY UPDATE
but I really want something that will, on duplicate key, increment the value of the insert value to the next integer that is unique to the school_id
.
Any pointers would be greatly appreciated.
Upvotes: 0
Views: 52
Reputation: 31772
Migrate from table contacts1
to contacts2
insert into contacts2
select
c1.contact_id,
c1.school_id,
count(c2.contact_id) as display_order
from contacts1 c1
join contacts1 c2
on c2.school_id = c1.school_id
and (
c2.key_contact > c1.key_contact
or
c2.key_contact = c1.key_contact and c2.contact_id <= c1.contact_id
)
group by c1.contact_id, c1.school_id
order by c1.contact_id;
Explanation
The key logic is in the join condition:
c2.key_contact > c1.key_contact
or
c2.key_contact = c1.key_contact and c2.contact_id <= c1.contact_id
This condition defines that the row from c2
has a higher or equal contact priority for the given school compared to the row from c1
. (The priority is only equal if the contact_id
is the same.) In the SELECT
part we count all the rows with a higher or equal priority for each contact_id from c1 (group by c1.contact_id
).
c2.key_contact > c1.key_contact
is only true if c1.key_contact=0
and c2.key_contact=1
. So every row from c2
found by this condition has a higher priority and will be counted.
c2.key_contact = c1.key_contact and c2.contact_id <= c1.contact_id
If key_contact
is equal then we only count the rows with a smaller or equal contact_id
.
This gives you the same result as if you would sort your table like this:
select *
from contacts1 c1
order by c1.school_id, c1.key_contact desc, c1.contact_id
and then enumerate the rows for each school.
Upvotes: 1