我遇到了问题,我不知道是否有任何方法只能借助SQL解决问题。
我有一张桌子users
+----+------------+
| ID | group_id |
+----+------------+
| 1 | 1;2;3 |
+----+------------+
| 2 | 1;2;3;4 |
+-----------------+
| 3 | 1;2;3;6 |
+-----------------+
| 4 | 1;2;6 |
+-----------------+
我知道它不是正常形式,但我无法改变它,因为它已被客户使用。
所以问题不是显示我没有的群组的用户。
例如:如果我为ID = 3的用户选择。我需要显示用户1,3和4,因为用户ID = 3包含所有具有用户ID = 1的组,但我不应该显示用户ID = 2。
如果有兴趣的话,我的同事会帮助我找到最佳解决方案:
SELECT *
FROM `users`
WHERE CONCAT('[',REPLACE('1;2;3;6', ';', ']['), ']') LIKE CONCAT('%[', REPLACE(group_id,';',']%['),']%')
答案 0 :(得分:1)
试试这个:
SELECT *
FROM users u
WHERE
INSTR(
(SELECT group_id
FROM users u2
WHERE u2.id = '3'),
u.group_id) <> 0
**编辑:**
您必须为每一行实现一个STORED PROCEDURE,将您的组ID字符串转换为新临时表的行。所以你有这样的情况:
TEMP_TABLE(user_id,group_id)
user_id group_id
1 1
1 2
1 3
2 1
2 2
2 3
2 4
等等
所以你的查询可以用这种方式用NOT EXISTS条件重写:(我创建了app表但你必须用存储过程的输出来改变我的app表)
create table user (id int, group_id varchar(20));
insert into user values(1, '1;2;3'),
(2, '1;2;3;4'),
(3, '1;2;3;6'),
(4, '1;2;6');
CREATE TABLE app (user_id int, group_id varchar(10));
insert into app values
(1, '1'),
(1, '2'),
(1, '3') and so on
select *
from user u
where id not in (
select distinct a1.user_id
from app a1
where not exists(
select 'x'
from app a2
where a2.user_id = 3
and a2.group_id = a1.group_id
)
)
显示新的SqlFiddle
答案 1 :(得分:1)
MySQL具有针对此类用例的内置命令find_in_set
。
不幸的是,它只适用于逗号分隔值,而不是分号分隔的值,但也可以轻松克服:
SELECT *
FROM users
WHERE FIND_IN_SET('3', REPLACE(group_id,';',','))
答案 2 :(得分:0)
正如你所说,你无法改变它,但这些案例的一个简单解决方案是Bitwise:
http://dev.mysql.com/doc/refman/5.0/en/bit-functions.html
例如:
我为状态设置了一个数字方案,例如:
1 =预期客户
2 =取消服务
4 =泳池服务
8 =割草坪
16 =窗户洗涤
32 =修剪树木
64 =房屋绘画
128 =移动换油
使用此方案,需要池服务(4)和窗口清洗(16)的客户将具有20(4 + 16)的状态。可能对移动换油(128)感兴趣的潜在客户(1)的状态为129(1 + 128)。等...
按位逻辑允许我根据其状态值选择购买特定服务的客户。
SELECT * FROM customers WHERE status & 1
//returns all prospects)
SELECT * FROM customers WHERE status & 16
//returns all of my window washing customers even if they are cancelled
SELECT * FROM customers WHERE (status & 16) AND !(status & 2)
//returns all of my window washing customers but not the cancelled ones
SELECT * FROM customers WHERE status & 36
//returns all of my tree trimming AND pool service customers i.e. 32+4
SELECT * FROM customers WHERE status & 10
//returns all cancelled lawn moving customers i.e. 2+8
SELECT * FROM customers WHERE (status & 32) AND !(status & 128)
//returns all tree trimming customers who do not get a mobile oil change
答案 3 :(得分:0)
我创建了“一个班轮”,也许它有点复杂,但是加上没有必要使用存储过程或临时表。
减号是select 1 union select 2 union select 3 union...
的一部分,因为我们需要为一个人创建尽可能多的行。
上次where id1 = 3
是您的参数。
create table users (id integer, group_id varchar(100));
insert into users
select 1, '1;2;3' union
select 2, '1;2;3;4' union
select 3, '1;2;3;6' union
select 4, '1;2;6';
select id2 as user_id
from (
select u1.id as id1, u2.id as id2, count(*) as qty
from (
select distinct id, group_id, substring_index(substring_index(group_id, ';', t.n), ';', -1) as g_id
from users
cross join (
select @i := @i + 1 as n from (select @i:=0) t0,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t1,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t2
) as t
) as u1
join users u2 on find_in_set(u1.g_id, replace(u2.group_id, ';', ',')) > 0
group by u1.id, u2.id
) as t
join (
select id, group_id, length(group_id) - length(replace(group_id, ';', '')) + 1 as groups_count
from users
) as g on t.id2 = g.id and g.groups_count <= t.qty
where id1 = 3;
如果您需要超过100组(每人)添加另一行(使用不同的别名):
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) txxxx
我已经检查了它并且它接缝好了: