我有三个表:流程,文档类型和文档。 Flows有许多属于文档类型的文档。
比方说,我需要选择所有具有属于某个文档类型列表的文档的流,例如,其中文档类型id在1、2、3和4中。换句话说,我只想选择流具有所有上述文档类型ID的文档。我应该如何使用逻辑/查询?
我的第一次尝试是使用where in
,但是它不能确保文档完全具有所有文档类型,它至少查询一种:
select * from flows where id in (
select flow_id from documents where document_type_id in (1, 2, 3, 4)
);
我必须使用Laravel Eloquent编写查询,但这在发现正确的逻辑之后将变得微不足道。
答案 0 :(得分:6)
您可以使用聚合和having
:
select f.*
from flows f
where f.id in (select d.flow_id
from documents d
where d.document_type_id in (1, 2, 3, 4)
group by d.flow_id
having count(distinct d.document_type) = 4
);
= 4
保证可以在documents
中找到所有四种类型。请注意,我还添加了表别名并限定了所有列引用。对于您编写的任何查询,这些都是好主意。
您也可以使用相关子查询来执行此操作,这在MySQL中可能更有效:
select f.*
from flows f
where exists (select 1
from documents d
where d.document_type_id in (1, 2, 3, 4) and
d.flow_id = f.id
having count(distinct d.document_type) = 4
);
尤其是,这可以利用documents(flow_id, document_type)
上的索引。
答案 1 :(得分:2)
基本上,使用GROUP_CONCAT,您可以获得DISTINCT
document_type_id ,以获得流ID ,并以逗号分隔的字符串连接。之后使用HAVING
子句进行过滤。
这是一个示例查询(请相应地编辑表和列名称):
SELECT f.*,
GROUP_CONCAT(DISTINCT d.document_type_id
ORDER BY d.document_type_id ASC) AS document_types_in_flow
FROM flows AS f
INNER JOIN documents AS d ON d.flow_id = f.id
GROUP BY f.id
HAVING document_types_in_flow = '1,2,3,4'
答案 2 :(得分:1)
您可以使用内置关系轻松添加该约束...
$flows = Flow::has('documents', '=', 4)->get();
这取决于您正确建立关系,并且可能取决于数据库中的唯一键,该键不允许特定流在数据透视表中附加多个文档。
通过首先计算文档数并将该计数变量(而不是4)放入查询中来使这4个动态值也很聪明。
更个性化的解决方案...
$documentIds = [1,2,3,4];
$flows = Flow::whereHas('documents', function($q) use ($documentIds) {
$q->whereIn('document_type_id', $documentIds);
}, '=', count($documentIds));