MySQL, использующий GROUP BY после нескольких UNIONS - PullRequest
0 голосов
/ 10 мая 2018

У меня довольно сложный MySQL Query с несколькими UNION операторами. Я пытаюсь исключить дубликаты из окончательного вывода, но не все столбцы идентичны (включая идентификатор). Поэтому я хочу использовать GROUP BY в столбце «имя», чтобы исключить записи с тем же именем. Это для карты коллажей из ряда других слоев карты. Некоторые из маркеров мест появляются на нескольких слоях (то есть ресторан может появляться на слое «обеденный», а также на слое «бары» и слое «Домашняя кухня», каждый с различным идентификатором).

Каждый оператор UNION SELECT создает только одну строку с именем места, но к концу, после выполнения всех UNION, у меня будет несколько записей для одного и того же места. Поэтому я чувствую, что мне нужно каким-то образом обрабатывать GROUP BY на всех данных после каждого UNION.

Я попытаюсь проиллюстрировать упрощенной версией утверждения ...

(
    SELECT l.id AS lid, m.markername AS markername, m.id AS mid, m.layer AS mlayer
    FROM layertable 
    INNER JOIN markertable 
    ON m.layer LIKE Concat('%"',l.id,'"%') 
    WHERE l.id='66' 
    ## RESULT INCLUDES Joes Place AND Eatery
)
UNION
(
    SELECT l.id AS lid, m.markername AS markername, m.id AS mid, m.layer AS mlayer
    FROM layertable 
    INNER JOIN markertable 
    ON m.layer LIKE Concat('%"',l.id,'"%') 
    WHERE l.id='82' 
    ## RESULT INCLUDES Joes Place AND Eatery
)
UNION
(
    SELECT l.id AS lid, m.markername AS markername, m.id AS mid, m.layer AS mlayer
    FROM layertable 
    INNER JOIN markertable 
    ON m.layer LIKE Concat('%"',l.id,'"%') 
    WHERE l.id='91' 
    ## RESULT INCLUDES Joes Place
)

ORDER BY markername ASC
LIMIT 10

Результаты выглядят примерно так ...

| lid | markername | mid | mlayer               |
=================================================
| 66  | Joes Place | 10  | ["66","82","91"]     |
| 82  | Joes Place | 10  | ["66","82","91"]     |
| 91  | Joes Place | 10  | ["66","82","91"]     |
| 66  | Eatery     | 11  | ["66","82"]          |
| 82  | Eatery     | 11  | ["66","82"]          |

То, что я хочу, это ...

| lid | markername | mid | mlayer               |
=================================================
| 91  | Joes Place | 10  | ["66","82","91"]     |
| 82  | Eatery     | 11  | ["66","82"]          |

DISTINCT, похоже, не работает, потому что записи не полностью идентичны.

Я пытался поставить GROUP BY markername до и после ORDER BY, но я получаю сообщение об ошибке синтаксиса в любом случае. Применение его внутри отдельного SELECT S не помогает, потому что в любом случае у каждой таблицы будет только один экземпляр этого места.

Итак, чтобы повторить мой вопрос: Как применить GROUP BY к общему списку после UNION и вывести только уникально названные места? ИЛИ есть ли другой способ выполнить эту задачу?

Заранее спасибо.

Ответы [ 4 ]

0 голосов
/ 10 мая 2018

Вы можете сделать GROUP BY всех результатов, например:

SELECT * FROM 
(
    SELECT l.id AS lid, m.markername AS markername, m.id AS mid, m.layer AS mlayer
    FROM layertable AS l
    INNER JOIN markertable 
    ON m.layer LIKE Concat('%"',l.id,'"%') 
    WHERE l.id='66' 
    ## RESULT INCLUDES Joes Place AND Eatery
)
UNION
(
    SELECT l.id AS lid, m.markername AS markername, m.id AS mid, m.layer AS mlayer
    FROM layertable AS l
    INNER JOIN markertable 
    ON m.layer LIKE Concat('%"',l.id,'"%') 
    WHERE l.id='82' 
    ## RESULT INCLUDES Joes Place AND Eatery
)
UNION
(
    SELECT l.id AS lid, m.markername AS markername, m.id AS mid, m.layer AS mlayer
    FROM layertable AS l
    INNER JOIN markertable 
    ON m.layer LIKE Concat('%"',l.id,'"%') 
    WHERE l.id='91' 
    ## RESULT INCLUDES Joes Place
)

