使用IN()时多次选择一行

时间:2016-05-27 17:07:38

标签: mysql sql

我有这个问题:

select 
     name 
from 
     provinces 
WHERE 
     province_id IN(1,3,2,1)  
ORDER BY FIELD(province_id, 1,3,2,1)

IN()中的值数是动态的


如何使用给定的ORDER BY获得所有行甚至重复(在此示例中为> 1)?

结果应该是这样的:

name1
name3
name2
name1

加上我不应该使用UNION ALL:

select * from provinces WHERE province_id=1
UNION ALL
select * from provinces WHERE province_id=3
UNION ALL
select * from provinces WHERE province_id=2
UNION ALL
select * from provinces WHERE province_id=1

3 个答案:

答案 0 :(得分:4)

这里需要一个帮助表。在SQL Server上可以是:

SELECT name
FROM (Values (1),(3),(2),(1)) As list (id) --< List of values to join to as a table
INNER JOIN provinces ON province_id = list.id

更新:在MySQL Split Comma Separated String Into Temp Table中可用于将字符串参数拆分为帮助程序表。

答案 1 :(得分:1)

要多次获取同一行,您需要加入另一个表。我建议只创建一次(!)辅助表。该表只包含一系列自然数(1,2,3,4 ......等)。这样的表可用于许多其他目的。

以下是创建它的脚本:

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 */

对于手头的任务,没有必要添加许多记录,因为您只需要确保in条件中的重复次数不会超过上述seq表中的重复次数。我猜128会很好,但可以随意将记录数量增加一倍。

完成上述操作后,您可以编写如下查询:

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

示例数据和样本in列表的输出:

| province_id |   name | ord |
|-------------|--------|-----|
|           1 | name 1 |   2 |
|           2 | name 2 |   4 |
|           3 | name 3 |   6 |
|           1 | name 1 |   8 |

SQL Fiddle

如何运作

您需要将赋值中的值列表放入变量@in。为了使它工作,每个有效的id必须包含在逗号之间,这就是为什么在开始和结束时都有一个虚拟零。

通过加入seq表,结果集可以增长。从seq为特定省份记录加入的记录数等于列表province_id中相应@in的出现次数。

没有开箱即用的功能来计算此类事件的数量,因此num <=右侧的表达式可能看起来有点复杂。但它只是为@in中的每个匹配添加一个字符,并检查该操作的长度增长。这种增长是发生的次数。

select子句中,返回province_id列表中@in的位置并用于对结果集进行排序,因此它对应于@in中的顺序}列表。事实上,该位置是参考@in2@in的副本,但允许更改:

在计算此@pos时,@pos中找到的@in2上的数字被#字符销毁,因此province_id相同在同一个位置再也找不到了。

答案 2 :(得分:0)

目前还不清楚你究竟想要什么,但这就是为什么它不能按你想要的方式工作。 IN关键字是创建像......这样的语句的简写。其中province_id = 1 OR province_id = 2 OR province_id = 3 OR province_id = 1.由于province_id = 1在该语句的开头被评估为true,因此它不是如果它再次被包括在内,那已经是真的了。这与结果是否返回重复无关。