2015-04-12 21 views
2

首先,在此先感謝。具有特定基數的SQL查詢(多對多):解決方案

我有三個表中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')); 

回答

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

+0

謝謝!您的查詢也可以正常工作,而且更簡單! –

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 

這東西線也意味着它不可能寫,對於任意數量的傳感器工作的可變參數查詢。 (我很想被證明是錯的!)

+1

感謝您的回覆, 您的查詢產生相同的結果,只要它只檢查custom_service是否具有這些傳感器,但不是如果它有更多。 雖然你指着我在正確的方向,最後我實現了它添加幾行到您的查詢。我將用解決方案更新答案,因爲它放在這裏太長了。 謝謝,你救了我的一天! –

+0

很高興聽到這個!唉,您必須添加儘可能多的'exists()'行數與您必須檢查的許多傳感器。 – 9000

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上測試過它。它應該像其他大多數一樣運行。