zoukankan      html  css  js  c++  java
  • 多对多的属性对应表如何做按照类别的多属性匹配搜索

    电商设计中常用到的属性对应表需要做按照类别的多属性匹配功能,举例建表如下

    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');
    INSERT INTO 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

  • 相关阅读:
    LeetCode 297. 二叉树的序列化与反序列化
    LeetCode 14. 最长公共前缀
    LeetCode 1300. 转变数组后最接近目标值的数组和
    bigo一面凉经
    LeetCode 128.最长连续序列
    LeetCode中二分查找算法的变种
    LeetCode 93. 复原IP地址
    LeetCode 1004. 最大连续1的个数 III
    LeetCode 1282. 用户分组
    多线程理解
  • 原文地址:https://www.cnblogs.com/lizhaoyao/p/7199611.html
Copyright © 2011-2022 走看看