ВЫБОР из предыдущей записи и использование двух основных ORDER BY (s) - PullRequest
0 голосов
/ 28 октября 2011

пользователи:

user_id    user_name     
---------------------

 1          User A
 2          User B

отслеживание:

user_id     track         
---------------------

 1           no
 2           no

приложения:

user_id    date_of_application   date_ended    grade    status    
---------------------------------------------------------------

 1            2011-01-01         2011-02-28     1.0     Ended
 1            2011-02-02         2011-03-28     1.0     Ended
 1            2011-03-03         2011-04-28     (1.5)   Ended

 2            2011-01-01         2011-02-20     2.0     Ended
 2            2011-02-02         2011-03-11     2.5     Ended
 2            2011-03-03         2011-04-28     (1.0)   Ended

 1            2011-05-10              -          -      Pending
 2            2011-05-15              -          -      Pending
  • обратите внимание, что таблица может содержать несколько записей одной и той жепользователь, если все его предыдущие приложения закончились (статус = закончен)
  • user_id не является уникальным (относится только к таблице приложений)
  • дата в ГГ-ММ-ДД формат
  • дата_конечный и оценка обновляются только в момент окончания приложения
  • также, как я понимаючто для 'status', вероятно, рекомендуется иметь собственную таблицу, однако я бы предпочел, чтобы вышеуказанные таблицы были взяты как есть (за исключением опечаток и значительных ошибок, конечно)

Что я хочуздесь можно получить все строки , ГДЕ состояние 'Ожидание' и такое, что значение для столбца оценка для каждой из этих полученных строк является значением последняя оценка (другими словами, строка с последней датой), (в скобках выше), где статус «Завершено» для данного конкретного пользователя (или строки).

Кроме того, мне нужно иметь первые 10 строк изрезультат будет заказан по класс ASC .И иметь последующие строки после этого ( 11-й ряд до последней строки ) для ORDERed BY date_of_application ASC .

Очевидно, что SQL-запросы не самая сильная моя область, поэтому я не уверен, лучше ли (или возможно ли) выполнять ORDER BY (s), используя 2 или более запросов.Однако я предпочитаю, чтобы это делалось с использованием только одного запроса.

Желаемый результат:

user_id   user_name   date_of_application   grade   status   track 
--------------------------------------------------------------------

 1         User A         2011-05-10        (1.5)    Pending    no
 2         User B         2011-05-15        (1.0)    Pending    no

Рабочий код, который у меня есть на моем конце [минус возможные опечатки], (и перечисленные дополнения должны быть применены) :

  • последний класс
  • ORDER BY оценка (первые 10), ORDER BY date_of_application (с 11-го по последний ряд)

Запрос:

SELECT users.user_name,
       t.track,
       a.user_id,
       a.date_of_application,
       a.status,
       (SELECT ae.grade
          FROM applications AS ae
          WHERE ae.status = 'Ended' 
            AND ae.user_id = a.user_id                                                            
         LIMIT 1) AS grade
  FROM users
  JOIN applications AS a ON users.user_id = a.user_id
  JOIN tracking AS t ON users.user_id = t.user_id
 WHERE a.status = 'Pending'
ORDER BY grade ASC

Ответы [ 2 ]

2 голосов
/ 28 октября 2011

Вы, вероятно, пытаетесь сделать слишком много в одном запросе здесь.

В любом случае, если вы хотите, чтобы что-то повредило ваши глаза:

 select a.* from
 (
 SELECT u.user_name,
 a.user_id,
 a.date_of_application,
 td.grade,
 a.status,
 t.track
 FROM users u
 JOIN applications AS a ON u.user_id = a.user_id
 JOIN tracking AS t ON u.user_id = t.user_id
 LEFT OUTER JOIN
 (
 select ap.user_id,ap.grade 
 from applications ap
 inner join
 (select a.user_id,max(date_ended) as max_ended_date
 from applications a
 where a.status = 'Ended'
 group by a.user_id
 ) md on md.user_id = ap.user_id and ap.date_ended = md.max_ended_date
 ) as td on u.user_id = td.user_id
 WHERE a.status = 'Pending'
 ORDER BY cast(replace(replace(td.grade,'(',''),')','') as decimal(12,2)),u.user_id ASC
 LIMIT 10
 ) a
 WHERE grade is not null
 UNION ALL
 select b.* from
 (
 SELECT u.user_name,
   u.user_id,
   a2.date_of_application,
   td.grade,
   ifnull(a2.status,'No applications yet') as status,
   t2.track
 FROM users u
 LEFT OUTER JOIN (select user_id,date_of_application,status from applications where     status = 'Pending') AS a2 ON u.user_id = a2.user_id
 JOIN tracking AS t2 ON u.user_id = t2.user_id
 LEFT OUTER JOIN
 ( 
 select ap.user_id,ap.grade 
 from applications ap
 inner join
  (select a.user_id,max(date_ended) as max_ended_date
  from applications a
  where a.status = 'Ended'
  group by a.user_id
 ) md on md.user_id = ap.user_id and ap.date_ended = md.max_ended_date
 ) as td on u.user_id = td.user_id
 where u.user_id not in (
 select t1.user_id
 from (
 select ap1.user_id,ap1.grade 
  from applications ap1
  inner join
  (select a1.user_id,max(date_ended) as max_ended_date
   from applications a1
   where a1.status = 'Ended'
   group by a1.user_id
  ) md1 on md1.user_id = ap1.user_id and ap1.date_ended = md1.max_ended_date
  order by cast(replace(replace(ap1.grade,'(',''),')','') as decimal(12,2)),md1.user_id asc
  limit 10
  ) as t1
 )
 ORDER BY status desc,a2.date_of_application ASC
 ) b;

