【问题标题】:Select all that has exact fields选择所有具有确切字段的内容
【发布时间】:2018-09-18 12:34:00
【问题描述】:

我有三个表:flowsdocument_typesdocuments。 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 编写我的查询,但是在发现正确的逻辑之后这将是微不足道的。

【问题讨论】:

  • 您可以将 GROUP BY 与条件总和结合使用,例如 GROUP BY <column> HAVING SUM(document_type_id = 1) = 1 AND SUM(document_type_id = 2) = 1 ....
  • 因为在 Gordon Linoff 上针对我的评论回答“@RaymondNijland 所以我之前应该按“document_type_id”分组吗?”阅读此stackoverflow.com/help/how-to-ask 部分“帮助其他人重现问题”或“我为什么要为在我看来是一个非常简单的 SQL 查询提供 MCVE?” meta.stackoverflow.com/questions/333952/…

标签: mysql sql laravel eloquent


【解决方案1】:

你可以使用聚合和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) 上的索引。

【讨论】:

  • 我在这里错过了GROUP BY 吗?我知道大多数数据库在没有 GROUP BY 的情况下使用 HAVING 可以正常工作
  • @RaymondNijland 那么我之前应该按“document_type_id”分组吗?
  • @RaymondNijland 。 . .一点也不;)现在仔细看看。 (谢谢)。
【解决方案2】:

基本上,使用GROUP_CONCAT,您可以获得DISTINCT document_type_id(s),用于流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' 

【讨论】:

    【解决方案3】:

    您可以使用内置关系轻松添加该约束...

    $flows = Flow::has('documents', '=', 4)->get();
    

    这将取决于您的关系是否正确设置,并且可能是您数据库中的唯一键,该键不允许特定流在您的数据透视表中附加超过 1 个文档。

    通过首先计算文档数并将该计数变量放入查询而不是 4 来使这 4 个动态化也可能是明智的。

    https://laravel.com/api/5.7/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.html#method_has

    更个性化的解决方案...

    $documentIds = [1,2,3,4];
    
    $flows = Flow::whereHas('documents', function($q) use ($documentIds) {
        $q->whereIn('document_type_id', $documentIds);
    }, '=', count($documentIds));
    

    【讨论】:

    • 这意味着它只会返回附加了 4 个文档的流。我已链接到描述此方法的 API。
    • 好的,让我看看这对我有什么帮助。也许Flow::whereHas('documents', function () { ... })->has('documents', '=', 4)->get()
    • whereHas 也为同样的事情 Flow::whereHas('documents', function () { ... }, '=', 4) 采用额外的参数。无需使用has
    猜你喜欢
    • 1970-01-01
    • 2015-08-23
    • 1970-01-01
    • 2016-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多