Группировка по псевдониму

#sql #sql-server #database #database-design

#sql #sql-сервер #База данных #база данных-дизайн

Вопрос:

 SELECT COALESCE (rsu.last_name   ', '   rsu.first_name   ' '   rsu.middle_name   '.', rsu.last_name   ', '   rsu.first_name)  as student_name, rsu.day_id
FROM roster_school_unattended rsu
GROUP BY student_name
ORDER BY rsu.day_id
  

не работает. Какой самый элегантный обходной путь?

РЕДАКТИРОВАТЬ: Результирующий набор должен иметь что-то вроде этого

 Muster, Hans | 2011-11-01
Muster, Hans | 2011-11-02
Williams, Clay | 2011-10-01
Williams, Clay | 2011-10-02
  

Сначала имя группируется по, затем для каждого имени выполняется сортировка по датам.

Комментарии:

1. Вам нужно перестать думать в терминах «элегантный», когда вы запрашиваете базу данных. Часто наименее элегантный код является лучшим с точки зрения производительности базы данных, что гораздо важнее, чем «элегантность». Вы никогда не ошибетесь, написав код базы данных с точки зрения производительности (то, что, скорее всего, будет работать наилучшим образом) в первую очередь. Как только вы привыкнете к наиболее производительному типу SQL для вашей базы данных, его будет так же легко поддерживать, как и «элегантный» код.

2. Если вы намерены часто группировать имена вместе таким образом, я считаю, что лучше всего сделать это постоянным вычисляемым столбцом. Таким образом, вам не придется выполнять все эти неприятные действия по объединению и конкатенации более одного раза.

3. Кроме того, ваша правка показывает, что вам не нужна GROUP BY . Вы имеете в виду, что хотите, чтобы все было упорядочено по столбцу name, а затем по столбцу date.

Ответ №1:

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

 select t.student_name, t.day_id
from (
  select COALESCE (rsu.last_name   ', '   rsu.first_name   ' '   rsu.middle_name   '.', rsu.last_name   ', '   rsu.first_name) as student_name, 
    rsu.day_id
  from roster_school_unattended rsu ) t
group by t.student_name
order by t.day_id
  

Но у вас все еще есть проблема с идентификатором day_id — он не включен в ваше предложение группировки, поэтому вы не сможете выбрать его без использования aggregate (например, MAX).

Ответ №2:

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

 select student_name, day_id
from (SELECT COALESCE (rsu.last_name   ', '   rsu.first_name   ' '   rsu.middle_name   '.', rsu.last_name   ', '   rsu.first_name)  as student_name, rsu.day_id
FROM roster_school_unattended rsu
) as rows
GROUP BY student_name
ORDER BY day_id
  

Ответ №3:

РЕДАКТИРОВАТЬ: Все заменено, поскольку недавнее редактирование вопроса показывает, что GROUP BY не требуется…

Без каких-либо изменений для «элегантности»…

 SELECT
  rsu.last_name   ', '   rsu.first_name   COALESCE (' '   rsu.middle_name   '.', '') as student_name,
  rsu.day_id
FROM
  roster_school_unattended  AS [rsu]
ORDER BY
  rsu.last_name   ', '   rsu.first_name   COALESCE (' '   rsu.middle_name   '.', ''),
  rsu.day_id
  

Возможно изменение для «элегантности»…

 WITH formatted_rsu AS
(
  SELECT rsu.last_name   ', '   rsu.first_name   COALESCE (' '   rsu.middle_name   '.', '') as student_name, rsu.day_id
  FROM   roster_school_unattended  AS [rsu]
)
SELECT   student_name, day_id
FROM     formatted_rus
ORDER BY student_name, day_id
  

Другое возможное использование APPLY…

 SELECT      formatted_rsu.student_name, rsu.day_id
FROM        roster_school_unattended  AS [rsu]
CROSS APPLY (SELECT rsu.last_name   ', '   rsu.first_name   COALESCE (' '   rsu.middle_name   '.', '') as student_name) AS [formatted_rsu]
ORDER BY    formatted_rsu.student_name, rsu.day_id
  

Ответ №4:

Я бы пошел с:

 SELECT
    rsu.last_name
      ', '   rsu.first_name
      COALESCE ( ' '   rsu.middle_name   '.'
               , ''
               )
    AS student_name
  , rsu.day_id
FROM
    roster_school_unattended AS rsu
ORDER BY
    rsu.last_name
  , rsu.first_name
  , rsu.middle_name
  , rsu.day_id
  

Ответ №5:

CROSS APPLY ваш друг по псевдонимированию неоконных выражений:

 SELECT this.student_name, MAX(rsu.day_id) AS day_id
FROM roster_school_unattended rsu
CROSS APPLY (
  SELECT COALESCE (
      rsu.last_name ', ' rsu.first_name ' ' rsu.middle_name '.'
    , rsu.last_name ', ' rsu.first_name
    )  AS student_name
  ) this
GROUP BY this.student_name
ORDER BY this.student_name, MAX(rsu.day_id)
  

(предполагается, что SQL2005 и выше).