Сложный SQL-запрос с переменными

0

Что мой запрос, чтобы получить первые $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

Теги:
pdo

1 ответ

1
Лучший ответ

"Нам нужен уникальный каталог по всему миру"

Чтобы идентифицировать уникальные значения 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

  • 0
    Спасибо за Ваш ответ! Но этот запрос немного неправильный. Посмотрите здесь sqlfiddle.com/#!9/e42628/5 Здесь должно быть 5 строк. Строки с catalog_id '4926348963357290 и' 70000001018295015 должны быть включены
  • 0
    catalog_id 4926348963357290, по-видимому, не удовлетворяет спецификации «уникальный catalog_id глобально». Как я сказал в своем комментарии к вопросу, это действительно зависит от того, что такое спецификация, как спецификация интерпретируется. Мой комментарий спросил, означает ли спецификация, что мы должны возвращать только значения catalog_id которые являются уникальными в контактах, или мы просто catalog_id значение catalog_id не повторялось в результате. Опять же, именно здесь предоставление примера ожидаемого результата поможет прояснить спецификацию (так, как это делает «уникальный catalog_id глобально»).
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню