如何计算MySQL中的唯一设置值

时间:2015-02-20 02:51:15

标签: php mysql mysqli

我很感激您的输入,以帮助我计算MySql中SET类型的唯一值。我有一个名为"功能"定义为SET字段如下:

CREATE TABLE cars (features SET('power steering', 'power locks', 'satellite radio', 'power windows', 'sat nav', 'turbo'));

当我填写此表时,由于这些功能并不相互排斥,因此我将获得包含这些功能中的两个或更多功能组合的记录。例如:

Car 1具有动力转向和电动车窗,但没有其余功能。 车2具有所有功能。 除了卫星导航和涡轮增压外,Car 3具有所有功能。

我想要做的是获取表中所有单个列出的功能的列表,包括使用GROUP BY子句以类似方式与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;

然而,不是我期望的,我得到了每个现有功能组合的计数:

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查询?我可以通过执行一个查询来实现对于每个功能,但我确信必须有一种避免这种麻烦的方法。有人可能建议为功能和连接使用不同的表,但是在此时不可能不会严重影响项目的其余部分。提前谢谢!

2 个答案:

答案 0 :(得分:1)

通常,我们使用FIND_IN_SET函数。

您可以使用这样的查询来返回指定的结果:

 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并获得相同的结果。此查询省略"零计数":具有"功能的行#34;这对任何一辆车来说都不会出现。要获得这些内容,您可以使用外部联接(在LEFT之前添加JOIN关键字,而不是在SELECT列表中添加COUNT(1)COUNT(expr)其中expr是来自cars的{​​{1}}列,或者是找到匹配行时非NULL的其他表达式,以及找不到匹配行时的NOT NULL

答案 1 :(得分:1)

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

改编自:

MySQL: Query for list of available options for SET

我的查询以上述帖子中的SQL为基础,获取可用列值的列表。所有缩进的SQL都是一个查询,如果单独执行它,你将获得列表,我从中创建一个结果集,我称之为#34; set_list&#34;。我只是原样复制了那个查询,但它基本上做了大量的字符串操作来获取列表 - 正如Mike Brant建议的那样,如果将列表放入另一个表中,代码会更简单(但可能只是不动态) ,刚刚加入。

然后我将set_list重新加入cars表,将set_list中的每个项目与包含该功能的汽车中的行连接起来 - FIND_IN_SET()。它是一个外部联接,所以如果没有表示集合列表中的任何内容,那么它将在那里计数为零。