Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sorting 在CakePHP 3中对子查询列进行分页排序_Sorting_Cakephp_Subquery_Cakephp 3.x - Fatal编程技术网

Sorting 在CakePHP 3中对子查询列进行分页排序

Sorting 在CakePHP 3中对子查询列进行分页排序,sorting,cakephp,subquery,cakephp-3.x,Sorting,Cakephp,Subquery,Cakephp 3.x,这可能已经在其他地方得到了回答,但我在过去几天里一直在寻找答案,但找不到适合我的问题/我理解的答案 我正在使用CakePHP3.8.5,目前正在处理一个查询,该查询在select中包含一个子查询。 我有3张桌子,电脑和打印机。位置和计算机以及位置和打印机处于一种归属关系 因此,我尝试获取以下查询,就数据结果而言,该查询运行良好: $computersQuery = $this->Computers->find(); $computersQuery->select

这可能已经在其他地方得到了回答,但我在过去几天里一直在寻找答案,但找不到适合我的问题/我理解的答案

我正在使用CakePHP3.8.5,目前正在处理一个查询,该查询在select中包含一个子查询。 我有3张桌子,电脑和打印机。位置和计算机以及位置和打印机处于一种归属关系

因此,我尝试获取以下查询,就数据结果而言,该查询运行良好:

    $computersQuery = $this->Computers->find();
    $computersQuery->select([$computersQuery->func()->count('*')])
        ->where(function (QueryExpression $exp) {
            return $exp
                ->notEq('Computers.Unwanted_Software', '')
                ->equalFields('Computers.Area_ID', 'Locations.Area_ID');
        });
        
    $printersQuery = $this->Printers->find();
    $printersQuery->select($printersQuery->func()->count('*'))
        ->where(function (QueryExpression $exp) {           
            return $exp
                ->eq('Printers.WHQL', 0)
                ->equalFields('Printers.Area_ID', 'Locations.Area_ID');
        });
    
    $dataQuery = $this->Locations->find();
    $dataQuery->select(['Locations.Area_ID',
            'Unwanted_Software' => $computersQuery,
            'Printers_Not_WHQL_Compatible' => $printersQuery])
        ->group('Locations.Area_ID');
所以我尝试在我的控制器中对$dataQuery进行分页。在我的模型中,我可以单击所有三个列标题,但只有Area_ID列将被排序。这两个子查询列不会排序。即使我没有犯错误。 查看SQL日志显示,它甚至从未尝试按这两列排序

非常感谢您提出的任何解决方案

如果你需要更多关于我的代码的信息,请在下面留下评论

编辑1:

正如user@ndm指出的,我必须将计算字段放入分页数组的sortWhitelist选项中。 这样做效果很好,因为我能够按列标题进行排序:

    $this->paginate = [
        'limit' => '100',
        'sortWhitelist' => [
            'Locations.Area_ID',
            'Unwanted_Software',
            'Printers_Not_WHQL_Compatible'
        ],
        'order' => ['Locations.Area_ID' => 'ASC']
    ]
但是接下来的问题出现了。正在尝试按打印机不兼容列进行排序。生成的SQL代码有一个小问题,顺便说一句,我使用的是SQL Server 2008:

    SELECT * 

    FROM (SELECT Locations.Area_ID AS [Locations__Area_ID], 
    (SELECT (COUNT(*)) FROM computers Computers WHERE (...)) AS [Unwanted_Software], 
    (SELECT (COUNT(*)) FROM printers Printers WHERE (...)) AS [Printers_Not_WHQL_Compatible], 
    (ROW_NUMBER() OVER (ORDER BY SELECT (COUNT(*)) FROM printers Printers WHERE (...) asc, Locations.Area_ID ASC)) AS [_cake_page_rownum_] FROM locations_Views Locations GROUP BY Locations.Area_ID ) _cake_paging_ 

    WHERE _cake_paging_._cake_page_rownum_ <= 100
有没有办法解决这个问题

编辑2:

因此@ndm通过pull请求或通过newExpr函数进行修复来回答这两个问题都非常有效。至少关于Order By中子查询的括号