Это делает следующие предположения:

  1. Всегда есть только одна строка для каждого user_id в users и tracking стол

EDIT

Чтобы объяснить этот запрос немного:

Встроенный просмотр с псевдонимом a (он же «The Top Half») возвращает список из 10 лучших пользователей в соответствии с их последним возрастанием по окончанию класса. Обратите внимание на следующую часть запроса, которая убирает все скобки из оценки, преобразует полученное число в десятичное или 2 десятичных разряда и упорядочивает их по возрастанию по классу, а затем, в случае равных баллов, по user_id:

ORDER BY cast(replace(replace(td.grade,'(',''),')','') as decimal(12,2)),u.user_id ASC

Встроенное представление b во многом аналогично встроенному представлению a, за исключением того, что исключает пользователей, которые появятся в верхней половине, и упорядочивает результаты по статусу DESC (чтобы переместить пользователей без приложений в нижнюю часть). списка) и дата подачи заявки ASC.

1 голос
/ 28 октября 2011

Это должно хорошо работать для вас ... Чтобы прояснить, что происходит, вы должны начать с самой внутренней части запроса. Для каждого пользователя найдите самую высокую «ожидающую» дату (поскольку, как вы указали, будет только одну) и последнюю дату «Завершенного» класса. Группировка по пользователю. Это гарантирует одну запись для каждого пользователя, причем обе они рассчитываются заранее как PreQuery.

Затем выполните самостоятельное присоединение к таблице приложений ДВАЖДЫ ... один раз по пользователю и дате последнего завершения, затем по пользователю и дате последнего ожидания. Если вы выполните ЛЕВНОЕ СОЕДИНЕНИЕ, если у вас есть только человек, у которого есть приложение и у которого нет конца, они будут включены ... аналогично, если только законченный класс, в котором больше нет ожидающих приложений, они тоже будут включены.

Извлеките соответствующие столбцы из этих псевдонимов, чтобы получить оценку. Пока мы на этом, используя переменные SQL и используя порядок запросов по классу, DESCENDING выставит лучшие оценки от 1-n безотносительно к дате подачи заявки.

Наконец, возьмите весь этот набор результатов и выполните специальный порядок по ... Порядку при условии, что, если рейтинг пользователя меньше 11, используйте его порядок. В противном случае, пусть у всех остальных будет одинаковое значение «11» для первого заказа по частям ... После этого, заказ по дате заявки.

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

select
      QryRank.*
   from
      ( select
            PreQuery.User_ID,
            usr.user_Name,
            trk.Track,
            PreQuery.LastEnded,
            appEnd.Grade,
            PreQuery.LastPend as Date_Of_Application,
            @Rank := @Rank +1 UserRank
         from
            ( select
                  app.user_id,
                  max( if( app.status = "Ended", date_ended, null ) ) as LastEnded,
                  max( if( app.status = "Pending", app.date_of_application, null )) LastPend
               from
                  Applications app
               group by
                  app.user_id ) PreQuery

            LEFT JOIN Applications appEnd
               on PreQuery.User_ID = appEnd.User_ID
              AND PreQuery.LastEnded = appEnd.date_ended

            LEFT JOIN Applications appPend
               on PreQuery.User_ID = appPend.User_ID
               AND PreQuery.LastPend = appPend.date_of_application

            join Users usr   
               on PreQuery.user_id = usr.user_id

            join Tracking trk
               on PreQuery.user_id = trk.user_id,

            ( select @Rank := 0 ) sqlvars

         order by
            appEnd.Grade DESC ) QryRank
    order by
       if( QryRank.UserRank < 11, QryRank.UserRank, 11 ),
       QryRank.Date_Of_Application
...