Скрипт: Строковые массивы для Лоции на MSSQL (завершение)

Обсуждение технических вопросов работы с системами управления базами данных (СУБД), работе с языком SQL и скриптовыми языками.
Ответить
Аватара пользователя
Александр
Активный участник
Сообщения: 1652
Зарегистрирован: 24 авг 2006, 08:06
Используемое ПО: Lotsia PDM PLUS
Откуда: 55.745578,37.665825

Скрипт: Строковые массивы для Лоции на MSSQL (завершение)

Сообщение Александр »

По мотивам
http://www.lplm.ru/phpBB2/viewtopic.php?t=177
http://www.lplm.ru/phpBB2/viewtopic.php?t=255

Ниже - Последний вариант. В ожидании новой версии Лоции устраивает нас на 90%
Массив(ы) = Строковый Атрибут (не привязанный к объекту)
3 функции
lsdbo.Ric_CreateTableID - Пересоздать таблицу уникальных ID (lsdbo)
lsdbo.Ric_ClearArray - Очистить массив и вернуть ID в таблицу (lsdbo)
lsdbo.Ric_RefreshArray - Заполнить массив используя ID из таблицы (lsdbo,Party)

Как работает:
- Чтобы не нарушать работу с генерацией ID самой Лоции - забираем сколько нужно ID из верхнего адресного пространства и формируем из них таблицу 'служебных' ID. (однократно)
- Выбираем из базы данные
- Через курсоры набираем наш строковый массив, при этом ID заимствуется из созданной таблицы и используется в массиве
- При очистке массива все его используемые ID возвращаются в таблицу обратно
Таким образом используется постоянный изолированный набор ID и конфликтов по уникальности ключей не возникает

Сами функции

Код: Выделить всё

/*------------------------------------------------------
 * Создать таблицу уникальных ID с 'учетом' филиала
 *-----------------------------------------------------*/
ALTER      Procedure lsdbo.Ric_CreateTableID 
          (@Length int=1000,		--длина таблицы
           @Filial int=99999		--номер филиала (5 знаков на филиал)
           )As
 Begin

 Declare @Row numeric(18,0)		--10 знаков на ID
     Set @Row =9999999999		--верхняя граница диапазона

  --удалить таблицу c ID если она есть
  If Exists (Select *
               From dbo.sysobjects
              Where dbo.sysobjects.name='RIC_Tableid')
    Drop Table lsdbo.Ric_TableID

  --создать новую таблицу под ID  
  Create Table lsdbo.Ric_TableID
               (Free_id numeric(18,0),
     Constraint PK_user_myid Primary key (Free_id)
                )
  --заполнить таблицу ID с учетом параметров
  While 
  (Select Count(*) From lsdbo.Ric_TableID)<@Length 
   Begin
     Insert into lsdbo.Ric_TableID(Free_id) Values(@Row*100000+@Filial)
     Set @Row=(@Row-1)
   End

 End

Код: Выделить всё

/*------------------------------------------------------
 * Если массив (атрибут id=@d_atr) не пустой:
 *   -очистить его (удалить все значения атрибута)
 *   -вернуть все используемые id массива в RIC_TableID
 * Иначе
 *   -выйти без изменений
 *-----------------------------------------------------*/
