Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Web программирование > SQL, базы данных
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 10.01.2010, 14:34   #1
vario_rus
Пользователь
 
Регистрация: 05.05.2009
Сообщений: 10
Вопрос Реализация запроса:

Уважаемые знатоки, подскажите, как красивее решить следующую задачу:

Запрос возвращает следующее:
имя, номер
XXX 3
XXX 4
XXX 5
XXX 6
YYY 1
YYY 5
YYY 7

задача - вернуть недостающие цифры в порядковой нумерации, т.е. результат должен быть следующим:

XXX 1
XXX 2
YYY 2
YYY 3
YYY 4
YYY 6

Пока реализовал через курсор, но получилось довольно громоздко. Вероятно есть и другие решения.
vario_rus вне форума Ответить с цитированием
Старый 10.01.2010, 19:31   #2
motorway
Участник клуба
 
Регистрация: 28.06.2009
Сообщений: 1,950
По умолчанию

Ну в PHP, например, есть функции для работы с массивами. Можно вычесть из массива эти элементы, что останется - то выводить. Или в цикле проверять на совпадение...
motorway вне форума Ответить с цитированием
Старый 11.01.2010, 12:40   #3
soleil@mmc
SQL-коддинг
Участник клуба
 
Регистрация: 16.01.2009
Сообщений: 1,192
По умолчанию

может еще озвучишь СУБД? тогда решение будет самым красивым
soleil@mmc вне форума Ответить с цитированием
Старый 11.01.2010, 15:27   #4
vario_rus
Пользователь
 
Регистрация: 05.05.2009
Сообщений: 10
Восклицание

Цитата:
Сообщение от soleil@mmc Посмотреть сообщение
может еще озвучишь СУБД? тогда решение будет самым красивым
Извините, MS SQL 2008
vario_rus вне форума Ответить с цитированием
Старый 11.01.2010, 16:36   #5
soleil@mmc
SQL-коддинг
Участник клуба
 
Регистрация: 16.01.2009
Сообщений: 1,192
По умолчанию

может и дождемся варианта от МССКЛ-ьщиков
и ваш вариант тоже хотелось бы посмотреть
а "курсор" - это же запрос или так ХП обзывают в МССКЛ?

вот вариант для Оракла
Код:
with 
  t as (
  select 'XXX' i_name, 3 i_number from dual union all
  select 'XXX', 4 from dual union all
  select 'XXX', 5 from dual union all
  select 'XXX', 6 from dual union all
  select 'YYY', 1 from dual union all
  select 'YYY', 5 from dual union all
  select 'YYY', 7 from dual
  ),
  t2 as (
  select 
    case when min(i_number) > 1 then 1 else min(i_number) end num_min, 
    max(i_number) num_max, 
    i_name
  from t
  group by i_name)

select   
  i_name,
  num_min + level - 1 i_number
from t2
connect by 
  connect_by_root i_name = i_name
  and level <= num_max
minus
select   
  i_name,
  i_number
from t
order by 1, 2
с "коннект бай" до 1 млн. строк вполне себе шустро летает
soleil@mmc вне форума Ответить с цитированием
Старый 11.01.2010, 19:17   #6
soleil@mmc
SQL-коддинг
Участник клуба
 
Регистрация: 16.01.2009
Сообщений: 1,192
По умолчанию

а если отображать интервалами, то будет проще и красивее таким запросом
Код:
with 
  t as (
  select 'XXX' i_name, 3 i_number from dual union all
  select 'XXX', 4 from dual union all
  select 'XXX', 5 from dual union all
  select 'XXX', 6 from dual union all
  select 'YYY', 1 from dual union all
  select 'YYY', 5 from dual union all
  select 'YYY', 7 from dual
  )

select 
  i_name, 
  i_number_from, 
  i_number_to 
from
  ( select 
      i_name,
      i_number,
      lag(i_number, 1, 0) over (partition by i_name order by i_number) + 1 as i_number_from,
      i_number - 1 as i_number_to
    from t
  )
where i_number_from <= i_number_to
soleil@mmc вне форума Ответить с цитированием
Старый 12.01.2010, 10:14   #7
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

ну, если TC устроит вариант с указанием пропущенных диапазонов, то аналог (чуть расширенный - дополнительно указывается количество пропущенных) запроса из пост #6 в MS SQL будет выглядеть примерно так:
Код:
-- drop table #xxx
create table #xxx([i_name] [varchar](20) NOT NULL, [id] [numeric](3, 0) NOT NULL)

insert into #xxx([i_name], [id]) values ('xxx', 3)
insert into #xxx([i_name], [id]) values ('xxx', 4)
insert into #xxx([i_name], [id]) values ('xxx', 5)
insert into #xxx([i_name], [id]) values ('xxx', 6)
insert into #xxx([i_name], [id]) values ('yyy', 1)
insert into #xxx([i_name], [id]) values ('yyy', 5)
insert into #xxx([i_name], [id]) values ('yyy', 7)


