Php 如何计算MySQL中的唯一集值
如果您能帮助我计算MySql中集合类型的唯一值,我将不胜感激。我将一个名为features的列定义为集合字段,如下所示:Php 如何计算MySQL中的唯一集值,php,mysql,mysqli,Php,Mysql,Mysqli,如果您能帮助我计算MySql中集合类型的唯一值,我将不胜感激。我将一个名为features的列定义为集合字段,如下所示: CREATE TABLE cars (features SET('power steering', 'power locks', 'satellite radio', 'power windows', 'sat nav', 'turbo')); 当我填写此表时,由于这些特性不是互斥的,因此我将得到包含两个或更多这些特性组合的记录。例如: 1号车有动力转向和电动车窗,但没有其
CREATE TABLE cars (features SET('power steering', 'power locks', 'satellite radio', 'power windows', 'sat nav', 'turbo'));
当我填写此表时,由于这些特性不是互斥的,因此我将得到包含两个或更多这些特性组合的记录。例如:
1号车有动力转向和电动车窗,但没有其他功能。
2号车具备所有功能。
除卫星导航和涡轮外,3号车拥有所有功能
我想做的是获得表中所有单个列出的功能的列表,包括以类似于使用GROUPBY子句的SELECT语句的方式关联到每个功能的记录计数。因此,按照上面的例子,我应该能够得到以下结果:
features |count
---------------+------
power steering | 3 //All cars have this feature
power locks | 2 //Only cars 2 and 3 have it
satellite radio| 2 //Only cars 2 and 3 have it
power windows | 3
sat nav | 1 //only car 2 has it
turbo | 1 //only car 2 has it
我尝试使用以下查询,期望获得上述结果:
SELECT features, COUNT(features) FROM cars GROUP BY features;
SELECT f.feature
, COUNT(1)
FROM ( SELECT 'power steering' AS feature
UNION ALL SELECT 'power locks'
UNION ALL SELECT 'satellite radio'
UNION ALL SELECT 'power windows'
UNION ALL SELECT 'sat nav'
UNION ALL SELECT 'turbo'
) f
JOIN cars c
ON FIND_IN_SET(f.feature,c.features)>0
GROUP BY f.feature
ORDER BY f.feature
但是,我得到的不是我所期望的,而是每个现有功能组合的计数:
features |count
------------------------------------------------+--------
power steering, power windows | 1 //i.e. only 1 car has
| //only these 2 features
| //(car 1 in this example)
|
------------------------------------------------+-------
power steering, power locks, satellite radio, |
power windows, sat nav, turbo | 1
------------------------------------------------+-------
power steering, power locks, satellite radio, |
power windows | 1
所以,问题是:有没有一种方法可以使用一个MySQL查询获得第一个表中所示的每个特性的计数?我可以通过对每个特性执行一个查询来实现这一点,但我相信一定有办法避免这种麻烦。有人可能会建议使用不同的表进行特性和连接,但此时不可能不严重影响项目的其余部分。提前谢谢 通常,我们使用FIND_IN_SET函数
您可以使用如下查询返回指定的结果:
SELECT features, COUNT(features) FROM cars GROUP BY features;
SELECT f.feature
, COUNT(1)
FROM ( SELECT 'power steering' AS feature
UNION ALL SELECT 'power locks'
UNION ALL SELECT 'satellite radio'
UNION ALL SELECT 'power windows'
UNION ALL SELECT 'sat nav'
UNION ALL SELECT 'turbo'
) f
JOIN cars c
ON FIND_IN_SET(f.feature,c.features)>0
GROUP BY f.feature
ORDER BY f.feature
您可以忽略>0并获得相同的结果。此查询忽略零计数:具有任何汽车都不会显示的功能的行。要获得这些,您可以使用外部联接在联接之前添加LEFT关键字,而不是选择列表中的COUNT1、COUNTexpr,其中expr是cars中不为NULL的列,或者在找到匹配行时为非NULL的其他表达式,在找不到匹配行时为NULL
SELECT set_list.features, COUNT(cars.features) FROM
(SELECT TRIM("'" FROM SUBSTRING_INDEX(SUBSTRING_INDEX(
(SELECT TRIM(')' FROM SUBSTR(column_type, 5)) FROM information_schema.columns
WHERE table_name = 'cars' AND column_name = 'features'),
',', @r:=@r+1), ',', -1)) AS features
FROM (SELECT @r:=0) deriv1,
(SELECT ID FROM information_schema.COLLATIONS) deriv2
HAVING @r <=
(SELECT LENGTH(column_type) - LENGTH(REPLACE(column_type, ',', ''))
FROM information_schema.columns
WHERE table_name = 'cars' AND column_name = 'features')) set_list
LEFT OUTER JOIN cars
ON FIND_IN_SET(set_list.features, cars.features) > 0
GROUP BY set_list.features
改编自:
我的查询以上面文章中的SQL为基础,以获得可用列值的列表。所有缩进SQL都是一个查询,如果单独执行它,就会得到列表,我从中创建一个结果集,我称之为set_list。我只是照着原样复制了这个查询,但它基本上是在做大量的字符串操作来获取列表——正如Mike Brant所建议的,如果将列表放入另一个表中,并将其合并,代码会简单得多,但可能没有那么动态
然后,我将set_列表重新连接到cars表中,将set_列表中的每个项目连接到cars中包含该功能的行中-FIND_in_set。它是一个外部联接,因此如果集合列表中的任何内容没有表示,它将以零计数出现。如果需要这些类型的结果,为什么不将特征数据规范化到另一个表中?此问题的状态如何?如果一个答案解决了它,它应该被标记为已解决。为了能够理解它,要求你描述你的查询做了什么会不会太多?这比我的MySQL基础知识要先进得多。再次感谢@user3783407我已经添加了一个描述,如果有任何不清楚的地方,请告诉我。值得注意的是,这里的smarts是一个动态获取集合列表的查询,我从我引用的帖子中复制了它——这是一个复杂的字符串操作,可以将值列表作为结果集。在这之后,它并不比连接一些表更复杂,如果需要的话,如果您将功能列表放在另一个表中,您可以避免复杂的查询-如果您更改了集合列表,您只需要维护额外的表。