不幸的是,我们已经遇到了下一个问题。这两种解决方案生成的SQL值都很重要!有点像是在Order By中刷新整个查询的参数输入,这意味着它将Where子句的筛选参数放在starting By parameter:c0中。您可以在以下查询中看到:

SELECT * 

FROM (SELECT Locations.Area_ID AS [Locations__Area_ID], 
(SELECT (COUNT(*)) 
    FROM computers Computers 
    WHERE (Computers.Unwanted_Software != :c0 
    AND Computers.Area_ID = (Locations.Area_ID)
    )
) AS [Unwanted_Software], 
(SELECT (COUNT(*)) 
    FROM printers Printers 
    WHERE (Printers.WHQL = :c1 
    AND Printers.Area_ID = (Locations.Area_ID))
) AS [Printers_Not_WHQL_Compatible], 
(ROW_NUMBER() OVER (ORDER BY 
    (SELECT (COUNT(*)) 
        FROM printers Printers 
        WHERE (Printers.WHQL = :c0 
        AND Printers.Area_ID = (Locations.Area_ID))) asc,
    Locations.Area_ID ASC)
) AS [_cake_page_rownum_] 

FROM locations_Views Locations 

GROUP BY Locations.Area_ID ) _cake_paging_ 

WHERE _cake_paging_._cake_page_rownum_ <= 100
我认为这不是预期的结果。我个人可能可以解决这个问题,通过避免直接传递参数,我不必处理具体的外部用户输入。我仍然认为这应该被检查一下


感谢@ndm的大力帮助!肯定是我向上投票。

正如注释中链接的那样,默认情况下,分页器只允许对主表中存在的列、其他表的列联接或计算列进行排序

生成的窗口函数SQL中缺少的括号看起来像一个bug,它不会检查order子句中定义的表达式是否是查询,这将需要将生成的SQL封装在括号中

我已经为3.9和4.1推出了一个可能的修复程序:

如果您现在无法升级,一种可能的解决方法是将子查询包装在其他表达式中,编译时应将内部查询表达式包装在括号中:

$dataQuery ->挑选[ “位置.区域ID”, “不需要的软件”=>$dataQuery->newExpr$computersQuery, “打印机不兼容”=>$dataQuery->newExpr$printersQuery ] ->组“位置。区域_ID”;
听起来像。默认情况下,只允许对主存储库的列进行排序。@ndm我更新了我的问题,因为您的帮助使我更接近解决方案,但似乎仍有一些小错误。希望你能帮我解决这个问题!谢谢真的帮了我很多忙!再次编辑该问题,因为我认为还没有解决所有问题,但仍然竖起大拇指!:@Yama是的,看起来不对,我会再看一次。@Yama所以结果有点棘手,我创建了一个PR,有一个可能的解决方案,但我不确定可能的副作用。也许您可以尝试一下,如果可以,请在GitHub上添加一些反馈:
SELECT * 

FROM (SELECT Locations.Area_ID AS [Locations__Area_ID], 
(SELECT (COUNT(*)) 
    FROM computers Computers 
    WHERE (Computers.Unwanted_Software != :c0 
    AND Computers.Area_ID = (Locations.Area_ID)
    )
) AS [Unwanted_Software], 
(SELECT (COUNT(*)) 
    FROM printers Printers 
    WHERE (Printers.WHQL = :c1 
    AND Printers.Area_ID = (Locations.Area_ID))
) AS [Printers_Not_WHQL_Compatible], 
(ROW_NUMBER() OVER (ORDER BY 
    (SELECT (COUNT(*)) 
        FROM printers Printers 
        WHERE (Printers.WHQL = :c0 
        AND Printers.Area_ID = (Locations.Area_ID))) asc,
    Locations.Area_ID ASC)
) AS [_cake_page_rownum_] 

FROM locations_Views Locations 

GROUP BY Locations.Area_ID ) _cake_paging_ 

WHERE _cake_paging_._cake_page_rownum_ <= 100