C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
sql запрос на основании двух столбцов
telepath
Отправлено: 09.03.2005, 15:05


Станционный диспетчер

Группа: Участник
Сообщений: 132



Можно ли получить результат сгруппированный по двум столбцам, если третий результат статистической функции.
Например, есть таблица REC
поля:
rec_id (id записи)
years (за какой год запись)
per_id (за какой период)
org_id (от какой организации)

мне нужно получить список id записей последних периодов за год
запрос типа:

CODE

SELECT rec.org_id, max(rec.per_id) FROM rec WHERE
rec.years_num=2004
group by rec.org_id


работает, но выводит только org_id и max
никак не могу прикрутить сюда rec_id.
В книжке прочитал, что при группировке по двум столбцам sql обеспечивает только один уровень группировки. Можно ли это как-то обойти или сделать по другому?
Субд FireBird, работаю через FIBPlus
olegenty
Отправлено: 09.03.2005, 15:34


Ветеран

Группа: Модератор
Сообщений: 2412



а что,
SQL
SELECT
rec.rec_id,
rec.org_id,
max(rec.per_id)
FROM rec WHERE rec.years_num=2004
group by
rec.rec_id,
rec.org_id

не даёт желаемого результата?
кстати, если rec_id — уникальный ID записи, то такой запрос бессмысленен, записей будет столько, сколько rec_id придётся на условие rec.years_num=2004
AVC
Отправлено: 09.03.2005, 15:42


Ветеран

Группа: Модератор
Сообщений: 1583



А может нужен первый встречный rec_id (0 или 1) для каждого org_id у которого per_id максимален внутри группы org_id ?
telepath
Отправлено: 09.03.2005, 15:51


Станционный диспетчер

Группа: Участник
Сообщений: 132



да, rec_id уникальный идентификатор
нужна выборка max(per_id) из групп org_id и rec_id этих записей
т.е. записей в результате должно быть не больше кол-ва организаций

Отредактировано telepath — 09/03/2005, 15:54
olegenty
Отправлено: 09.03.2005, 15:59


Ветеран

Группа: Модератор
Сообщений: 2412



тогда тебе нужно делать это в 2 этапа:
1. получить org_id и max(per_id)
2. по некоторому правилу зацепить rec_id, например, максимальный или минимальный rec_id для записи, удовлетворяющей НД действия 1

в Firebird 1.5 ещё НЕ поддерживает подзапросов, поэтому, как ни грустно, действие п.1 надо выносить либо во VIEW, либо в ХП (предпочтительно ХП с условием по years_num), а затем результат VIEW/ХП джоинить по условию с этой же таблицей для вытягивания rec_id
AVC
Отправлено: 09.03.2005, 16:02


Ветеран

Группа: Модератор
Сообщений: 1583



Рабочий вариант (если я правильно понял вопрос)
CODE

/*
create table rec
(rec_id integer
,year_num integer
,org_id integer
,per_id integer
);
*/
--delete from rec;
--insert into rec Values (1,2005,1,1);
--insert into rec Values (2,2005,1,1);
--insert into rec Values (3,2005,1,2);
--insert into rec Values (4,2005,1,2);
--insert into rec Values (5,2005,2,1);
--insert into rec Values (6,2005,2,1);
--insert into rec Values (7,2005,2,2);
--insert into rec Values (8,2005,2,2);
--insert into rec Values (9,2005,2,2);

-- Select * From rec


Select
--  r.*
-- ,r.org_id * 10000 + r.per_id
max(rec_id) as rec_id
From rec r
Where 1 = 1
 and (r.org_id * 10000 + r.per_id) in
  (
   Select (r1.org_id * 10000 + max(r1.per_id)) From rec r1
   Where r1.year_num = 2005
   Group by r1.org_id
  )
Group by r.org_id, r.per_id

-- возвращает Rec_id = 4, 9

Жаль, что это FB
telepath
Отправлено: 09.03.2005, 16:02


Станционный диспетчер

Группа: Участник
Сообщений: 132



понятно, жаль...
Спасибо smile.gif
olegenty
Отправлено: 09.03.2005, 16:10


Ветеран

Группа: Модератор
Сообщений: 2412



я припозднился с ответом, но, всё же, прочти сообщение, что до AVC, предлагаемое там решение — рабочее.
telepath
Отправлено: 09.03.2005, 16:55


Станционный диспетчер

Группа: Участник
Сообщений: 132



про ХП я писал, у нас админы дурные sad.gif
если только представление сделать.
Попробую что быстрее получится, хотя этот запрос достаточно редко будет использоваться
olegenty
Отправлено: 09.03.2005, 17:06


