我的数据库结构格式如下:    id        |   cid
--------------------------------
1             | ,4,5,7,
--------------------------------
3             | ,4,5,8,
--------------------------------
4             | ,5,4,
--------------------------------
6             | ,5,4,7,8,
--------------------------------
7             | ,8,4,5,7,9,
--------------------------------
8             | ,7,9,4,5,8,10,我想请教一下
假如我post过来的cid值分别是4和5,那我如何精确的查询到id=4的这条数据?
同理,假如我post过来的cid值分别是4,5,7,8的时候,那我如何精确的查询到id=6的这条数据?这里请注意:
cid这一列的数据排列是非固定式的,没规律可循,唯一能够确认的就是不会重复出现同一个值
还有就是用like写法and链接这种方式我试过了,不够精确.例如...where cid like'%,4,%' and cid like'%,5,%'我认为可行的思路应该是使用mysql的replace函数进行替换,替换之后只剩一个逗号的才能满足要求,例如:
...where replace(replace(cid,',4,',','),',5,',',')=','
但这种嵌套的replace我担心效率,还有就是担心不知道能post过来多少个值,如果一次给我post过来几十个值,用这种方法只能replace几十次了,这恐怕不行吧!

解决方案 »

  1.   

    select id from tablename having locate('4',cid)>0 and locate('5',cid)>0 and LENGTH(cid)=length(',4,5')
    我的思路就是根据你post的数据中的数字个数来写这个SQL语句,首先这条记录里要包含所有的数字,并且长度也是固定的,比如两个数字,那么其长度必然是length(',4,5')的长度。
      

  2.   

    REGEXP 正则的实现两个字符串组的匹配。
    http://blog.csdn.net/acmain_chm/article/details/4141864
      

  3.   

    REGEXP 正则的实现两个字符串组的匹配。
    分类: MySQL 2009-05-01 15:04 593人阅读 评论(2) 收藏 编辑 删除
    最近MySQL版块中类似问题出现得比较多。总结了一下。 由于某些原因,有时候我们没有按照范式的设计准则而把一些属性放到同一个字符串字段中。比如个人兴趣,有时候我们设计表为
    create table members (uid int primary key,uname varchar(20),hobby varchar(100));表中内容如下mysql> select * from members;
    +-----+-------+---------------------------------+
    | uid | uname | hobby                           |
    +-----+-------+---------------------------------+
    |   1 | AAAA  | 音乐,电影,网络,篮球,阅读,乒乓球 |
    |   2 | BBBB  | 音乐,阅读,乒乓球,发呆,围棋,参禅 |
    |   3 | CCCC  | 交友,乒乓球                     |
    |   4 | DDDD  | 台球,网络,看书,旅游             |
    |   5 | EEEE  | 音乐,发呆,下围棋,参禅           |
    +-----+-------+---------------------------------+
    4 rows in set (0.00 sec) 如果我们现在想查找一个与某个用户X (阅读,交友,围棋,足球,滑雪)有着相同爱好的会员记录 如果来操作呢?在其它数据库中,我们能只通过程序来或者存储过程来分解这个 "阅读,交友,围棋,足球,滑雪" 字符串为单独的爱好项目,然后一个一个进行 like '%xxxx%' 来查询。 但在MySQL中我们可以直接利用这个regexp正规表达式 来构造SQL语句来实现。 首先我们把 '阅读,交友,围棋,足球,滑雪' 转换成为正则式 为 '阅读|交友|围棋|足球|滑雪' ,  | 在正则表达式中为 '或' 的意思mysql> select replace('阅读,交友,围棋,足球,滑雪',',','|');
    +---------------------------------------------+
    | replace('阅读,交友,围棋,足球,滑雪',',','|') |
    +---------------------------------------------+
    | 阅读|交友|围棋|足球|滑雪                    |
    +---------------------------------------------+
    1 row in set (0.00 sec) 这样我们可以用SQL语句如下。
    mysql> select * from members where hobby regexp replace('阅读,交友,围棋,足球,滑雪',',','|');
    +-----+-------+---------------------------------+
    | uid | uname | hobby                           |
    +-----+-------+---------------------------------+
    |   1 | AAAA  | 音乐,电影,网络,篮球,阅读,乒乓球 |
    |   2 | BBBB  | 音乐,阅读,乒乓球,发呆,围棋,参禅 |
    |   3 | CCCC  | 交友,乒乓球                     |
    |   5 | EEEE  | 音乐,发呆,下围棋,参禅           |
    +-----+-------+---------------------------------+
    3 rows in set (0.00 sec)
    如上语句我们可以通过一句SQL得到所有hobby包含 '阅读,交友,围棋,足球,滑雪' 任一项的记录。但上述的语句中还有一点小的缺陷,那就是把 '下围棋' 这一条也选择了出来,如果精确匹配的话这条记录不应该被选中。为了避免这种情况,我们对SQL语句做如下改进。
    把正则式改为 ',(阅读|交友|围棋|足球|滑雪),'  也就是要求匹配项前后必须有一个界定符"," mysql> select concat(',(',replace('阅读,交友,围棋,足球,滑雪',',','|'),'),');
    +---------------------------------------------------------------+
    | concat(',(',replace('阅读,交友,围棋,足球,滑雪',',','|'),'),') |
    +---------------------------------------------------------------+
    | ,(阅读|交友|围棋|足球|滑雪),                                  |
    +---------------------------------------------------------------+
    1 row in set (0.00 sec)mysql> select * from members
        -> where concat(',',hobby,',') regexp
        ->   concat(',(',replace('阅读,交友,围棋,足球,滑雪',',','|'),'),');
    +-----+-------+---------------------------------+
    | uid | uname | hobby                           |
    +-----+-------+---------------------------------+
    |   1 | AAAA  | 音乐,电影,网络,篮球,阅读,乒乓球 |
    |   2 | BBBB  | 音乐,阅读,乒乓球,发呆,围棋,参禅 |
    |   3 | CCCC  | 交友,乒乓球                     |
    +-----+-------+---------------------------------+
    3 rows in set (0.00 sec)这样避免了第5条记录被选中。 当然也可以利用这种正则式 ',阅读,|,交友,|,围棋,|,足球,|,滑雪,', 但效率显然不如 ',(阅读|交友|围棋|足球|滑雪),' 这种了。 参考文档: MySQL 5.1参考手册 - 12.3.1. 字符串比较函数 - REGEXP (RLIKE)http://dev.mysql.com/doc/refman/5.1/zh/functions.html#string-comparison-functions MySQL 5.1参考手册 - 附录G:MySQL正则表达式http://dev.mysql.com/doc/refman/5.1/zh/regexp.html
      

  4.   

    示例:
    唱歌,电脑  我想查询爱好包括唱歌或是电脑的人 给显示出来 
    select * from tt where Hobbies REGEXP concat('.*[',replace('唱歌,电脑',',','|'),'].*')唱歌,电脑  我想查询爱好包括唱歌或是电脑的人 给显示出来 
    select * from tt where f1 REGEXP '唱歌|电脑'
      

  5.   

    你要准确匹配select * from tt where cid REGEXP ',4,|,5,'
      

  6.   

    我结合大家的想法,用这种方法实现了,请批评指正
    Select id,cid From pkucun where locate(',5,',cid)>0 and locate(',10,',cid)>0 and LENGTH(cid)=length(',5,10,');思路是必须包含  ,5,  和  ,10,  且cid的长度必须和   ,5,10,  这个字符串的长度相等,请问这样会不会有例外的状况发生?
      

  7.   

    道听途说不如自己親自測試,剛剛做了一個測試,結果已經出來了
    我分别用了三种方法做测试,测试的时候是循环20000次提取数据库里的数据,结果如下:
    //1770 ms~1800 ms
    Select id,type From hotel where type like '%|21|%' and type like '%|101|%' and LENGTH(type)=length('|21|101|')//1760 ms~1810 ms
    Select id,type From hotel where locate('|21|',type)>0 and locate('|101|',type)>0 and LENGTH(type)=length('|21|101|')//CPU直接100%,机器挂掉
    Select id,type From hotel where type REGEXP concat('.*[',replace('21,101',',','|'),'].*')
    至于yueliangdao0608所说的效率巨差的问题,还请指教,说说你的方法不但能精确提取数据,而且还要能经得起此测试.