ALTER           Procedure lsdbo.Ric_ClearArray
          (@d_atr numeric(18,0) Output 
           )As
 Begin

 Declare @RestoreID numeric(18,0) 			--возвращаемый ID

 --если массив(атрибут) не пустой - очистить его и вернуть все ID 
  If (Select count(*) From lsdbo.value_string Where attrib_id=@d_atr)<>0

   Begin 
     Declare @CursorVarID CURSOR			--настроить курсор 
     Set @CursorVarID=CURSOR SCROLL DYNAMIC
       For
         Select id					--встать на массив
           From lsdbo.value_string
          Where attrib_id=@d_atr
     For update						--для обновлений

     Open @CursorVarID					--открыть курсор

     Begin Tran						--начать транзакцию
     --цикл по всей таблице курсора
     Fetch Next From @CursorVarID Into @RestoreID;	--прочитать первое значение
     While @@FETCH_STATUS = 0				--пока курсор не 'пустой'
       Begin 
         Delete lsdbo.value_string			--удалить текущую строку массива (атрибута) 
           Where current of @CursorVarID;
         Insert into lsdbo.RIC_TableID (Free_id)	--вернуть ID в таблицу  
           Values(@RestoreID);
         Fetch Next From @CursorVarID Into @RestoreID;	--прочитать следующее значение
         If @@Error<>0					--если ошибка -выйти из цикла	 
           Begin    
             Rollback tran 				--откатить транзакцию
             Set @d_atr=-1				--Ret: Ошибка в время очистки
             GoTo Stop;				
           End
       End

     Commit Tran					--подтвердить транзакцию
     Set @d_atr=1					--Ret: Массив очищен 
 Stop: 
     Close @CursorVarID;				--закрыть курсор 
     Deallocate @CursorVarID;				--и освободить ресурсы 

   End 
  Else
   Set @d_atr=0						--Ret: Массив был пустой   

 End
Последний раз редактировалось Александр 10 июл 2007, 08:02, всего редактировалось 9 раз.

Софт - RicCRM<<LotsiaPDM(4.40)<<MsSQL(5/8)
Уровень администрирования - Альтернативный

Аватара пользователя
Александр
Активный участник
Сообщения: 1652
Зарегистрирован: 24 авг 2006, 08:06
Используемое ПО: Lotsia PDM PLUS
Откуда: 55.745578,37.665825

Сообщение Александр »

... продолжение

Код: Выделить всё

/*------------------------------------------------------
 * предварительно очистить и 
 * добавить строковому массиву (атрибуту) c id=@d_atr 
 * значения отобранные выбранным Select и имеющими значения 
 * ID выбранные из RIC_TableID (таблицы свободных ID) 
 *-----------------------------------------------------*/
ALTER     Procedure lsdbo.Ric_RefreshArray
        (@d_atr numeric(18,0) Output,  		--ID массива (атрибута) для записи значений
         @NSelect integer=0,			--номер Select
         @ObjID numeric(18,0)=0,      		--ID объекта
         @ObjType char(256),       		--Тип объекта
         @ObjAttr1ID numeric(18,0)=0,  		--ID Атрибута1 Объекта
         @ObjAttr1Value sql_variant=0,      	--Значение Атрибута1 Объекта
         @ObjAttr2ID numeric(18,0)=0,  		--ID Атрибута2 Объекта
         @ObjAttr2Value sql_variant=0		--Значение Атрибута2 Объекта
         )As

 Begin

 Declare @ID numeric(18,0),			--переменная для ID	
         @Value varchar(255),                   --переменная для значения массива
         @CountID integer,			--количество свободных ID				
         @CountArray integer			--количество запрашиваемых ID

  --Проверить и очистить массив (атрибут) если нужно
  Set @ID=@d_atr --используем временную переменную т.к. обращение по ссылке                               
  Exec @ID=lsdbo.Ric_ClearArray @ID output
  If @ID<>-1					--если ошибок не возникло то продолжим
   Begin
 
    Declare @CursorVarID CURSOR			--создать курсор для работы с ID
    Set @CursorVarID = CURSOR SCROLL KEYSET For
      Select Free_ID				--сформировать запрос для курсора
      From lsdbo.RIC_TableID
    For update					--тип курсора - для обновления

    Declare @CursorVar CURSOR			--создать курсор для работы с массивом  
    						--сформировать запрос для курсора

Софт - RicCRM<<LotsiaPDM(4.40)<<MsSQL(5/8)
Уровень администрирования - Альтернативный

Аватара пользователя
Александр
Активный участник
Сообщения: 1652
Зарегистрирован: 24 авг 2006, 08:06
Используемое ПО: Lotsia PDM PLUS
Откуда: 55.745578,37.665825

Сообщение Александр »

...продолжение

