Что мой запрос, чтобы получить первые $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
в 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
, мы могли бы включить этот запрос как встроенное представление и присоединить его к строкам в контактах с соответствующим каталогом.
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
.
Мы можем включить это в запрос как встроенное представление, сопоставляя max_id
со встроенным представлением с 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
внешнего запроса в это встроенное представление. Если мы этого не сделаем, то max_id
возвращаемый встроенным представлением, может ссылаться на строку (id
) в contacts
, которая не удовлетворяет условиям в WHERE
.
Перемещение условий WHERE
на cnt
во встроенный просмотр...
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
catalog_id
которые являются уникальными в контактах, или мы простоcatalog_id
значениеcatalog_id
не повторялось в результате. Опять же, именно здесь предоставление примера ожидаемого результата поможет прояснить спецификацию (так, как это делает «уникальный catalog_id глобально»).