我在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'));
答案 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'
答案 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上测试过它。它应该按原样运行在大多数其他地方。