ORDER BY markername ASC
LIMIT 10
) AS makernames
GROUP BY makername

Или вы можете просто пропустить части, которые делают результаты неуникальными.Например:

(
    SELECT m.markername AS markername, m.id AS mid, m.layer AS mlayer
    FROM layertable AS l
    INNER JOIN markertable 
    ON m.layer LIKE Concat('%"',l.id,'"%') 
    WHERE l.id='66' 
    ## RESULT INCLUDES Joes Place AND Eatery
)
UNION
(
    SELECT m.markername AS markername, m.id AS mid, m.layer AS mlayer
    FROM layertable AS l
    INNER JOIN markertable 
    ON m.layer LIKE Concat('%"',l.id,'"%') 
    WHERE l.id='82' 
    ## RESULT INCLUDES Joes Place AND Eatery
)
UNION
(
    SELECT m.markername AS markername, m.id AS mid, m.layer AS mlayer
    FROM layertable AS l
    INNER JOIN markertable 
    ON m.layer LIKE Concat('%"',l.id,'"%') 
    WHERE l.id='91' 
    ## RESULT INCLUDES Joes Place
)

ORDER BY markername ASC
LIMIT 10 

Вам не нужно иметь l.id в предложении SELECT, чтобы оно работало в предложении WHERE.И я предполагаю, что если вы готовы потерять lid в некоторых строках, чтобы иметь только одну строку на makername, это означает, что вам на самом деле не нужно lid в результатах.

0 голосов
/ 10 мая 2018

Вы можете сделать все это одним запросом:

SELECT max(l.id) AS lid, m.markername AS markername, m.id AS mid, m.layer AS mlayer
FROM layertable 
INNER JOIN markertable 
ON m.layer LIKE Concat('%"',l.id,'"%') 
  WHERE l.id in ('66','82','91')
GROUP BY m.markername, m.id, m.layer
0 голосов
/ 10 мая 2018

(это должен быть комментарий, но он немного длиннее)

потому что записи не полностью идентичны

Тогда вы ДОЛЖНЫ БЫТЬ БОЛЬШЕ УКАЗАННЫМИ О ЧЕМ ВЫ ДУБЛИКАЕТЕ. В вашем примере вы извлекли MAX (l.id) - это ваше намерение?

Почему вы используете СОЮЗ здесь? Вы могли бы просто ...

SELECT MAX(lid), markername, mid, mlayer
FROM ( 
  SELECT l.id AS lid, m.markername, m.id AS mid, m.layer AS mlayer
  FROM layertable 
  INNER JOIN markertable 
  ON m.layer LIKE Concat('%"',l.id,'"%') 
  WHERE l.id IN ('91', '82', '66')
  LIMIT 10
) AS ilv
GROUP BY markername, mid, mlayer

Использование LIKE - это JOIN, это ужасно и подразумевает, что ваши данные не нормализованы. Почему целые значения цитируются в вашем запросе?

(обратите внимание, что подвыбор может быть избыточным / ускорять или замедлять их в зависимости от распределения ваших данных и доступных индексов).

Не думаете ли вы, что вы должны организовывать картографические данные в соответствии с геопространственной индексацией?

0 голосов
/ 10 мая 2018

Вы можете использовать группу по и max (id)

  select max(lid), markername, mid, mlayer 
  from (


  (
      SELECT l.id AS lid, m.markername AS markername, m.id AS mid, m.layer AS mlayer
      FROM layertable 
      INNER JOIN markertable 
      ON m.layer LIKE Concat('%"',l.id,'"%') 
      WHERE l.id='66' 
      ## RESULT INCLUDES Joes Place AND Eatery
  )
  UNION
  (
      SELECT l.id AS lid, m.markername AS markername, m.id AS mid, m.layer AS mlayer
      FROM layertable 
      INNER JOIN markertable 
      ON m.layer LIKE Concat('%"',l.id,'"%') 
      WHERE l.id='82' 
      ## RESULT INCLUDES Joes Place AND Eatery
  )
  UNION
  (
      SELECT l.id AS lid, m.markername AS markername, m.id AS mid, m.layer AS mlayer
      FROM layertable 
      INNER JOIN markertable 
      ON m.layer LIKE Concat('%"',l.id,'"%') 
      WHERE l.id='91' 
      ## RESULT INCLUDES Joes Place
  )

  ORDER BY markername ASC
  LIMIT 10 
  ) t
  group by markername, mid, mlayer 
...