多对多的属性对应表如何做按照类别的多属性匹配搜索

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

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

时间: 2024-11-05 21:48:18

多对多的属性对应表如何做按照类别的多属性匹配搜索的相关文章

HTML5 学习笔记(二)——HTML5新增属性与表单元素

目录 一.HTML5新增属性 1.1.contextmenu 1.2.contentEditable 1.3.hidden 1.4.draggable 1.5.data-* 1.6.placeholder占位属性 1.7.required必填属性 1.8.pattern正则属性 1.9.autofocus自动聚焦属性 1.10.autocomplete自动完成属性 1.11.novalidate不验证属性 1.12.multiple多选属性 二.HTML5表单新功能解析 2.1.表单结构更自由

ABAP内表数据做层次XML输出

*&---------------------------------------------------------------------**& Report  Z_BARRY_TEST_XML*&---------------------------------------------------------------------**& 46C - ECC6 通用*&----------------------------------------------

HTML5 学习总结(二)——HTML5新增属性与表单元素

一.HTML5新增属性 1.1.contextmenu contextmenu的作用是指定右键菜单. <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="div1" style="height:900px; backgrou

Hbase 无法创建带有snappy压缩属性的表

一.要求 在Hbase 数据库中创建带有snappy压缩属性的表. 二.登陆到hbase 数据库执行建表操作 hbase(main):016:0> create 'dcs:t_dev_history',{NAME => 'f', DATA_BLOCK_ENCODING => 'PREFIX_TREE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', VERSIONS => '1', COMPRESSION => '

vue.js基础知识篇(1):简介、数据绑定、指令、计算属性、表单控件绑定和过滤器

目录第一章:vue.js是什么? 代码链接: http://pan.baidu.com/s/1qXCfzRI 密码: 5j79 第一章:vue.js是什么? 1.vue.js是MVVM框架 MVVM的代表框架是Angular.js,以及vue.js. MVVM的view和model是分离的,View的变化会自动更新到ViewModel上,ViewModel的变化会自动同步到View上显示.这种自动同步依赖于ViewModel的属性实现了Observer. 2.它与angular.js的区别 相同

JavaScript - 表单提交前预览图片属性

即Preview image and its properties before upload 其实这东西网上到处都是,但并不完整. 正好我也遇到了这个问题,不仅仅是预览,还需要得到图片的属性. 于是东凑西凑整理出一个完整的版本,并根据个人的理解加上了一点点说明. (ps:感谢爆栈^^) 首先做一些准备工作,HTML方面主要是img和input标签的id:     <form>         <input type='file' id="imgFile"  />

django-创建表的字段属性,表关系

表的各种属性文档:null char ..., django与之对应的文档 https://docs.djangoproject.com/en/1.11/ref/models/fields/   英文 https://yiyibooks.cn/xx/Django_1.11.6/ref/models/fields.html     中文 表关系 class Book(models.Model): headline = models.CharField('大标题', max_length=50) p

hbase建表create高级属性 //hbase 表预分区也就是手动分区 这个很重要

2019/2/19 星期二 hbase建表create高级属性 //hbase 表预分区也就是手动分区 这个很重要 下面几个shell 命令在后续的hbase 操作中可以起到很到的作用,且主要体现在建表的过程中,看下面几个create 属性1.BLOOMFILTER 默认是NONE 是否使用布隆过虑使用何种方式布隆过滤可以每列族单独启用.使用HColumnDescriptor.setBloomFilterType(NONE |ROW | ROWCOL) 对列族单独启用布隆.Default = N

4.mybatis属性和表的列名不相同时的处理方法

/** * 属性和表的列名不相同时的处理方法 * 1.sql中给列重新命名: * select tid id, tname name from teacher t where tid=#{id} * 2.在teacherMapper.xml中使用resultMap标签 * <select id="getTeacher2" parameterType="int" resultMap="getTeacherMap"> * select *