Страница 1 из 1

Помогите с sql-запросом

Добавлено: 11.11.2022 10:34:29
Newbee
Всем привет!

Давно не брал SQL в руки, но все циклично.
Есть вот такая табличка:

Код: Выделить всё

CREATE TABLE test_tbl (
	u_name varchar NOT NULL,
	u_color varchar NULL
);

INSERT INTO test_tbl (u_name, u_color) values ('Ivanov', 'RED');
INSERT INTO test_tbl (u_name, u_color) values ('Petrov', 'YELLOW');
INSERT INTO test_tbl (u_name, u_color) values ('Ivanov', 'RED');
INSERT INTO test_tbl (u_name, u_color) values ('Petrov', 'YELLOW');
INSERT INTO test_tbl (u_name, u_color) values ('Ivanov', 'GREEN');
INSERT INTO test_tbl (u_name, u_color) values ('Petrov', 'PERFECT');
INSERT INTO test_tbl (u_name, u_color) values ('Petrov', 'RED');
INSERT INTO test_tbl (u_name, u_color) values ('Sidorov', 'GREEN');
INSERT INTO test_tbl (u_name, u_color) values ('Sidorov', 'GREEN');
INSERT INTO test_tbl (u_name, u_color) values ('Sidorov', 'YELLOW');
INSERT INTO test_tbl (u_name, u_color) values ('Ivanov', 'RED');
INSERT INTO test_tbl (u_name, u_color) values ('Sidorov', 'PERFECT');
INSERT INTO test_tbl (u_name, u_color) values ('Sidorov', 'PERFECT');
INSERT INTO test_tbl (u_name, u_color) values ('Petrov', 'YELLOW');
INSERT INTO test_tbl (u_name, u_color) values ('Ivanov', 'GREEN');
INSERT INTO test_tbl (u_name, u_color) values ('Sidorov', 'RED');
INSERT INTO test_tbl (u_name, u_color) values ('Petrov', 'RED');
INSERT INTO test_tbl (u_name, u_color) values ('Petrov', 'GREEN');
INSERT INTO test_tbl (u_name, u_color) values ('Ivanov', 'YELLOW');
INSERT INTO test_tbl (u_name, u_color) values ('Sidorov', 'RED');
Нужен запрос, чтобы получить сумму цветов для каждой фамилии:
Name/Color|RED|YELLOW|GREEN|PURPLE
Ivanov | 3 | 1 | 2 | 0
Petrov | 2 | 3 | 1 | 1
Sidorov| 2 | 1 | 2 | 2

Re: Помогите с sql-запросом

Добавлено: 13.11.2022 00:59:13
zdn
Возможно так:

Код: Выделить всё

with
 RED as (select u_name, count(u_color) as color from test_tbl where u_color = 'RED' group by u_name),
 YELLOW as (select u_name, count(u_color) as color from test_tbl where u_color = 'YELLOW' group by u_name),
 GREEN as (select u_name, count(u_color) as color from test_tbl where u_color = 'GREEN' group by u_name),
 PURPLE as (select u_name, count(u_color) as color from test_tbl where u_color = 'PURPLE' group by u_name)
select RED.u_name, 
  coalesce(RED.color,0) as RED, 
  coalesce(YELLOW.color,0) as YELLOW, 
  coalesce(GREEN.color,0) as GREEN, 
  coalesce(PURPLE.color,0) as PURPLE
 from RED
  left join YELLOW on RED.u_name = YELLOW.u_name
  left join GREEN on YELLOW.u_name = GREEN.u_name
  left join PURPLE on GREEN.u_name = PURPLE.u_name
;

Re: Помогите с sql-запросом

Добавлено: 13.11.2022 13:36:49
fraks
В первичных данных нет цвета PURPLE, вместо него написан PERFECT.

Запрос может выглядеть так (синтаксис Firebird, для другого сервера может потребоваться заменить IIF на CASE или чего там еще есть):

Код: Выделить всё

select
  u_name,
  --
  sum( iif(u_color = 'RED'     , 1, 0) ) as RED,
  sum( iif(u_color = 'YELLOW'  , 1, 0) ) as YELLOW,
  sum( iif(u_color = 'GREEN'   , 1, 0) ) as GREEN,
  sum( iif(u_color = 'PERFECT' , 1, 0) ) as PERFECT,
  sum( iif(u_color = 'PURPLE'  , 1, 0) ) as PURPLE

from
  test_tbl

group by
  u_name

Re: Помогите с sql-запросом

Добавлено: 13.11.2022 13:44:16
fraks
Вот вариант для простгресса.

Код: Выделить всё

select
  u_name,
  --
  sum ( case when u_color = 'RED'     then 1 else 0 end ) as RED,
  sum ( case when u_color = 'YELLOW'  then 1 else 0 end ) as YELLOW,
  sum ( case when u_color = 'GREEN'   then 1 else 0 end ) as GREEN,
  sum ( case when u_color = 'PERFECT' then 1 else 0 end ) as PERFECT,
  sum ( case when u_color = 'PURPLE'  then 1 else 0 end ) as PURPLE

from
  test_tbl

group by
  u_name
;  

Код: Выделить всё

+=========+=====+========+=======+=========+========+
| u_name  | red | yellow | green | perfect | purple |
+=========+=====+========+=======+=========+========+
| Petrov  | 2   | 3      | 1     | 1       | 0      |
| Sidorov | 2   | 1      | 2     | 2       | 0      |
| Ivanov  | 3   | 1      | 2     | 0       | 0      |
+---------+-----+--------+-------+---------+--------+

