SQL select查询具有特殊修改

时间:2013-10-15 10:16:58

标签: mysql sql

我遇到了问题,我不知道是否有任何方法只能借助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,';',']%['),']%')

4 个答案:

答案 0 :(得分:1)

试试这个:

SELECT *
FROM users u
WHERE
INSTR(
    (SELECT group_id
    FROM users u2
    WHERE u2.id = '3'),
u.group_id) <> 0

显示SqlFiddle

**编辑:**

您必须为每一行实现一个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,';',','))

SQLFiddle

答案 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;

Live example on SQL Fiddle

如果您需要超过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

我已经检查了它并且它接缝好了:

  • for 1返回1
  • for 2返回1,2
  • for 3返回1,3,4
  • for 4返回4