2012-03-16 25 views
2

我有3個表:MySQL的 - 最好的辦法,以保證唯一值在多行

Molecule: 
    id 

Atom: 
    id 

MoleculeAtom: # Composite primary key 
    molecule_id 
    atom_id 

我的目標是,以確保沒有原子的組成分子的組合,是重複的。例如,水分子,我會在MoleculeAtom表中存儲兩行; 1個氫原子和1個氧原子。正如你所看到的,我需要確保沒有其他分子只有氫和氧,儘管可能有其他分子包括氫和氧。

在這一點上,我有一個查詢,它標識哪些分子包含氫或氧,並且只有MoleculeAtom表中有2個原子。

SELECT 
    m.id, m.name, (SELECT count(*) from molecule_atom where molecule_id = m.id group by molecule_id) as atomCount 
FROM 
    molecule AS m 
INNER JOIN 
    molecule_atom AS ma ON ma.molecule_id = m.id 
WHERE 
    ma.atom_id IN (1,2) 
HAVING atomCount = 2; 

它返回(示範段):

+----+----------------------------+-----------+ 
| id | name      | atomCount | 
+----+----------------------------+-----------+ 
| 53 | Carbon Dioxide    |   2 | 
| 56 | Carbon Monoxide   |   2 | 
+----+----------------------------+-----------+ 

(我知道,CO和CO2具有完全相同的原子,以不同的量,但DIS-方面,作爲我跟蹤數量作爲另一列在同一表)

截至目前我拉動上述結果,並檢查他們的atom_ids通過PHP,這意味着我必須爲每個分子發出一個單獨的查詢,這似乎效率低下,所以我正在查看是否有可能做這個檢查嚴格使用SQL。

請原諒可能與化學有關的任何錯誤,chem101已經很長時間了。

+0

你知道除了'H2O',還有'H2O2',對吧? – 2012-03-16 00:35:52

+0

分子/原子模式抽象我真正在做什麼,這就是爲什麼提到我不關心數量,只有確保跨分子獨特原子的原則。 – 2012-03-16 00:43:28

回答

0

正如ypercube提到的那樣,MySQL不支持斷言,因此我結束了寫查詢以查找所有至少有一個原子屬於我嘗試創建的新分子的分子,並且具有相同數量的原子。在查詢匹配之後,應用程序遍歷每個分子並確定它們是否與新分子具有相同的確切原子。查詢看起來是這樣的(假設我想創建2個原子的新分子):

SELECT 
    m.id, 
    m.name, 
    (SELECT GROUP_CONCAT(ma.atom_id) FROM molecule_atom AS ma WHERE ma.molecule_id = m.id GROUP BY ma.molecule_id HAVING (SELECT COUNT(ma.atom_id)) = 2) AS atoms 
FROM 
    molecule AS m 
INNER JOIN 
    molecule_atom AS mas ON mas.molecule_id = m.id 
WHERE 
    mas.atom_id IN (1,2) 

然後在代碼(PHP)我做的:

foreach ($molecules as $molecule) { 

    if (isset($molecule['atoms'])) { 

     $diff = array_diff($newAtomIds, explode(',', $molecule['atoms'])); 

     // If there is no diff, then we have a match 
     if (count($diff) === 0) { 
      return $molecule['name']; 
     } 
    } 
} 

感謝大家的響應。

0

獨特的索引可能對molecular_atom表有幫助。這將防止在該級別重複。你仍然需要通過SQL語句進行一些檢查。另一個取決於列表大小的選項是將其加載到內存中的哈希表中,然後從那裏運行檢查。

+0

我應該提到它,但MoleculeAtom表的molecule_id和atom_id列是複合主鍵,因此滿足唯一約束。 – 2012-03-16 00:28:19

0

這裏的想法是要找到對的分子,其原子的名單是不一樣的:

select m1.molecule_id as m1id, m2.molecule_id as m2id 
from molecule_atom as m1, molecule_atom as m2, 
    (select atom_id from molecule_atom as m where m.molecule_id=m1id) as m1a, 
    (select atom_id from molecule_atom as m where m.molecule_id=m2id) as m2a, 
where m1id < m2id and (((m1a - m2a) is not null) or ((m2a - m1a) is not null)) 
+0

有趣的,我會看看這個。謝謝。 – 2012-03-16 01:01:49

1

你所要求的是一個表級的約束,這些都是不可用在MySQL。在SQL-92標準中,有ASSERTION,實際上它甚至更普遍(跨多於1個表的約束)。有關詳細信息和有關某些產品(MS-Access)的信息,請參閱此問題中的asnwers:Why don't DBMS's support ASSERTION,這些產品具有此類功能,但存在限制。

在MySQL中,您可以嘗試使用觸發器來模仿這種約束。


更新:

Firebird documentation說,它可以讓子查詢CHECK約束。

+0

感謝您的回覆,我將通讀鏈接文檔。如果我切換到MS-Access,有人需要踢我的狗。 – 2012-03-16 01:02:39

+0

你可能想在這裏發佈你的'更新'作爲這個問題的答案:[什麼SQL數據庫支持CHECK約束中的子查詢](http://stackoverflow.com/questions/6195881/what-sql-databases-support-subqueries -in檢查約束) – onedaywhen 2012-03-16 10:12:39