Re: Помогите с sql-запросом

Добавлено: 14.11.2022 09:54:43
Newbee
Земной поклон за помощь!

Re: Помогите с sql-запросом

Добавлено: 15.11.2022 15:10:44
Newbee
А если предположить, что помимо Иванова, Петрова и Сидорова есть и другие фамилии, то можно их как-то объединить, например под "Остальные" и суммарно посчитать цвета и для них?
Конструкция "case when u_name in ('Ivanov', 'Petrov', 'Sidorov') then u_name else 'Other' end ) as u_name" явно не прокатит, так как все фамилии не из списка будут заменены на Other, но группировки и суммирования не произойдет.

Re: Помогите с sql-запросом

Добавлено: 16.11.2022 04:14:43
fraks
Newbee писал(а): 15.11.2022 15:10:44 Конструкция "case when u_name in ('Ivanov', 'Petrov', 'Sidorov') then u_name else 'Other' end ) as u_name" явно не прокатит, так как все фамилии не из списка будут заменены на Other, но группировки и суммирования не произойдет.
По какому полю сгруппируешь - по тому и будет. Группировать можно не только по полю но и по выражению.

Код: Выделить всё

select
  case when u_name in ('Ivanov', 'Petrov') then u_name else 'Other' end  as u_name,
  --
  sum ( case when u_color = 'RED'     then 1 else 0 end ) as RED,
  sum ( case when u_color = 'YELLOW'  then 1 else 0 end ) as YELLOW,
  sum ( case when u_color = 'GREEN'   then 1 else 0 end ) as GREEN,
  sum ( case when u_color = 'PERFECT' then 1 else 0 end ) as PERFECT,
  sum ( case when u_color = 'PURPLE'  then 1 else 0 end ) as PURPLE

from test_tbl
group by 1
;

Код: Выделить всё

+========+=====+========+=======+=========+========+
| u_name | red | yellow | green | perfect | purple |
+========+=====+========+=======+=========+========+
| Other  | 2   | 1      | 2     | 2       | 0      |
| Petrov | 2   | 3      | 1     | 1       | 0      |
| Ivanov | 3   | 1      | 2     | 0       | 0      |
+--------+-----+--------+-------+---------+--------+

Re: Помогите с sql-запросом

Добавлено: 16.11.2022 09:17:36
Newbee
Спасибо! Забыл что можно группировать по порядковому номеру, а не названию поля.

Re: Помогите с sql-запросом

Добавлено: 01.02.2023 15:55:07
Newbee
Всем доброго времени суток!

Продолжаю быть начинающим в PostgreSQL. Случилась крайне странная ситуация - не срабатывает команда update.
Для теста создал схему, в ней две таблицы - tbl и tbl_h, на обновление tbl повесил триггер - он перекидывает предыдущие значения в таблицу tbl_h (историческая). Запускаю update и commit (на всякий случай) - update "проходит", но в основной таблице ничего не меняется, а триггер срабатывает и добавляет строку в таблицу с историей.
Пытаюсь разобраться в чем проблема. Подскажите новичку куда копать.

Код: Выделить всё

DROP SCHEMA IF EXISTS test CASCADE;
DROP ROLE IF EXISTS test;
commit;

CREATE USER test WITH 
    NOSUPERUSER
    NOCREATEDB
    NOCREATEROLE
    INHERIT
    LOGIN
    NOREPLICATION
    NOBYPASSRLS
    CONNECTION LIMIT -1
    PASSWORD 'qwerty';
CREATE SCHEMA IF NOT EXISTS test AUTHORIZATION test;

CREATE TABLE test.tbl (
    tbl_id integer NOT NULL,
    tbl_name varchar(255) NOT NULL,
    CONSTRAINT tbl_pk PRIMARY KEY (tbl_id)
) WITH (
  OIDS=FALSE
);

CREATE TABLE test.tbl_h (
    tbl_id integer NOT NULL,
    tbl_name varchar(255) NOT NULL,
    tbl_h_dt TIMESTAMP
) WITH (
  OIDS=FALSE
);

CREATE OR REPLACE FUNCTION tbl_h_fnc ()
RETURNS trigger AS
$$
DECLARE

BEGIN
insert into test.tbl_h select t.tbl_id, t.tbl_name, current_timestamp from test.tbl t;
RETURN NULL;
END;

$$ LANGUAGE 'plpgsql';

CREATE TRIGGER tbl_h_trg
     BEFORE UPDATE ON test.tbl
     FOR EACH ROW EXECUTE PROCEDURE tbl_h_fnc();
     

ALTER TABLE test.tbl_h ADD CONSTRAINT tbl_h_fk FOREIGN KEY (tbl_id) REFERENCES test.tbl(tbl_id);


select * from test.tbl t;
select * from test.tbl_h th;

insert into test.tbl values (111, 'Test');

update test.tbl set tbl_name = 'BLABLABLA' where tbl_id = 111;
commit;
select * from test.tbl t;
select * from test.tbl_h th;
P.S. Все тесты гоняю в DBeaver 22.2.4.

Re: Помогите с sql-запросом

Добавлено: 06.02.2023 16:36:43
Newbee
Нашел сам.
В функции надо возвращать значение NEW, а не NULL.