Ветеран

Группа: Модератор
Сообщений: 2412



кстати, если правило для rec_id будет заключаться в min/max, то всё ещё проще:
SQL
SELECT org_id, max(rec_id), max(per_id)
FROM rec WHERE years_num=2004
group by
rec.org_id
AVC
Отправлено: 09.03.2005, 17:15


Ветеран

Группа: Модератор
Сообщений: 1583



Красиво.
telepath
Отправлено: 09.03.2005, 17:38


Станционный диспетчер

Группа: Участник
Сообщений: 132



ух! smile.gif
Спасибо smile.gif
AVC
Отправлено: 09.03.2005, 18:17


Ветеран

Группа: Модератор
Сообщений: 1583



Извиняюсь. Красиво, но неправильно.
Мы находим max(rec_id) для данного org_id, а нужно max(rec_id) для данного org_id и для данного (максимального) per_id

Например, если добавить в мой скрипт
insert into rec Values (10, 2005, 2, 1);
то все увидете сами
olegenty
Отправлено: 10.03.2005, 08:19


Ветеран

Группа: Модератор
Сообщений: 2412



да, правильно, я такое повидение и имел в виду для простейшего правила (оно же вырожденное). а общий случай — как раньше сказал... smile.gif

идеально решается как select ... from (select ... from rec ...) x join rec r ...
olegenty
Отправлено: 10.03.2005, 08:42


Ветеран

Группа: Модератор
Сообщений: 2412



2 telepath вот тебе реальное рабочее решение для Firebird (для других СУБД это будет скорее изврат), которое я имел в виду (оттестил, даже работает):

SQL
/*create table rec
(rec_id integer
,year_num integer
,org_id integer
,per_id integer
);*/

--delete from rec; --insert into rec Values (1,2005,1,1);
--insert into rec Values (2,2005,1,1);
--insert into rec Values (3,2005,1,2);
--insert into rec Values (4,2005,1,2);
--insert into rec Values (5,2005,2,1);
--insert into rec Values (6,2005,2,1);
--insert into rec Values (7,2005,2,2);
--insert into rec Values (8,2005,2,2);
--insert into rec Values (9,2005,2,2);
--insert into rec Values (10,2005,2,1);

/*create procedure sp_ord_max_per(year integer)
returns (org_id integer, per_id integer)
as begin for select org_id, max(per_id)
FROM rec WHERE year_num = :year
group by org_id
into :org_id, :per_id
do
suspend;
end*/

--select * from sp_ord_max_per(2005) select max(r.rec_id) rec_id, s.org_id, s.per_id
from sp_ord_max_per(2005) s
inner join rec r on s.org_id = r.org_id and s.per_id = r.per_id
group by s.org_id, s.per_id


результат как раз тот, что был нужен:

REC_ID ORG_ID PER_ID
4 1 2
9 2 2

olegenty
Отправлено: 10.03.2005, 08:47


Ветеран

Группа: Модератор
Сообщений: 2412



грёбаный тег SQL всё испортил, имелось в виду следующее:

CODE

/*create table rec
(rec_id integer
,year_num integer
,org_id integer
,per_id integer
);*/

--delete from rec;
--insert into rec Values (1,2005,1,1);
--insert into rec Values (2,2005,1,1);
--insert into rec Values (3,2005,1,2);
--insert into rec Values (4,2005,1,2);
--insert into rec Values (5,2005,2,1);
--insert into rec Values (6,2005,2,1);
--insert into rec Values (7,2005,2,2);
--insert into rec Values (8,2005,2,2);
--insert into rec Values (9,2005,2,2);
--insert into rec Values (10,2005,2,1);

/*create procedure sp_ord_max_per(year integer)
returns (org_id integer, per_id integer)
as
begin
   for select org_id, max(per_id)
       FROM  rec
       WHERE year_num = :year
       group by org_id
       into :org_id, :per_id
   do
       suspend;
end*/

--select * from sp_ord_max_per(2005)

select max(r.rec_id) rec_id, s.org_id, s.per_id
from sp_ord_max_per(2005) s
inner join rec r on s.org_id = r.org_id
and s.per_id = r.per_id
group by s.org_id, s.per_id

2 2
telepath
Отправлено: 10.03.2005, 11:15


Станционный диспетчер

Группа: Участник
Сообщений: 132



спасибо, учту, сейчас бьюсь за использование ХП smile.gif

Вернуться в Работа с базами данных в C++Builder