Код: Выделить всё

    If @NSelect=1
    --1.0 Выбрать все объекты, где: 
    --    = Тип объекта @ObjType
    --    > Значения @ObjAttr1NumValue числового атрибута @ObjAttr1ID
      Begin					
        Set @CursorVar = CURSOR SCROLL KEYSET For
        Select rtrim(rw.description)+space(200-len(rw.description))+str(rw.id,15) as value
          From lsdbo.object_reference_view rw,
               lsdbo.object_type_view tw
         Where (rw.type_id = tw.id) 
                 AND
               ((tw.mnemo = @ObjType 
                 AND rw.id in
                (Select av.object_id
                   From lsdbo.attrib_value_view av,
                        lsdbo.value_numeric_view vv
                  Where av.value_id = vv.id and
                        av.attrib_id = @ObjAttr1ID and
                        vv.attrib_id = @ObjAttr1ID AND
                        vv.Value > CAST(@ObjAttr1Value AS numeric(18,0)))));
      End
...
     If @NSelect=4
    --4.0 Выбрать все дочерние объекты по типу связи Дерево проекта, где: 
    --    = ID родительского объекта @ObjID
      Begin
        Set @CursorVar = CURSOR SCROLL KEYSET For
        Select rtrim(rw.description)+space(200-len(rw.description))+str(rw.id,15) as value
          From lsdbo.object_reference_view rw,
               lsdbo.tree_link_view tl
         Where tl.parent_id =@ObjID 
               AND tl.link_type_id = 1
               and rw.id = tl.link_id
      End


    Open @CursorVarID				--Открыть курсор (выполнить запрос)
    Set  @CountID=@@Cursor_Rows		   	--прочитать количество доступных ID
    Open @CursorVar				--Открыть курсор (выполнить запрос)	
    Set  @CountArray=@@Cursor_Rows		--прочитать количество запрашиваемых ID

    If (@CountID>=@CountArray) and @CountArray>0
     Begin 
      Begin Tran						--начать транзакцию

        --цикл по всей таблице курсора (счетчик по последнему открытому курсору)
        Fetch Next From @CursorVar Into @Value;	--прочитать первое значение
        Fetch Next From @CursorVarID Into @ID;	--прочитать первое значение
        While @@FETCH_STATUS = 0		--пока курсор не 'пустой'	
          Begin
            Delete From lsdbo.RIC_TableID Where current of @CursorVarID
            Insert Into lsdbo.value_string (id, filial_id, value, author_id, attrib_id )
                                     values(@ID,0,@Value,0,@d_atr); 
            Fetch Next From @CursorVarID Into @ID;
            Fetch Next From @CursorVar Into @Value;
            If @@Error<>0			--если ошибка -выйти из цикла	 
              Begin    
                Rollback tran 			--откатить транзакцию
                Set @d_atr=-1			--Ret: Ошибка в время перезаписи
                GoTo Stop;				
              End
          End
        Commit Tran				--подтвердить транзакцию
        Set @d_atr=@CountID-@CountArray     	--Ret: Количество свободных ID   
     End
    Else    
     Set @d_atr=-2				--Ret: Недостаточно свободных ID   