select t1.i_name, t1.id+1 NumBeg, min(t2.id)-1 NumEnd, min(t2.id)-t1.id-1 Cnt
from 
  (select i_name, 0 as id from #xxx
       group by i_name
   union all 
   select i_name, id from #xxx) t1, #xxx t2
where t1.id<t2.id
  and t1.i_name = t2.i_name
group by t1.i_name, t1.id
having min(t2.id)-t1.id>1
p.s. создание и заполнение временной таблицы можно, разумеется, выкинуть, это для отладки/проверки вставлено...

p.p.s. автор оригинального запроса не я, копирайт некоего автора с sql.ru
Serge_Bliznykov вне форума Ответить с цитированием
Старый 12.01.2010, 12:39   #8
vario_rus
Пользователь
 
Регистрация: 05.05.2009
Сообщений: 10
Радость

Цитата:
Сообщение от soleil@mmc Посмотреть сообщение
может и дождемся варианта от МССКЛ-ьщиков
и ваш вариант тоже хотелось бы посмотреть
а "курсор" - это же запрос или так ХП обзывают в МССКЛ?
Приведу свой вариант c курсором. Так как строк обрабатывается от силы 100-150, такой вариант приемлем, с большим количеством строк, конечно, будут тормоза.

Код:
insert into @Table ([name], [num]) values ('xxx', 3)
insert into @Table ([name], [num]) values ('xxx', 4)
insert into @Table ([name], [num]) values ('xxx', 5)
insert into @Table ([name], [num]) values ('xxx', 6)
insert into @Table ([name], [num]) values ('yyy', 1)
insert into @Table ([name], [num]) values ('yyy', 5)
insert into @Table ([name], [num]) values ('yyy', 7)

Declare @name as VarChar(50),
@MaxNum as int,
@I as int

DECLARE names_cursor CURSOR FOR 
{
Здесь SELECT возвращает таблицу имен с максимальным значением NUM:
В данном случае будет 
 xxx 6
 yyy 7
}
OPEN names_cursor

FETCH NEXT FROM names_cursor INTO @name, @MaxNum
WHILE @@FETCH_STATUS = 0
BEGIN
SET @I=1

WHILE @i<=@MaxNum BEGIN
// циклом бежим по таблице и вставляем недостающие строки
update @Table 
set name=name 
where name=@name
AND num=@I
if @@ROWCOUNT=0
   BEGIN
insert into @Table ([name], [num]) values (@Name, @I)
   END

SET @i=@i+1
END

FETCH NEXT FROM names_cursor INTO @name, @MaxNum
END
CLOSE names_cursor  
DEALLOCATE names_cursor
Громоздко, но результат выдает нужный.
vario_rus вне форума Ответить с цитированием
Старый 12.01.2010, 14:09   #9
soleil@mmc
SQL-коддинг
Участник клуба
 
Регистрация: 16.01.2009
Сообщений: 1,192
По умолчанию

имхо запросом с найденными интервалами "дырок" будет шустрее
стоит только сравнить лист из 1 млн. записей, в котором есть 100-150 дырок (пусть "дырки" будут распределены равномерно по всему диапазону записей) - ваш "курсор" будет молотить все эти записи и при этом "потрогает" каждую (может там еще и триггеры будут задействованы), а через запрос получите лист из тех же 100-150 дырок
soleil@mmc вне форума Ответить с цитированием
Старый 12.01.2010, 14:45   #10
vario_rus
Пользователь
 
Регистрация: 05.05.2009
Сообщений: 10
По умолчанию

Цитата:
Сообщение от soleil@mmc Посмотреть сообщение
имхо запросом с найденными интервалами "дырок" будет шустрее
стоит только сравнить лист из 1 млн. записей, в котором есть 100-150 дырок (пусть "дырки" будут распределены равномерно по всему диапазону записей) - ваш "курсор" будет молотить все эти записи и при этом "потрогает" каждую (может там еще и триггеры будут задействованы), а через запрос получите лист из тех же 100-150 дырок
Оно и понятно, но элегантного варианта для MS SQL пока никто не предложил.
vario_rus вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Реализация страниц spein PHP 1 14.12.2009 23:54
[Delphi] TQuery и реализация запроса. MaGWaY_minsk Помощь студентам 2 12.05.2009 00:31
Реализация программы K123 Общие вопросы C/C++ 2 07.05.2009 20:30
Реализация очереди! Lazio Помощь студентам 2 08.04.2009 17:41
Реализация конфигуратора BlackOmen Общие вопросы Delphi 3 30.05.2008 17:12