To get the same row more than once you need to join in another table. I suggest to create, only once(!), a helper table. This table will just contain a series of natural numbers (1, 2, 3, 4, ... etc). Such a table can be useful for many other purposes.
Here is the script to create it:
create table seq (num int);
insert into seq values (1),(2),(3),(4),(5),(6),(7),(8);
insert into seq select num+8 from seq;
insert into seq select num+16 from seq;
insert into seq select num+32 from seq;
insert into seq select num+64 from seq;
/* continue doubling the number of records until you feel you have enough */
For the task at hand it is not necessary to add many records, as you only need to make sure you never have more repetitions in your in
condition than in the above seq
table. I guess 128 will be good enough, but feel free to double the number of records a few times more.
Once you have the above, you can write queries like this:
select province_id,
name,
@pos := instr(@in2 := insert(@in2, @pos+1, 1, '#'),
concat(',',province_id,',')) ord
from (select @in := '0,1,2,3,1,0', @in2 := @in, @pos := 10000) init
inner join provinces
on find_in_set(province_id, @in)
inner join seq
on num <= length(replace(@in, concat(',',province_id,','),
concat(',+',province_id,',')))-length(@in)
order by ord asc
Output for the sample data and sample in
list:
| province_id | name | ord |
|-------------|--------|-----|
| 1 | name 1 | 2 |
| 2 | name 2 | 4 |
| 3 | name 3 | 6 |
| 1 | name 1 | 8 |
SQL Fiddle
How it works
You need to put the list of values in the assignment to the variable @in
. For it to work, every valid id must be wrapped between commas, so that is why there is a dummy zero at the start and the end.
By joining in the seq
table the result set can grow. The number of records joined in from seq
for a particular provinces record is equal to the number of occurrences of the corresponding province_id
in the list @in
.
There is no out-of-the-box function to count the number of such occurrences, so the expression at the right of num <=
may look a bit complex. But it just adds a character for every match in @in
and checks how much the length grows by that action. That growth is the number of occurrences.
In the select
clause the position of the province_id
in the @in
list is returned and used to order the result set, so it corresponds to the order in the @in
list. In fact, the position is taken with reference to @in2
, which is a copy of @in
, but is allowed to change:
While this @pos
is being calculated, the number at the previous found @pos
in @in2
is destroyed with a #
character, so the same province_id
cannot be found again at the same position.