具有特定基数的sql查询(多对多)

时间:2015-04-12 17:04:21

标签: sql count mariadb

我在Mariadb有三张桌子

sensor
+---------------+-------------+------+-----+---------+-------+
| Field         | Type        | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+-------+
| name          | varchar(64) | NO   | PRI | NULL    |       |
| reload_time   | int(11)     | NO   |     | NULL    |       |
| discriminator | varchar(20) | NO   |     | NULL    |       |
+---------------+-------------+------+-----+---------+-------+

sensor_common_service
+---------------+-------------+------+-----+---------+-------+
| Field         | Type        | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+-------+
| service_name  | varchar(64) | NO   | PRI | NULL    |       |
| sensor_name   | varchar(64) | NO   | PRI | NULL    |       |
+---------------+-------------+------+-----+---------+-------+

common_service
+---------------+-------------+------+-----+---------+-------+
| Field         | Type        | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+-------+
| service_name  | varchar(64) | NO   | PRI | NULL    |       |
| version       | int(11)     | NO   |     | NULL    |       |
| reload_time   | int(11)     | NO   |     | NULL    |       |
+---------------+-------------+------+-----+---------+-------+

我希望得到所有具有一组传感器的common_services,例如,所有具有传感器温度和湿度的common_services。

所以,如果我有

common_service1 : sensors [temperature]
common_service2 : sensors [temperature,humidity]
common_service3 : sensors [temperature,humidity, luminosity]

查询应该只返回common_service2。

我的第一个尝试是尝试调整Join between mapping (junction) table with specific cardinality

上的查询

这是结果

SELECT * FROM custom_service
JOIN (
      SELECT scm.service_name FROM sensor_custom_service scm
      WHERE scm.sensor_name IN (
                      SELECT s.name FROM sensor s
                      WHERE s.name='luminosity' OR s.name='temperature'
                      )
      GROUP BY scm.service_name HAVING COUNT(DISTINCT scm.sensor_name)=2
      ) AS jt
ON custom_service.service_name=jt.service_name;
另一个,

SELECT scs.* FROM sensor_custom_service scs
where scs.sensor_name IN ( 'luminosity', 'temperature' )
GROUP BY scs.service_name;
HAVING COUNT(scs.sensor_name) = 2

但是通过这些查询,我还得到了具有其他传感器的common_services 因为有计数只计算满足where子句的sensor_custom_service。

使用上面的例子,这个查询都返回

common_service2 : sensors [temperature,humidity]
common_service3 : sensors [temperature,humidity]

我认为这个查询很容易使用INTERSECT运算符,就像这样

SELECT scs.* FROM sensor_custom_service scs
where scs.sensor_name IN ( 'luminosity', 'temperature' )
INTERSECT
SELECT scs.* FROM sensor_custom_service scs
HAVING COUNT(scs.sensor_name) = 2

但Mariabb返回

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'INTERSECT

因为它不受支持(我认为,因为两个查询都是单独工作的)


使用9000查询的解决方案。

select * 
from custom_service cs 
where 
  exists (select 1 from sensor_custom_service scs where 
      scs.service_name = cs.service_name and
      scs.sensor_name = 'luminosity') 
  AND
  exists (select 1 from sensor_custom_service scs where 
      scs.service_name = cs.service_name and
      scs.sensor_name = 'temperature')
  AND
  NOT exists (select  1  from sensor_custom_service scs where
      scs.service_name = cs.service_name and
      scs.sensor_name NOT IN ('temperature', 'luminosity'));

3 个答案:

答案 0 :(得分:2)

MariaDB和MySQL具有GROUP_CONCAT()函数来完成此任务:

SELECT service_name,
       GROUP_CONCAT(sensor_name ORDER BY sensor_name) AS sensors
FROM sensor_common_service
GROUP BY service_name
HAVING sensors='humidity,temperature'

http://sqlfiddle.com/#!9/2f574/1

答案 1 :(得分:1)

请注意,当您需要IN语义时,OR会为您提供AND语义。基本上,如果您需要所有3个传感器,则需要3个连接,每个连接代表一个单独的传感器。

的内容
select * 
from common_service cs 
where 
  exists (select 1 from sensor_common_service scs where 
          scs.service_name = cs.service_name and
          scs.sensor_name = 'luminosity') 
  AND
  exists (select 1 from sensor_common_service scs where 
          scs.service_name = cs.service_name and
          scs.sensor_name = 'temperature')
  -- add more sensors along these lines

这也意味着编写适用于任意数量传感器的可变参数查询是不可能的。 (我很乐意被证明是错的!)

答案 2 :(得分:1)

您要做的只是计算“温度”和“湿度”显示的次数以及每项服务显示的其他内容的次数。结果应该是第一个数字= 2(都显示)和第二个数字= 0(没有其他显示)。

select  ss.Service_Name
from    Sensor_Service ss
group by ss.Service_Name
having  Sum( case when ss.Sensor_Name in( 'Temperature', 'Humidity' ) then 1 else 0 end ) = 2
    and Sum( case when ss.Sensor_Name in( 'Temperature', 'Humidity' ) then 0 else 1 end ) = 0;

这只使用通用SQL。我在Oracle和MariaDB上测试过它。它应该按原样运行在大多数其他地方。