Подтвердить что ты не робот

Преобразование запросов SELECT DISTINCT ON из Postgresql в MySQL

Я использовал PostgreSQL и теперь перешел на MySQL.

В моих запросах я использую PostgreSQL SELECT DISTINCT ON (col1, col2, col3), мне было интересно, существует ли какая-либо копия этого оператора в MySQL.

4b9b3361

Ответ 1

Не существует точного эквивалента для преобразования запроса Postgresql, использующего SELECT DISTINCT ON для MySQL.

Postgresql SELECT DISTINCT ON

В Postgresql следующий запрос устранит все строки, в которых соответствуют выражения (col1, col2, col3), и будет содержать только "первую строку col4, col5" для каждого набора совпадающих строк:

SELECT DISTINCT ON (col1, col2, col3) col4, col5
FROM tablename

Итак, если ваша таблица выглядит так:

col1 | col2 | col3 | col4 | col5
--------------------------------
1    | 2    | 3    | 777  | 888
1    | 2    | 3    | 888  | 999
3    | 3    | 3    | 555  | 555

наш запрос будет содержать только одну строку для (1,2,3) и одну строку для (3,3,3). Результирующие строки будут следующими:

col4 | col5
-----------
777  | 888
555  | 555

обратите внимание, что "первая строка" каждого набора непредсказуема, наша первая часть может быть (888, 999), если мы не укажем ORDER BY:

SELECT DISTINCT ON (col1, col2, col3) col4, col5
FROM tablename
ORDER BY col1, col2, col3, col4

(DISTINCT на выражениях должны соответствовать крайним левым выражениям ORDER BY, но ORDER BY может содержать дополнительные выражения).

Расширение MySQL для GROUP BY

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

Итак, этот запрос Postgresql:

SELECT DISTINCT ON (col1, col2, col3) col4, col5
FROM tablename

можно считать эквивалентным этому запросу MySQL:

SELECT col4, col5
FROM tablename
GROUP BY col1, col2, col3

оба Postgresql и MySQL возвращают "Первая строка" для каждого (col1, col2, col3), и в обоих случаях возвращаемая строка непредсказуема, потому что мы не указывали и не заказывали предложение.

Многим людям очень хотелось бы преобразовать этот запрос Postgresql с помощью ORDER BY:

SELECT DISTINCT ON (col1, col2, col3) col4, col5
FROM tablename
ORDER BY col1, col2, col3, col4

с этим:

SELECT col4, col5
FROM (
  SELECT col1, col2, col3, col4, col5
  FROM tablename
  ORDER BY col1, col2, col3, col4
) s
GROUP BY col1, col2, col3

Идея здесь заключается в том, чтобы применить ORDER BY к подзапросу, так что когда MySQL группируется по col1, col2, col3, он будет хранить первое встреченное значение для col4 и col5. Идея хорошая, но это неправильно! MySQL может свободно выбирать любое значение для col4 и col5, и мы не знаем, какие первые значения встречаются, это зависит от оптимизатора. Поэтому я бы исправил это:

SELECT t1.col4, t1.col5
FROM tablename t1 INNER JOIN (SELECT col1, col2, col3, MIN(col4) as m_col4
                              FROM tablename
                              GROUP BY col1, col2, col3) s
     ON t1.col1=s.col1
        AND t1.col2=s.col2
        AND t1.col3=s.col3
        AND t1.col4=s.m_col4
GROUP BY
  t1.col1, t1.col2, t1.col3, t1.col4

но это начинает усложняться.

Заключение

Как правило, нет точного способа преобразования запроса Postgresql в запрос MySQL, но есть много обходных путей, результирующий запрос может быть таким же простым, как исходный, или может стать очень сложным, но это зависит от самого запроса.

Ответ 2

Используйте подзапрос, чтобы определить порядок, и внешний запрос для их группировки.

Как указывает @a_horse_with_no_name, это работает, потому что MySQL допускает частичный group by, в отличие от других СУБД.

Например:

CREATE TABLE customer_order
    (`customer` varchar(5), `item` varchar(6), `date` datetime)
;

INSERT INTO customer_order
    (`customer`, `item`, `date`)
VALUES
    ('alice', 'widget', '2000-01-05 00:00:00'),
    ('bob', 'widget', '2000-01-02 00:00:00'),
    ('alice', 'widget', '2000-01-01 00:00:00'),
    ('alice', 'wodget', '2000-01-06 00:00:00')
;

Запрос для каждого клиента первого порядка:

select *
from
  (select customer, item, date
  from customer_order
  order by date) c
group by customer

Результат:

| CUSTOMER |   ITEM |                           DATE |
|----------|--------|--------------------------------|
|    alice | widget | January, 01 2000 00:00:00+0000 |
|      bob | widget | January, 02 2000 00:00:00+0000 |

http://sqlfiddle.com/#!2/6cbbe/1

Ответ 3

Вы не можете выбрать отдельные значения из нескольких столбцов. при выборе использования запроса, подобного этому

select distinct col1, col2 from table

Ответ 4

вам следует перейти на PDO или MSYQLI вместо MYSQL, поскольку он уже устарел.

о вашем вопросе, который вы можете сделать

   SELECT DISTINCT col1, col2, col3

или

    SELECT col1, col2, col3
    ........

    GROUP BY col1 --//--- or whatever column you want to be distinct