如何在查询生成器中有效地转换嵌套 SQL [重复]
Posted
技术标签:
【中文标题】如何在查询生成器中有效地转换嵌套 SQL [重复]【英文标题】:how to efficiently convert a nested SQL in Query builder [duplicate] 【发布时间】:2021-09-16 09:37:43 【问题描述】:我有一个嵌套的 sql 查询
SELECT
city_id,
town_id,
SUM(IF(total_visit >= 2, 1, 0)) visited_twice,
SUM(IF(total_visit >= 3, 1, 0)) visited_thrice
FROM
(
SELECT
c.city_id,
c.town_id,
c.id,
COUNT(v.id) AS total_visit
FROM
VISITS v
LEFT JOIN
CUSTOMERS c
ON v.customer_id = c.id
WHERE
c.customer_type = 1
AND MONTH(v.visit_date) = 6
AND YEAR(v.visit_date) = 2021
GROUP BY
c.town_id,
c.id,
MONTH(v.visit_date),
YEAR(v.visit_date)
HAVING
total_visit > 1
)
GROUP BY
town_id
如何转换为查询构建器模式以使代码可读?
我已尝试转换为普通查询的查询生成器,但正在寻找嵌套查询的建议。
编辑
$visitTable = Visit::$TABLE_NAME;
$customerTable = Customer::$TABLE_NAME;
$sub = Visit::with($with)
->selectRaw("$customerTable.city_id, $customerTable.town_id,
$customerTable.id, COUNT($visitTable.id) total_visit")
->leftJoin("$customerTable", "$customerTable.id", '=', "$visitTable.customer_id")
->where("$customerTable.customer_type_id", 1)
->whereMonth("$visitTable.visit_date", $month)
->whereYear("$visitTable.visit_date", $year)
->groupBy("$customerTable.town_id, MONTH($visitTable.visit_date), YEAR($visitTable.visit_date)")
->havingRaw('total_visit > 1');
$query = DB::table( DB::raw("($sub->toSql()) as sub") )
->selectRaw("city_id, town_id,
SUM(IF(total_visit >= 2, 1, 0)) visited_twice, SUM(IF(total_visit >= 3, 1, 0)) visited_thrice ")
->mergeBindings($sub->getQuery())
->groupBy("town_id");
但最终还是这样
"connection": ,
"grammar": ,
"processor": ,
"bindings":
"select": [],
"join": [],
"where": [
1,
"6",
"2021"
],
"having": [],
"order": [],
"union": []
,
"aggregate": null,
"columns": [
],
【问题讨论】:
【参考方案1】:您可以使用以下任何语法选项轻松地从子查询表中查询
DB::table(Closure, alias)
DB::table(Builder, alias)
DB::query()->from(Closure, alias)
DB::query()->from(Builder, alias)
这里,我使用的是第二个选项。
// Build the subquery first (without getting the results)
$visits_sub = DB::table('VISITS', 'v')
->select('c.city_id', 'c.town_id', 'c.id')
->selectRaw('count(v.id) as total_visit')
->leftJoin('CUSTOMERS as c', 'v.customer_id', 'c.id')
->where('c.customer_type', 1)
->whereMonth('v.visit_date', 6)
->whereYear('v.visit_date', 2021)
->groupByRaw('c.town_id, c.id, month(v.visit_date), year(v.visit_date)')
->having('total_visit', '>', 1);
// Use the built subquery as the table
$query = DB::table($visits_sub, 'visits')
->select('city_id', 'town_id')
->selectRaw('sum(if(total_visits >= 2, 1, 0) as visited_twice')
->selectRaw('sum(if(total_visits >= 3, 1, 0) as visited_thrice')
->groupBy('town_id');
// you can verify the sql by dumping the query
$query->dump();
$results = $query->get();
如果你想强制结果为Visit
模型,你需要使用->query()->from(...)
语法。
$query = Visit::query()
->from($visits_sub, 'visits')
// rest should be the same.
【讨论】:
感谢您的解释。但为什么我收到Object of class Illuminate\Database\Query\Builder could not be converted to string
你在哪里得到这个错误?
基本上,我在存储库模式和存储库级别使用此查询构建器。当我在邮递员上测试这个 api 时,我得到了这个。
可能取决于 laravel 版本。
@shaedrich 那么我该如何解决这个问题?我已经阅读了几篇关于 mergeBindings 的文章,但我已经完成了相应的操作。对我没用。以上是关于如何在查询生成器中有效地转换嵌套 SQL [重复]的主要内容,如果未能解决你的问题,请参考以下文章
Azure 数据工厂:如何在转换数据流中实现嵌套 sql 查询
从 Excel VBA 运行嵌套的 Access SQL 查询