这是我的查询,用于获取每个城市/子类别组合的前 $count
行
$contacts = $dbh->prepare("
SELECT *
FROM (SELECT c.*,
(@rn := IF(@cc = CONCAT_WS(':', city_id, subcategory_id), @rn + 1,
IF(@cc := CONCAT_WS(':', city_id, subcategory_id), 1, 1)
)
) as rn
FROM (SELECT reg.title as region_title, cnt.title, cnt.city_id, cnt.id, cnt.catalog_id, cnt.address, cnt.phone, cnt.email, cnt.website, cnt.subcategory_title, cnt.subcategory_id, cnt.manufacturer
FROM contacts as cnt
LEFT JOIN regions as reg
ON cnt.city_id = reg.id
WHERE city_id IN (".implode(',', $regions).") AND
subcategory_id IN (".implode(',', $categories).")
ORDER BY subcategory_title, city_id, title
) c CROSS JOIN
(SELECT @cc := '', @rn := 0) params
) c
WHERE rn <= $count");
我正在使用 $contacts->fetchAll(PDO::FETCH_GROUP);
按 reg.title 对行进行分组
[
['City 1'] = > [
[ contact 1 ],
[ contact 2 ],
...
],
['City 2'] = > [
[ contact 3 ],
[ contact 4 ],
...
]
...
]
现在我需要升级该查询,但它对我来说太复杂了:(所选行必须具有唯一的contacts.catalog_id值。
如何做到?
UPD
这是一个演示数据库 - http://sqlfiddle.com/#!9/ac71d7/2
最佳答案
“我们需要全局唯一的catalog_id”
识别 catalog_id
的唯一值在contacts
,我们可以使用这样的查询:
SELECT r.catalog_id
FROM contacts r
GROUP BY r.catalog_id
HAVING COUNT(1) = 1
也就是说,对于 contacts
中的给定行,如果 catalog_id
的值匹配catalog_id
contacts
中的任何其他行,即catalog_id
将从结果中排除。
如果我们想限制原始查询仅返回 catalog_id
的值,我们可以将此查询包含为内联 View ,并将其连接到具有匹配catalog_id的联系人中的行。
FROM contacts cnt
-- ------------
JOIN ( SELECT r.catalog_id
FROM contacts r
GROUP BY r.catalog_id
HAVING COUNT(1) = 1
) s
ON s.catalog_id = cnt.catalog_id
-- ------------
LEFT
JOIN regions reg
ON reg.id = cnt.city_id
<小时/>
编辑
如果对规范的解释不同,则代替含义 catalog_id
在联系人中必须是唯一,我们的意思是 catalog_id
结果中不应重复...我们可以使用相同的方法,但获取 id
的单个值来自contacts
对于每个 catalog_id
。我们可以编写这样的查询:
SELECT MAX(r.id) AS max_id
, r.catalog_id
FROM contacts r
GROUP BY r.catalog_id
我们可以使用 MIN() 聚合来代替 MAX()。目标是返回单个contacts.id
对于 catalog_id
的每个离散值.
我们可以将其作为内联 View 合并到查询中,匹配 max_id
从内联 View 到id
来自contacts
表。
类似这样的事情:
FROM contacts cnt
-- ------------
JOIN ( SELECT MAX(r.id) AS max_id
FROM contacts r
WHERE ...
GROUP BY r.catalog_id
) s
ON s.max_id = cnt.id
-- ------------
LEFT
JOIN regions reg
ON reg.id = cnt.city_id
我们可能想移动 WHERE
中的条件将外部查询的子句插入到该内联 View 中。如果我们不这样做,那么 max_id
内联 View 返回的可能引用 id
中的一行 ( contacts
)不满足 WHERE
中的条件条款。
重新定位WHERE
条件cnt
进入内联 View ...
SELECT d.*
FROM ( SELECT c.*
, ( @rn := IF( @cc = CONCAT_WS(':', city_id, subcategory_id)
, @rn + 1
, IF( @cc := CONCAT_WS(':', city_id, subcategory_id),1,1)
)
) AS rn
FROM ( SELECT reg.title AS region_title
, cnt.title
, cnt.city_id
, cnt.id
, cnt.catalog_id
, cnt.address
, cnt.phone
, cnt.email
, cnt.website
, cnt.category_title
, cnt.subcategory_title
, cnt.subcategory_id
, cnt.manufacturer
FROM contacts cnt
-- --------------
JOIN ( SELECT MAX(r.id) AS max_id
FROM contacts r
WHERE r.city_id IN ( ... )
AND r.subcategory_id IN ( ... )
AND r.email IS NOT NULL
AND r.manufacturer = 1
GROUP BY r.catalog_id
) s
ON s.max_id = cnt.id
-- --------------
LEFT
JOIN regions reg
ON reg.id = cnt.city_id
ORDER
BY cnt.category_title
, cnt.subcategory_title
, cnt.city_id
, cnt.title
) c
CROSS
JOIN ( SELECT @cc := '', @rn := 0) i
) d
WHERE d.rn <= 10
<小时/>
关于php - 带变量的复杂sql查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47763516/