Stop:   
    Close @CursorVarID;				--закрыть курсор ID
    Deallocate @CursorVarID;			--и освободить ресурсы
    Close @CursorVar;				--закрыть курсор значений
    Deallocate @CursorVar			--и освободить ресурсы	

   End						
  Else
   Set @d_atr=-3				--Ret: Ошибка очистки массива   

 --!!! Для корректного выхода из f_ExecSQLSelect_2 ('exec... нужно использовать
 --    Select @d_atr перед последним End					
 --    НО это в свою очередь вызывает двойной запуск процедуры из действия Лоции???
 --    Таким образом для эмитации нормального завершения функции - необходим следующий
 --    шаг с формой (можно с автоматическим завершением)-тогда все Ок (вызов один)
 End
Пара вызовов

Код: Выделить всё

tmp = Set ( f_ExecSQLSelect_2 ('exec lsdbo.RIC_RefreshArray 100028524100000,3,0,~'Подч~',100000019000005,-1,3000000000122,~'Менеджер~'','','') )
tmp = Set ( f_ExecSQLSelect_2 ('exec lsdbo.RIC_RefreshArray 100028524100000,1,0,~'Подч~',100000019000005,-1,0,0','','') )
tmp = Set ( f_ExecSQLSelect_2 ('exec lsdbo.RIC_RefreshArray 100028524100000,4,100000234560005,0,0,0,0,0','','') )
 
Если не все влезло - извините (форум как то по своему режет текст - поэтому и распихал в 3 топика)

Софт - RicCRM<<LotsiaPDM(4.40)<<MsSQL(5/8)
Уровень администрирования - Альтернативный

Аватара пользователя
Александр
Активный участник
Сообщения: 1652
Зарегистрирован: 24 авг 2006, 08:06
Используемое ПО: Lotsia PDM PLUS
Откуда: 55.745578,37.665825

Сообщение Александр »

Прошло 1.5 месяца...
Вчера замечен интересный эффект, не знаю насколько тесно он связан с моими процедурами?.

Сейча я держу 10 строковых атрибутов хранящих в своих значениях мои массивы данных.
Так вот при процедуре расширенного импорта некоторые из данных атрибутов обнулялись, причем ни конфликтов по ID, ничего другого, просто если в момент импорта запускалось действие по обновлению того или иного массива - то оно совершалось не до конца.
Т.е. происходила очистка массива (защищенная транзакция), а наполнение не успевало происходить или на что-то натыкалось и откатывалось (также защищенная транзакция)

Вполне возможно это обстоятельство связано с моментом автоматической генерации ID в процедурах импорта, и хотя мои 1000 ID все время заняты и не конфликтуют с системой - тем не менее они не отмечены в служебной таблице Лоции которая хранит максимальные текущие значения ID тех или иных атрибутов. Но с другой стороны MS SQL следит за уникальностью ключей да и Лоция (я думаю) если натыкается на неучтенный занятый ключ - может это дело обойти.

К счастью после импорта (и даже в процессе импорта) неоднократный вызов моих процедур по обновлению данных проходил на 85% успешно, и по завершению все встало на свои места. :wink:

Поскольку в ближайший год Лоция не сможет предоставить нам свои массивы для Party, мы намерены использовать свои разработки и далее.


PS Никто не пробовал применить это дело у себя??? :?

Софт - RicCRM<<LotsiaPDM(4.40)<<MsSQL(5/8)
Уровень администрирования - Альтернативный

Аватара пользователя
Александр
Активный участник
Сообщения: 1652
Зарегистрирован: 24 авг 2006, 08:06
Используемое ПО: Lotsia PDM PLUS
Откуда: 55.745578,37.665825

Сообщение Александр »

прошло пол-года - полет нормальный, глюков нет, используется в MSSQL2000-2005 :wink: :wink: :wink:
мы намерены расширить количество массивов и полностью отказаться от сервиса лоции по выбору объектов стандартными (неудобными) средствами :wink: :wink: :wink:

Софт - RicCRM<<LotsiaPDM(4.40)<<MsSQL(5/8)
Уровень администрирования - Альтернативный

Аватара пользователя
Александр
Активный участник
Сообщения: 1652
Зарегистрирован: 24 авг 2006, 08:06
Используемое ПО: Lotsia PDM PLUS
Откуда: 55.745578,37.665825

Сообщение Александр »

реализовали
http://www.lplm.ru/phpBB2/viewtopic.php?p=1402#1402
кстати расширенный импорт-опять запорол половину массивов-ну не нравятся ему атрибуты не привязанные к объектам - и он их пытается уничтожить - но не на тех напали - просто не будем делать расширенный импорт - по живому (когда все работают) и после - будем обновлять массивы

Софт - RicCRM<<LotsiaPDM(4.40)<<MsSQL(5/8)
Уровень администрирования - Альтернативный

Ответить