Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Помогите составить запрос, пожалуйста!  (Прочитано 14591 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Demidova Aigul
Гость
« : 27-04-2006 10:31 » 

Помогите, пожалуйста, решить следующую задачу.  Здесь была моя ладья...
У меня в таблице Rubriki_new есть 3 поля: id_rub, InventoryID, name_rubriki.
В поле name_rubriki через запятую занесены несколько слов, а мне их нужно разделить.
Для примера, в таблице Rubriki_new есть такая строка:

1         046144         Техника, технология и методика  геологоразведочных работ

(где 1 - это id_rub, 046144 - это InventoryID, а "Техника, технология и методика геологоразведочных работ" - это name_rubriki).

А мне нужно, чтобы из этой одной строки получилось две:

1         046144         Техника
1         046144         технология и методика геологоразведочных работ

Пожалуйста, подскажите, как это можно сделать, с помощью какой функции.  Не понял
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 27-04-2006 10:40 » 

Это не делается с помощью функции. Хранение информации "через запятую" для данной задачи - свидетельство отсутствия всякой нормализации. (Условно говоря, 0-я нормальная форма).

В SQL нет средств, позволяющих единым запросом обработать "несколько" слов. Только, если их количество фиксировано, либо ограничено сверху.

В любом случае БД будет очень плохо работать с такой таблицей.

Предлагаю создать новую нормализованную таблицу, куда перегнать данные из исходной. В случае необходимости построить запрос, формирующий из нескольких строчек одну "через запятую".

Преобразование в новую таблицу в случае неопределённого "нескольких" можно сделать только в цикле разбора строчек - реализовать можно отдельным sql-скриптом, хранимой процедурой, либо написать программу не на SQL, выполняющую преобразование. В MS SQL Server можно создать DTS-пакет.

Так как все эти возможности зависимы от особенностей реализации, то о какой СУБД идёт речь?
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Demidova Aigul
Гость
« Ответ #2 : 27-04-2006 10:51 » 

Цитата
Так как все эти возможности зависимы от особенностей реализации, то о какой СУБД идёт речь?

Ой, совсем забыла сказать, что мне запрос нужно сделать на MS SQL Server (е).  Улыбаюсь

Цитата
Предлагаю создать новую нормализованную таблицу, куда перегнать данные из исходной. В случае необходимости построить запрос, формирующий из нескольких строчек одну "через запятую".

А это у меня уже и есть новая таблица, построенная на основе другой таблицы (т.е. из другой таблицы в новую я взяла только несколько полей, одно из них - где как раз через запятую данные внесены). Вот мне и нужно в этой новой таблице чтобы из одной записи получилось две.

1         046144         Техника
1         046144         технология и методика геологоразведочных работ


Записан
Sla
Команда клуба

ua
Offline Offline
Пол: Мужской

WWW
« Ответ #3 : 27-04-2006 11:01 » 

Это можно сделать через union
select id_rub, InventoryID, func(name_rubriki) from Rubriki_new
union
select id_rub, InventoryID, func(name_rubriki) from Rubriki_new
и т.д.
где func функции работы со строкой - поиск запятой, выделение подстроки

Записан

Мы все учились понемногу... Чему-нибудь и как-нибудь.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 27-04-2006 12:24 » 

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

Belka*, Во-первых, перелопачивание одной таблицы можно сделать по такому алгоритму:
0) перейти к началу таблицы
1) пока есть записи в таблице, выполнять в цикле
1.1) взять запись
1.2) пока в записи есть строка, содержащая запятые выполнять в цикле
1.2.1) отделить часть строки до первой запятой
1.2.2) выполнить insert в эту же таблицу с тем же inventoryID и id_rub и выделенной строкой
1.2.3) выполнить update для текущей записи, удалив выделенную часть строки
1.2.4) повторять 2.
1.3) повторять 1.

Во-вторых, перебор записей можно сделать в скрипте при помощи курсора.

В-третьих, id_rub, надо полагать, не является первичным ключом таблицы. Если является, тогда алгоритм работать не будет.
« Последнее редактирование: 27-04-2006 12:28 от dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Sla
Команда клуба

ua
Offline Offline
Пол: Мужской

WWW
« Ответ #5 : 27-04-2006 13:08 » 

я специально написал func, (не знаю синтаксиса mssql)
(поиск первой запятой, подстрока от первой до второй) ну что-то типа этого
количество union - ограничено мыслимыми пределами, допустим до пяти (больше в данном случае не будет)

Конечно возможен вариант через промежуточную таблицу, с курсором с разбром name_rubriki

Вот только не понятно
Цитата
А это у меня уже и есть новая таблица, построенная на основе другой таблицы
тогда уж лучше не таблица, а вьюшка
И зачем, вообще, огород городить?
Записан

Мы все учились понемногу... Чему-нибудь и как-нибудь.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 27-04-2006 14:18 » 

