| 
| 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
 
 
 
  
 | понятно, жаль... Спасибо
   |  
|  |  
| olegenty | 
| Отправлено: 09.03.2005, 16:10 |  |  
| 
 Ветеран
 
 Группа: Модератор
 Сообщений: 2412
 
 
 
  
 | я припозднился с ответом, но, всё же, прочти сообщение, что до AVC, предлагаемое там решение — рабочее. |  
|  |  
| telepath | 
| Отправлено: 09.03.2005, 16:55 |  |  
| 
 Станционный диспетчер
 
 Группа: Участник
 Сообщений: 132
 
 
 
  
 | про ХП я писал, у нас админы дурные  если только представление сделать.
 Попробую что быстрее получится, хотя этот запрос достаточно редко будет использоваться
 |  
|  |  
| 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
 
 
 
  
 | ух!  Спасибо
   |  
|  |  
| 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
 
 
 
  
 | да, правильно, я такое повидение и имел в виду для простейшего правила (оно же вырожденное). а общий случай — как раньше сказал...  
 идеально решается как 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
 
 
 
  
 | спасибо, учту, сейчас бьюсь за использование ХП   |  
|  |  |