多對多的屬性對應表如何做按照類別的多屬性匹配搜索
電商設計中常用到的屬性對應表需要做按照類別的多屬性匹配功能,舉例建表如下
CREATE TABLE goods_attr ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT ‘自增id‘, `goods_id` int(11) DEFAULT ‘0‘ COMMENT ‘商品id‘, `type` int(11) DEFAULT ‘0‘ COMMENT ‘屬性類型:1:商品類型 2:支持語言 3:支持平臺‘, `value` varchar(50) DEFAULT ‘‘ COMMENT ‘屬性值‘, PRIMARY KEY(`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT=‘商品屬性信息表‘;
INSERT INTO goods_attr (`id`, `goods_id`, `type`, `value`) VALUES (‘1‘, ‘118‘, ‘1‘, ‘1‘); INSERT INTO goods_attr (`id`, `goods_id`, `type`, `value`) VALUES (‘2‘, ‘118‘, ‘1‘, ‘5‘); INSERT INTO goods_attr (`id`, `goods_id`, `type`, `value`) VALUES(‘3‘, ‘118‘, ‘1‘, ‘8‘); INSERT INTO goods_attr (`id`, `goods_id`, `type`, `value`) VALUES (‘4‘, ‘118‘, ‘2‘, ‘1‘); INSERT INTO goods_attr (`id`, `goods_id`, `type`, `value`) VALUES (‘5‘, ‘146‘, ‘3‘, ‘1‘); INSERT INTO goods_attr (`id`, `goods_id`, `type`, `value`) VALUES (‘6‘, ‘146‘, ‘1‘, ‘1‘); INSERTINTO goods_attr (`id`, `goods_id`, `type`, `value`) VALUES (‘7‘, ‘157‘, ‘1‘, ‘8‘); INSERT INTO goods_attr (`id`, `goods_id`, `type`, `value`) VALUES (‘8‘, ‘157‘, ‘1‘, ‘5‘); INSERT INTO goods_attr (`id`, `goods_id`, `type`, `value`) VALUES (‘9‘, ‘157‘, ‘2‘, ‘1‘); INSERT INTO goods_attr (`id`, `goods_id`, `type`, `value`) VALUES (‘10‘, ‘157‘, ‘1‘, ‘1‘);
如上所述,goods_id type value組成唯一的一條記錄
比如
首先,118商品擁有三個類型,是一個復合類型商品 有 1 5 8 三種類型
同時,118商品有一個語言 是1類型的語言
同時,118商品有1個平臺 是1類型平臺
146商品就只有一個類型是1,一種平臺是1,而且沒有語言
然後現在前臺或者接口調用處要根據某個屬性進行反查詢得到商品id,最常見的地方是商品的屬性搜索,參考
https://s.taobao.com/list?spm=a217l.8087239.620327.1.729cb1d2ofc3E9&q=%E7%94%B5%E9%A5%AD%E7%85%B2&style=grid&seller_type=taobao
可以看到能夠根據該類別商品的屬性進行搜索
比如容量 控制方式 等進行多屬性匹配搜索。
那麽,就需要一個很復雜的復合查詢才行,采用inner join多次連表也是能做到的,不過書寫的SQL就比較復雜,而且很難保證效率。
針對我們的表 假如要查詢 商品類型為5和8的復合類型,而且支持語言為1的商品,該如何查詢呢?
最容易想到的是
select * from goods_attr where ( type=1 and value in (‘5‘,‘8‘) ) or ( type=2 and value in (‘1‘) )
但是這樣的查詢條件必然是不正確的,因為 只要符合其中一個條件,那些不相幹的記錄也被查出來了,稍稍改進進行自鏈接
select * from goods_attr as a left join goods_attr as b on a.goods_id=b.goods_id and (( a.type=1 and a.value in (‘5‘,‘8‘) ) and ( b.type=2 and b.value in (‘1‘) ))
這樣的自鏈接看似是正確的,實際上偏離了我們要求的同時滿足復合屬性的記錄存在,value必須有5 而且又有8 而不是in (‘5‘,‘8‘) 所以也是不正確的。
如何得到同時有5又有8呢?只能這樣寫
select a.* from goods_attr as a inner join goods_attr as b on a.goods_id=b.goods_id and a.type=1 and a.value=5 and b.value=8
這種情況下能查詢出 type=1的情況下既有5 又有8 的屬性。那如何加上查詢type=2的情況下 value=1的屬性條件呢?當然是再連接一次!
select c.goods_id from ( select a.* from goods_attr as a inner join goods_attr as b on a.goods_id=b.goods_id and a.type=1 and a.value=5 and b.value=8 ) as tmp inner join goods_attr as c on c.goods_id=tmp.goods_id where c.type=2 and c.value=1
至此,自鏈接方法講述完畢,如果不想用大量的自鏈接,又該如何做呢?
我想到,可以使用行轉列的方式進行操作,行轉列,借助 group_concat實現
select goods_id,type, group_concat(value) as v from ( select * from goods_attr order by goods_id asc,type asc,value asc ) as u where (type=1 and value in (‘5‘,‘8‘)) or (type=2 and value in (‘1‘)) group by goods_id,type
然而這樣查詢出來的結果並沒有自然的排序放入 group_concat中 所以需要強制性指明排序
select goods_id,type, group_concat(value order by goods_id asc,type asc,value asc) as v from goods_attr where (type=1 and value in (‘5‘,‘8‘)) or (type=2 and value in (‘1‘)) group by goods_id,type
這樣就能強制性拿到排序
現在得到了屬性的分組,然後我們還要把屬性分類和分組的值再次合並形成一列,和剛剛一樣 再次使用group_concat
select group_concat(type,"-",v) as final,goods_id from (select goods_id,type,v from ( select goods_id,type, group_concat(value order by goods_id asc,type asc,value asc) as v from goods_attr as u where (type=1 and value in (‘5‘,‘8‘)) or (type=2 and value in (‘1‘)) group by goods_id,type ) as tmp ) as t group by goods_id
很顯然,我們拿到了所有符合的商品屬性的列和商品id,那麽再加一條查詢條件即可或得到我們需要的屬性列表
select goods_id from ( select group_concat(type,"-",v) as final,goods_id from (select goods_id,type,v from ( select goods_id,type, group_concat(value order by goods_id asc,type asc,value asc) as v from goods_attr as u where (type=1 and value in (‘5‘,‘8‘)) or (type=2 and value in (‘1‘)) group by goods_id,type ) as tmp ) as t group by goods_id ) as f where final=‘1-5,8,2-1‘
這樣我們就得到了需要的商品id!!!
因這篇文章探討SQL比較深入,所以這裏加一下版權。
版權所有,轉載需要聲明原文地址 http://www.cnblogs.com/lizhaoyao/p/7199611.html
多對多的屬性對應表如何做按照類別的多屬性匹配搜索