Цитата: Sla
я специально написал func, (не знаю синтаксиса mssql)
(поиск первой запятой, подстрока от первой до второй) ну что-то типа этого
количество union - ограничено мыслимыми пределами, допустим до пяти (больше в данном случае не будет)
Так не пойдёт.
а) решение не универсально, а мыслимые пределы со временем имеют тенденцию изменяться;
б) такой функции нет, но если её писать, одним аргументом не отделаешься, как минимум ещё нужно передать порядковый номер запроса;
в) в твоём запросе все select, соединённые union, должны относиться к одной записи исходной таблицы (если нужен выбор одной записи), поэтому без секциии where никак не обойтись; ко всему прочему, если количество элементов в строке меньше количества запросов, появятся пустые строки, которые тоже нужно отсекать в where.
Цитата: Sla
тогда уж лучше не таблица, а вьюшка
И зачем, вообще, огород городить?
г) предложенное решение в качестве view - это неимоверные тормоза. Не должно быть такой ситуации, когда семантически важные с точки зрения предметной области данные хранятся в ненормализованном состоянии. Это закладывание больших трудозатрат на сопровождение и развитиие использующих БД приложений, высокий риск неприемлимо низкой производительности БД и неустойчивости работы приложений.
« Последнее редактирование: 27-04-2006 14:19 от dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
kisilevski
Постоялец

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #7 : 28-04-2006 06:55 » 

А если так?
1) Создать курсор на основе слекта из таблицы, где строка LIKE '%,%'
2) Курсор должен брать в переменные все поля таблицы
3) Внутри курсора сделать цикл while (пока переменая - строка не пустая) BEGIN
 отрезАть в другую переменную левую часть строки (до запятой), либо до конца, убирая эту левую часть из исходной строки;
 Insert в таблицу новую запись из левой подстроки и  набора переменных - прочих полей таблицы
END
4) DELETE FROM табленаме WHERE строка LIKE '%,%'

5) Подстрока отрезается примерно так: SET @sVer1=LEFT(@sVer, CHARINDEX(',',@sVer))
« Последнее редактирование: 17-12-2007 17:35 от Алексей1153++ » Записан

Ложки нет. See MSDN for details.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #8 : 28-04-2006 07:16 » 

kisilevski, а это и есть реализация алгоритма
Цитата: dimka
0) перейти к началу таблицы
1) пока есть записи в таблице, выполнять в цикле
1.1) взять запись
1.2) пока в записи есть строка, содержащая запятые выполнять в цикле
1.2.1) отделить часть строки до первой запятой
1.2.2) выполнить insert в эту же таблицу с тем же inventoryID и id_rub и выделенной строкой
1.2.3) выполнить update для текущей записи, удалив выделенную часть строки
1.2.4) повторять 2.
1.3) повторять 1.
SQL скриптом
Только много раз update заменён на 1 финальный delete исходной записи.

P.S. Вопрос ещё в том, позволяет ли курсор манипуляции с записями во время своего прохождения по ним... Этим вопросом я ещё не задавался.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
kisilevski
Постоялец

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #9 : 28-04-2006 08:15 » 

1) Сорри, не вчитался в ответы предыдущих товарищей..
2) Позволяет, даже удаление можно делать.
Записан

Ложки нет. See MSDN for details.
Demidova Aigul
Гость
« Ответ #10 : 28-04-2006 08:22 » 

Цитата
В-третьих, id_rub, надо полагать, не является первичным ключом таблицы. Если является, тогда алгоритм работать не будет.


А у меня как раз id_rub является первичным ключом.  Жаль
Тогда что делать? С курсором будет работать?  А черт его знает...
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #11 : 28-04-2006 09:10 » 

Цитата: Belka*
А у меня как раз id_rub является первичным ключом.
Первичный ключ не может повторяться. В таком случае необходимо создать двухуровневый справочник.

Одна таблица - справочник рубрик (rub_id, InventoryID), вторая таблица - справочник названий (name_id, name, rub_id), в котором rub_id будет внешним ключом и может много раз повторяться. При такой декомпозиции целостность остальных частей базы не нарушится.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Igore
Гость
« Ответ #12 : 17-08-2006 22:02 » 

Знаю, что старая тема, но что-то прикололо... Тем более, что с немного похожими проблемами сейчас возюкаюсь... Вот накидал... Вроде работает... Улыбаюсь

-- имитация таблицы исходных данных
declare @tab table (id_rub int, InventoryID varchar(16), name_rubriki nvarchar (256))
insert @tab select 1, '046144', N'Техника, технология, методика  геологоразведочных работ'
insert @tab select 2, '056155', N'Тактика, стратегия разведения кроликов'
-- конец иммитации

declare @outtab table (id_rub int, InventoryID varchar(16), name_rubriki nvarchar (64))

declare @id_rub int, @InventoryID varchar(16), @name_rubriki nvarchar (64),
@i int, @j int, @len int

declare rub_cursor cursor
for select id_rub, InventoryID, name_rubriki from @tab
open rub_cursor
FETCH NEXT FROM rub_cursor
INTO @id_rub, @InventoryID, @name_rubriki

WHILE @@FETCH_STATUS = 0
BEGIN
   set @len = (select len(@name_rubriki) from @tab where id_rub = @id_rub)
   set @i = 1
   set @j = 1
   while (@j < @len)
   begin
      set @j = (select CHARINDEX( ',', @name_rubriki, @i))
      if @j = 0 set @j = @len else set @j = @j
      insert @outtab (id_rub, InventoryID, name_rubriki)
      select @id_rub, @InventoryID,
      substring(@name_rubriki, @i, @j-@i+1)
      print cast(@i as varchar(16))+'/'+cast (@j-@i as varchar(16))+'/'+cast(@len as varchar(16))
      set @i =  @j+1
   end

   FETCH NEXT FROM rub_cursor
   INTO @id_rub, @InventoryID, @name_rubriki
END
CLOSE rub_cursor
DEALLOCATE rub_cursor
   
select * from @outtab
go
« Последнее редактирование: 17-12-2007 17:36 от Алексей1153++ » Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines