Mysql union 2 запроса, содержащие порядок по и случайный - PullRequest
0 голосов
/ 10 июня 2019

У меня есть таблица с колонками ниже: id (AI), статус (логическое 0 или 1), созданный в (datetime)

Я хочу получить записи со статусом = 1 и упорядочить их, созданные в DESC, другой получить случайные записи со статусом = 0

Я запускаю код, указанный ниже, но не могу вернуть правильный ответ.

(SELECT *
FROM
    `Teacher` AS `teacher`
WHERE
    `teacher`.`status` = 1 ORDER BY `created_at` desc)

UNION 

(SELECT *
FROM
   `Teacher` AS `teacher`
WHERE 
   `teacher`.`status` = 0 ORDER By rand())

Ответы [ 2 ]

0 голосов
/ 10 июня 2019

Я столкнулся с подобной проблемой некоторое время назад ... Нечто подобное должно решить это.

SELECT * FROM
(
(SELECT ROW_NUMBER() OVER (order by `created_at` desc) AS RowNumber, `status`, id, datetime
FROM
    `Teacher` AS `teacher`
WHERE
    `teacher`.`status` = 1 ORDER BY `created_at` desc)

UNION 

(SELECT ROW_NUMBER() OVER (order by rand()) AS RowNumber, `status`, id, datetime
FROM
    `Teacher` AS `teacher`
WHERE 
   `teacher`.`status` = 0 ORDER By rand())

   ) order by `status`, RowNumber;

давайте добавим столбец индекса строки (RowNumber) в таблицу 1 и таблицу 2 в соответствии с заданными критериями, чтобы убедиться в правильном порядке в статусе. и у нас уже есть столбец со значением состояния (status). затем просто выберите * с заказом на status, RowNumber предоставит вам именно то, что вам нужно. [Простите за синтаксические ошибки в запросе.]

0 голосов
/ 10 июня 2019

Оператор set UNION заставляет операцию «Использование сортировки файлов» идентифицировать и удалять дубликаты.

Оператор набора UNION ALL объединит два набора результатов, не вызывая операцию сортировки для выявления и удаления дубликатов.

Но просто заменив UNION на UNION ALL, мы будем полагаться на поведение, которое не гарантируется. Если нам нужны результаты, возвращаемые в определенном порядке, то в самом внешнем запросе должно быть предложение ORDER BY.

https://dev.mysql.com/doc/refman/8.0/en/union.html

Выдержка

Однако использование ORDER BY для отдельных операторов SELECT ничего не подразумевает в порядке, в котором строки появляются в конечном результате, поскольку UNION по умолчанию создает неупорядоченный набор строк.

...

(Если кто-то добавит столбец в одну из таблиц, это приведет к сбою этого запроса с несоответствием количества возвращаемых столбцов.)

(Недопустимая ссылка на teacher.status во втором SELECT.)

(Лично я добавил бы столбец дискриминатора к каждому набору, а затем сослался бы на это в предложении ORDER BY во внешнем запросе. Я также исключил бы * в списке SELECT и указал бы столбцы, которые должны быть вернулся.)


Я бы добился указанного результата примерно так:

( 
  SELECT 'teacher' AS src
       , t.fee
       , t.fi
       , t.fo
       , t.fum
    FROM `Teacher` t
   WHERE t.`status` = 1
)
UNION ALL
( 
  SELECT 'mission' AS src
       , m.one
       , m.two
       , m.buckle
       , m.myshoe
    FROM `bouhun`.`missions` m
   WHERE m.`status` = 0
)
ORDER
   BY src DESC
    , CASE src WHEN 'teacher' THEN created_at END DESC
    , CASE src WHEN 'mission' THEN RAND() END

* СЛЕДОВАТЬ *

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

С этим изменением я бы использовал только один SELECT.

И избегайте UNION / UNION ALL из двух комплектов.

Мы можем просто добавить несколько умных выражений в предложение ORDER BY.

Примерно так:

 SELECT t.*
   FROM `Teacher` t
  WHERE t.status IN (0,1)
  ORDER
     BY t.status                              DESC
      , IF( t.status=0 , t.created_at , NULL) DESC 
      , IF( t.status=1 , RAND()       , NULL) DESC
...