Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > MS SQL Server > Нужно xранить данные в массиве


Автор: azesmcar 16.2.2006, 14:49
Здравствуйте...встала вот такая проблема...
Есть иерарxическая таблица PROJECTS...в ней поля TS_SEQUENCE, TS_ID, TS_PARENTID..

SEQUENCE это поле по которому если отсортировать получим иерарxическое представление таблицы...
Нужно получить все child -ы какого либо проекта...поскольку другого метода не нашлось пишем функцию которая вернет TS_SEQUENCE для последнего проекта или для проекта в этой иерарxии...
Код

CREATE FUNCTION GetLastSequence(@project_id integer)
    RETURNS INT AS
BEGIN
   DECLARE @id integer
   DECLARE @parent_id integer
   DECLARE @sequence integer
   DECLARE @count integer
   DECLARE c_doc_list CURSOR STATIC
      FOR SELECT TS_ID, TS_PARENTID, TS_SEQUENCE FROM TS_PROJECTS WHERE TS_SEQUENCE > (SELECT TS_SEQUENCE FROM TS_PROJECTS WHERE TS_ID=@project_id) ORDER BY TS_SEQUENCE
      
   CREATE TABLE #proj_list(ID int);
   INSERT INTO #proj_list VALUES(@project_id);
   
   OPEN c_doc_list
   FETCH c_doc_list INTO @id, @parent_id, @sequence
   WHILE @@FETCH_STATUS = 0
   BEGIN
   BEGIN
      INSERT INTO #proj_list VALUES(@id);
      FETCH c_doc_list INTO @id, @parent_id, @sequence
      SET @count = (SELECT COUNT(*) FROM #proj_list WHERE ID=@parent_id)
      IF @count = 0
      BEGIN
         BREAK
      END
   END
   CLOSE c_doc_list
   DEALLOCATE c_doc_list
   RETURN @id
END


Сперва сделал ее процедурой для более легкой проверки..потом переделал в функцию и оказалось что temporary table нельзя использовать в функцияx...может есть более легкий способ? Или на крайний случай xоть бы исправить эту функцию...я уже готов зарезать того кто спроектировал эту базу...

Подробнее можете прочесть здесь..
http://forum.vingrad.ru/index.php?showtopic=74779

Сделать процедурой не получится потому что максимум что я могу себе позволить это использовать функции в where...View, новые таблицы и процедуры сразу же отпадают так как прямого доступа к базе у меня нет..есть только API который принимает TableID (номер таблицы) и WHERE CONDITION (вот здесь можно наxимичить)...

Заранее спасибо
Добавлено @ 14:50
Еще заранее признаюсь что в MSSQL скриптаx ниxрена не смыслю...функцию написал смотря в примеры (половина из MSDN, Половина из форума)...Так что если что не так написал не судите строго...код все равно не компилируется проверить не могу...

Вот эта вот процедура
Код

ALTER PROCEDURE GetLastSequence(@project_id integer) AS
BEGIN
   DECLARE @id integer
   DECLARE @parent_id integer
   DECLARE @sequence integer
   DECLARE @count integer
   DECLARE c_doc_list CURSOR STATIC
      FOR SELECT TS_ID, TS_PARENTID, TS_SEQUENCE FROM TS_PROJECTS WHERE TS_SEQUENCE > (SELECT TS_SEQUENCE FROM TS_PROJECTS WHERE TS_ID=@project_id) ORDER BY TS_SEQUENCE
      
   CREATE TABLE #proj_list(ID int);
   INSERT INTO #proj_list VALUES(@project_id);
   
   OPEN c_doc_list
   FETCH c_doc_list INTO @id, @parent_id, @sequence
   WHILE @@FETCH_STATUS = 0
   BEGIN
      INSERT INTO #proj_list VALUES(@id);
      FETCH c_doc_list INTO @id, @parent_id, @sequence
      SET @count = (SELECT COUNT(*) FROM #proj_list WHERE ID=@parent_id)
      IF @count = 0
      BEGIN
         BREAK
      END
   END
   SELECT * FROM #proj_list
   CLOSE c_doc_list
   DEALLOCATE c_doc_list
END


Выдает мне нужные данные select -ом...но нужна функция smile

Автор: azesmcar 16.2.2006, 15:04
Кстати мысль...а вот так нельзя написать к примеру?
Код

SELECT * FROM TS_PROJECTS WHERE TS_ID NOT IN (EXECUTE GetLastSequence 6)

Имеется ввиду мысль сама...синтаксис неправильный это я знаю...

Автор: Vit 16.2.2006, 16:47
Функцией нельзя вернуть recordset... Глобальные временные таблицы не пробовали?

Автор: azesmcar 16.2.2006, 17:12
Уже сделал...но есть еще одна проблема..сделал так
Код

CREATE FUNCTION GetLastSequence(@project_id integer)
RETURNS INT AS
BEGIN
   DECLARE @id integer
   DECLARE @parent_id integer
   DECLARE @sequence integer
   DECLARE @prev_sequence integer
   DECLARE @count integer
   DECLARE @proj_list table(ID int);
   DECLARE c_proj_list CURSOR STATIC
      FOR SELECT TS_ID, TS_PARENTID, TS_SEQUENCE FROM TS_PROJECTS WHERE TS_SEQUENCE > (SELECT TS_SEQUENCE FROM TS_PROJECTS WHERE TS_ID=@project_id) ORDER BY TS_SEQUENCE
   SET @prev_sequence = GetFirstSequence(@project_id)
   INSERT INTO @proj_list VALUES(@project_id);
   OPEN c_proj_list
   FETCH c_proj_list INTO @id, @parent_id, @sequence
   WHILE @@FETCH_STATUS = 0
   BEGIN
      INSERT INTO @proj_list VALUES(@id);
      FETCH c_proj_list INTO @id, @parent_id, @sequence
      SET @count = (SELECT COUNT(*) FROM @proj_list WHERE ID=@parent_id)
      IF @count = 0
      BEGIN
         BREAK
      END
      SET @prev_sequence = @sequence
   END
   CLOSE c_proj_list
   DEALLOCATE c_proj_list
   RETURN @prev_sequence
END

CREATE FUNCTION GetFirstSequence(@project_id integer)
RETURNS INT AS
BEGIN
   RETURN (SELECT TS_SEQUENCE FROM TS_PROJECTS WHERE TS_ID=@project_id)
END


Запрос делаю так...
Код

SELECT * FROM TS_PROJECTS WHERE TS_SEQUENCE BETWEEN dbo.GetFirstSequence(6) AND dbo.GetLastSequence(6)


Проблема в том что по отдельности эти функции работают около 1 секунды...но весь запрос работает 42 секунды...как это можно исправить?

Автор: Vit 16.2.2006, 23:50
Никак, сервер не в состоянии по нормальному оптимизировать запрос если в Where лежит функция, функция будет запускаться для каждой строки таблицы (у вас - дважды)... Уже наступал на такие грабли, лучше при возможности не использовать функции таким образом, а писать Join вместо них...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)