SQL группа с заменой различных значений - PullRequest
0 голосов
/ 29 октября 2018

Возможно ли сгруппировать данные, но заменить другие значения, как (например) @, используя PostgreSQL. Или лучше и продуктивнее будет делать это с JAVA?

есть таблица со следующими данными

 id  name1  f1  f2  f3  f4  f5
  1   lol    0   1   1    0   0
  2   lol    0   1   1    0   0
  3   lol    0   1   1    0   0
  4   kek    1   1   1    1   0
  5   kek    2   1   1    0   0
  6   kek    4   1   1    0   0
  7   kek    3   1   1    0   0

и мне нужно получить имя с сгруппированными идентичными данными, но разные данные должны отображаться как some char Например:

  name1  f1  f2  f3  f4  f5
  lol    0   1   1   0   0
  kek    @   1   1   @   0

Ответы [ 3 ]

0 голосов
/ 29 октября 2018

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

SELECT
  name1,
  CASE WHEN array_length(array_agg(DISTINCT f1), 1) = 1 THEN min(f1)::text ELSE '@' END AS f1,
  CASE WHEN array_length(array_agg(DISTINCT f2), 1) = 1 THEN min(f2)::text ELSE '@' END AS f2,
  CASE WHEN array_length(array_agg(DISTINCT f3), 1) = 1 THEN min(f3)::text ELSE '@' END AS f3,
  CASE WHEN array_length(array_agg(DISTINCT f4), 1) = 1 THEN min(f4)::text ELSE '@' END AS f4,
  CASE WHEN array_length(array_agg(DISTINCT f5), 1) = 1 THEN min(f5)::text ELSE '@' END AS f5
FROM T
GROUP BY name1;

Что здесь происходит:

  1. Строки сгруппированы по name1
  2. Для каждой группы функция array_agg возвращает массив атрибутов данного поля
  3. Дубликаты в этом массиве удаляются предложением DISTINCT
  4. array_length функция возвращает количество элементов в массиве. Поскольку массив не имеет дубликатов, это количество уникальных элементов.
  5. С оператором CASE результат форматируется. Если массив имеет 1 элемент, он отображается (преобразуется в текст). В противном случае отображается @.

Песочница: https://www.db -fiddle.com / f / 3vxfeU8SzRRhtCcTvzj9fG / 0

0 голосов
/ 29 октября 2018

демо: дб <> скрипка

SELECT 
    name, 
    CASE WHEN COUNT(DISTINCT f1) > 1 THEN '@' ELSE MAX(f1)::text END as f1,
    CASE WHEN COUNT(DISTINCT f2) > 1 THEN '@' ELSE MAX(f2)::text END as f2,
    CASE WHEN COUNT(DISTINCT f3) > 1 THEN '@' ELSE MAX(f3)::text END as f3,
    CASE WHEN COUNT(DISTINCT f4) > 1 THEN '@' ELSE MAX(f4)::text END as f4,
    CASE WHEN COUNT(DISTINCT f5) > 1 THEN '@' ELSE MAX(f5)::text END as f5
FROM
    my_table
GROUP BY name

Для каждого столбца:

  1. Группа по имени
  2. Совокупный COUNT(DISTINCT) считает различные значения
  3. Все агрегаты, в которых количество дает более чем одно отличное значение, приводят к появлению вашего нового персонажа
  4. Другие выдают одно значение. (Поскольку вам нужны агрегатные функции, вызванные GROUP BY. Самый простой способ - взять MAX или MIN, это не имеет значения - есть только одно значение). Из-за добавления значения типа text все остальные значения должны быть преобразованы в один и тот же тип столбца, поскольку не допускается получение большего количества типов в одном столбце. Таким образом, если у вас действительно есть значения integer, то было бы лучше взять значение integer и для ваших "маркирующих" значений. Может быть, отрицательный может сделать это, если у вас нет отрицательных значений или что-то в этом роде.
0 голосов
/ 29 октября 2018

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

CREATE TABLE T(
  name1 varchar(50),
    f1 int,
   f2  int,
  f3 int, 
  f4 int,
  f5 int
);


INSERT INTO T VALUES ('lol',0,1,1,0,0);
INSERT INTO T VALUES ('lol',0,1,1,0,0);
INSERT INTO T VALUES ('lol',0,1,1,0,0);
INSERT INTO T VALUES ('kek',1,1,1,1,0);
INSERT INTO T VALUES ('kek',2,1,1,0,0);
INSERT INTO T VALUES ('kek',4,1,1,0,0);
INSERT INTO T VALUES ('kek',3,1,1,0,0);

Запрос 1 :

SELECT distinct
name1,
CASE WHEN  
(SELECT COUNT(DISTINCT f1) cnt
  FROM T tt 
  WHERE t1.name1 = tt.name1) > 1 THEN '@' ELSE t1.f1::VARCHAR(50) END,
  CASE WHEN  
(SELECT COUNT(DISTINCT f2) cnt
  FROM T tt 
  WHERE t1.name1 = tt.name1) > 1 THEN '@' ELSE t1.f2::VARCHAR(50) END,
  CASE WHEN  
(SELECT COUNT(DISTINCT f3) cnt
  FROM T tt 
  WHERE t1.name1 = tt.name1) > 1 THEN '@' ELSE t1.f3::VARCHAR(50) END,
  CASE WHEN  
(SELECT COUNT(DISTINCT f4) cnt
  FROM T tt 
  WHERE t1.name1 = tt.name1) > 1 THEN '@' ELSE t1.f4::VARCHAR(50) END,
    CASE WHEN  
(SELECT COUNT(DISTINCT f5) cnt
  FROM T tt 
  WHERE t1.name1 = tt.name1) > 1 THEN '@' ELSE t1.f5::VARCHAR(50) END  
FROM T t1 

Результаты :

| name1 | f1 | f2 | f3 | f4 | f5 |
|-------|----|----|----|----|----|
|   kek |  @ |  1 |  1 |  @ |  0 |
|   lol |  0 |  1 |  1 |  0 |  0 |
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...