0

我正在使用具有documents以下字段的单个表(称为 ):idparent_idstatusparent_id字段是指同一个表中的字段id。该status字段的类型为ENUM('submitted', 'accepted', 'rejected')

我想选择所有没有documents孩子的地方。status = 'accepted'

我的第一次尝试是这样的:

SELECT DISTINCT `documents`.*
FROM (`documents`)
LEFT OUTER JOIN `documents` children_documents
  ON `documents`.`id` = `children_documents`.`parent_id`
WHERE `children_documents`.`id` IS NULL
  OR `children_documents`.`status` != 'accepted'

这样做的问题是仍然会选择包含已接受和未接受子项的文档。不应选择包含任何已接受子项的文档。

我有一种感觉GROUP BY可能是我的朋友,但我不知道如何使用它来获得预期的结果。

4

4 回答 4

2

我用MySQLCASE语句解决了这个问题。

SELECT DISTINCT `documents`.*
FROM (`documents`)
LEFT OUTER JOIN `documents` children_documents
  ON `documents`.`id` = `children_documents`.`parent_id`
GROUP BY `documents`.`id`
HAVING SUM(CASE `children_documents`.`status` WHEN 'accepted' THEN 1 ELSE 0 END) = 0

这将选择所有文档,无论它们是否有孩子,并计算他们拥有的已接受孩子的数量。对于要选择的行,该数字必须为零。

编辑:出于好奇,我设法在 DataMapper ORM(CodeIgniter)中模拟查询:

$d->distinct()->where('status', 'accepted')->group_by('id')
  ->having_func('!SUM', array('[CASE]', '@children/status', '[WHEN]', 'accepted', '[THEN]', 1, '[ELSE]', 0, '[END]'), NULL);
于 2012-08-22T23:00:25.230 回答
2

如果我正确理解您要查找的内容,我将使用以下方法使事情变得简单。

SELECT *
FROM `documents`
WHERE `id` NOT IN ( 
    SELECT `parent_id`
    FROM `documents` children_documents
    WHERE `status` = 'accepted' );
于 2012-08-23T02:02:06.307 回答
2
SELECT DISTINCT `documents`.*
FROM (`documents`)
LEFT OUTER JOIN `documents` children_documents
  ON `documents`.`id` = `children_documents`.`parent_id`
  AND `children_documents`.`status` = 'accepted'
WHERE `children_documents`.`parent_id` IS NULL
于 2012-08-23T02:59:56.667 回答
1

MySQL中最快的方式大概是这样的:

select d.*
from documents d
where not exists (select 1
                  from documents c
                  where c.parent_id = d.id and
                        coalesce(c.status, '') = 'Accepted'
                  limit 1
                 )

这使用相关子查询来识别任何不符合条件的子文档。

于 2012-08-23T01:45:00.903 回答