【问题标题】:MySQL - Best approach to ensure unique values across multiple rowsMySQL - 确保多行唯一值的最佳方法
【发布时间】:2012-03-16 00:20:01
【问题描述】:

我有 3 张桌子:

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;

哪个返回(示范性sn-p):

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

(我知道,CO 和 CO2 都具有完全相同的原子,但数量不同,但请忽略这一点,因为我将这些数量作为同一张表中的另一列进行跟踪。)

到目前为止,我正在提取上述结果并通过 PHP 检查它们的 atom_ids,这意味着我必须为每个分子发出单独的查询,这似乎效率低下,所以我想看看是否可以使用严格的 SQL。

请原谅任何可能与化学有关的错误,自从 chem101 以来已经很久了。

【问题讨论】:

  • 你知道除了H2O,还有H2O2对吧?
  • 分子/原子模式抽象了我真正正在研究的东西,这就是为什么提到我不关心数量,只关心确保分子中唯一原子的原则。

标签: mysql sql join unique


【解决方案1】:

您要求的是表级约束,而这些在 MySQL 中不可用。在 SQL-92 标准中,有ASSERTION,它实际上更通用(一个跨多个表的约束)。请参阅此问题中的答案:Why don't DBMS's support ASSERTION,了解有关具有此类功能但有限制的某些产品 (MS-Access) 的详细信息和信息。

在 MySQL 中,您可以尝试使用触发器来模拟这样的约束。


更新:

Firebird documentation 表示它允许在 CHECK 约束中进行子查询。

【讨论】:

【解决方案2】:

唯一索引可能对分子原子表有所帮助。这将防止该级别的重复。您仍然需要通过 SQL 语句进行一些检查。另一个取决于列表大小的选项是将其加载到内存中的哈希表中,然后从那里运行检查。

【讨论】:

  • 我应该提到它,但是MoleculeAtom表的molecule_id和atom_id列是复合主键,所以满足唯一约束。
【解决方案3】:

这里的想法是找到原子列表不相同的分子对:

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))

【讨论】:

  • 有意思,我看看这个。谢谢。
【解决方案4】:

正如 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'];
        }
    }
}

感谢大家的回复。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-24
    • 1970-01-01
    • 2017-09-21
    • 2018-02-25
    • 1970-01-01
    • 2022-06-20
    • 1970-01-01
    • 2011-07-08
    相关资源
    最近更新 更多