Как мне агрегировать / сортировать результаты одного столбца на основе данных в другом?

#sql #group-by #count

#sql #группировать по #количество

Вопрос:

У меня есть таблица, отображающая три столбца: A, B, C. Столбец A имеет повторяющиеся значения. Как мне отсортировать результаты на основе столбца C?

Например:

 A                   B                C
Amanda                            healthy
Amanda                            healthy
Brian                             healthy
Brian                               sick
Brian                             healthy
Colleen                            [null]
Colleen                             sick
Tyler                              healthy
Tyler                               [null]
Tyler                               fever
Daniel                              [null]
Daniel                              [null]
Daniel                              [null]

  

Итак, это всего лишь пример. Я оставил столбец B пустым, потому что здесь это не имеет большого значения. То, что я пытаюсь сделать, это агрегировать дубликаты в A на основе результатов в C. Если все результаты равны нулю, то это должно показать мне значение 0. Если все результаты исправны или представляют собой смесь исправных и нулевых значений, то мне нужно значение 1. Если в результатах есть какое-либо упоминание о болезни, я хочу, чтобы это было значением 2.

Так, например, в приведенном выше примере я хочу, чтобы Аманда присвоила мне значение 1, Брайан 2, Коллин 2, Тайлер 2, Дэниел 0. Есть мысли о том, как я могу это сделать? Спасибо!

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

1. Пожалуйста, поделитесь тем, что вы пробовали, чтобы вы могли получить лучшее решение

2. Пожалуйста, отметьте свою СУБД (какую БД вы используете: MySQL, MSSQL и т.д.).

Ответ №1:

Из ваших данных и результатов это выглядит как хотите count(distinct) :

 select a, count(distinct c) cnt
from mytbale
group by a
  

Из описания вашего вопроса это немного отличается. Вы можете использовать case выражение:

 select 
    a,
    case 
        when max(case when c = 'sick'    then 1 else 0 end) = 1 then 2
        when max(case when c = 'healthy' then 1 else 0 end) = 1 then 1
        when count(c) = 0 then 0
    end as res
from mytable
group by a
  

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

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

Ответ №2:

Первый шаг: зарегистрируйте инциденты (да / нет = 1/0) возможных результатов в C для каждого A:

 SELECT a,BIT_XOR(CASE WHEN c IS NULL THEN 1 WHEN c="healthy" THEN 2 ELSE 4 END) FROM table GROUP BY a;
  

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

В этом запросе выходные данные являются:

  • 1, если все равно NULL (для c).
  • 2, если все «исправно».
  • 3 если все «исправные» (по крайней мере 1) или НУЛЕВЫЕ (по крайней мере один)
  • в противном случае (1xxb), если есть хотя бы один случай «болезни» / «лихорадки».

Чтобы адаптировать эти выходные данные к вашим желаемым значениям (0/1/1/2 для соответствующих случаев), запрос может быть адаптирован, например

 SELECT a,If(bitmap=1,0,IF(bitmapamp;4,2,1)) FROM 
(SELECT a,BIT_XOR(CASE WHEN c IS NULL THEN 1 WHEN c="healthy" THEN 2 ELSE 4 END) bitmap FROM table GROUP BY a) tmp;
  

PS: если у вас аллергические реакции на этот вложенный запрос (например, потому что сервер SQL может не оптимизировать его сам), просто перепишите его в один запрос, повторив внутреннее выражение, или просто переведите значения исходного запроса на принимающей стороне.

Ответ №3:

Этот сценарий предназначен для oracle, но «select» — это SQL-92. Надеюсь, это будет полезно для вас.

 create table anamnesis (
    a varchar(20),
    c varchar(20)
);

INSERT ALL
  INTO anamnesis (a, c) VALUES ('Amanda','healthy')
  INTO anamnesis (a, c) VALUES ('Amanda','healthy')
  INTO anamnesis (a, c) VALUES ('Brian','healthy')
  INTO anamnesis (a, c) VALUES ('Brian','sick')
  INTO anamnesis (a, c) VALUES ('Brian','healthy')
  INTO anamnesis (a, c) VALUES ('Colleen',null)
  INTO anamnesis (a, c) VALUES ('Colleen','sick')
  INTO anamnesis (a, c) VALUES ('Tyler','healthy')
  INTO anamnesis (a, c) VALUES ('Tyler',null)
  INTO anamnesis (a, c) VALUES ('Tyler','fever')
  INTO anamnesis (a, c) VALUES ('Daniel',null)
  INTO anamnesis (a, c) VALUES ('Daniel',null)
  INTO anamnesis (a, c) VALUES ('Daniel',null)
SELECT * FROM dual;

select t.a, (case when sick>0 then 2 else
                 case when healthy>0 then 1 else
                                          0
                 end
             end
            ) res
from
(select 
 t.a,
 sum(case when t.c is null then 1 else 0 end) nullable,
 sum(case when t.c='healthy' then 1 else 0 end) healthy,
 sum(case when coalesce(t.c,'-') not in ('-','healthy') then 1 else 0 end) sick
 from
 anamnesis t
 group by t.a) t;