powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Sybase ASA, ASE, IQ [игнор отключен] [закрыт для гостей] / Добавление записей
5 сообщений из 5, страница 1 из 1
Добавление записей
    #32513856
ASA8
Существует таблица вида:
MyTable(nPrimaryID integer, strString varchar(20), nAnotherID integer).

В хранимую процедуру Proc(in _nAnotherID integer, in _strString long varchar)
передается идентификатор _nAnotherID и строка вида "'str1', 'str2', 'str3', 'str4'".

Задача: привести содержимое MyTable по идентификатору nAnotherID в соответствие с этой строкой.

Поясню: в MyTable есть записи:

nPrimaryID strString nAnotherID
1 aaa 2
2 bbb 2
3 ccc 2
4 ddd 2
5 zzz 3

При выполнении в Proc с аргументами: Proc(2, str), где str = "'bbb', 'ddd', 'eee', 'fff'" должно получиться следущее:

nPrimaryID strString nAnotherID
2 bbb 2
4 ddd 2
5 zzz 3
6 eee 2
7 fff 2

т.е. удалиться записи со strString, не содержащимися в переданном аргументе и добавиться новые, ранее не содержащиеся в Table для данного nAnotherID.

Удаление производиться довольно просто:
delete from table MyTable where nAnotherID = _nAnotherID and strString not in (_strString);

Как можно произвести добавление записей с новыми strString (в приведенном выше примере 'eee' и 'fff')? Желательно без создания временных таблиц?
Заранее благодарю.
...
Рейтинг: 0 / 0
Добавление записей
    #32514069
Фотография ASCRUS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторУдаление производиться довольно просто:
delete from table MyTable where nAnotherID = _nAnotherID and strString not in (_strString);
Гм, ну во первых так вообще то ничего не удалится, похорошему уж надо писать:
Код: plaintext
1.
2.
3.
EXECUTE IMMDEDIATE('
  delete from MyTable 
  where nAnotherID = ' || _nAnotherID || ' and 
      strString not in (' || _strString || ')';
Только в этом случае будет работать, так как мы собираем полноценный правильный скрипт, где IN это не один стринговый параметр, а переданный список и выполняем этот скрипт через динамический SQL. Кстати не понятно, почему у Вас выжило "zzz" в последнем примере.

Добавление можно и без временной таблицы, если очень хочется - делаете цикл WHILE LOOP ... END LOOP , внутри через функцию CharIndex последовательно выщемляете по разделителю все значения из параметра _strString, и если их нет, то добавляете в таблицу посредством
Код: plaintext
1.
2.
INSERT INTO MyTable (...) 
  SELECT @Param 
  WHERE @Param NOT IN (SELECT strString FROM MyTable);
Выглядит это решение честно говоря кошмарно, про оптимизацию я вообще молчу, но работать конечно же будет :) Хотя я бы порекомендовал перед тем как его писать задасться одним маленьким вопросом - а на кой параметры в ХП передавать в виде стринговой строки с разделителем ? Может их легче на клиенте подготавливать до удобочитаемого вида, чем заниматься такими извратами с точки зрения СУБД ?

Ну и вообще хотелось бы узнать, с чего навеяна такая странная форма передачи параметров - действительно обоснованной необходимостью или же просто неопытностью или не знанием правил проектировки в ASA ?
...
Рейтинг: 0 / 0
Добавление записей
    #32514606
ASCRUS
Гм, ну во первых так вообще то ничего не удалится, похорошему уж надо писать:

Код: plaintext
1.
2.
3.
4.
EXECUTE IMMDEDIATE('
  delete from MyTable 
  where nAnotherID = ' || _nAnotherID || ' and 
      strString not in (' || _strString || ')';

Вы абсолютно правы. Я скопировал пример не оттуда =)

ASCRUS
Кстати не понятно, почему у Вас выжило "zzz" в последнем примере.

nAnotherID у записи "zzz" равняется 3, тогда как переданный параметр _nAnotherID равен 2. Запись с "zzz" и не должна была трогаться.

ASCRUS
Добавление можно и без временной таблицы, если очень хочется - делаете цикл WHILE LOOP ... END LOOP, внутри через функцию CharIndex последовательно выщемляете по разделителю все значения из параметра _strString, и если их нет, то добавляете в таблицу посредством
Код: plaintext
1.
2.
3.
INSERT INTO MyTable (...) 
  SELECT @Param 
  WHERE @Param NOT IN (SELECT strString FROM MyTable);

Т.е., насколько я понял, крутясь в цикле, я нахожу индекс первого вхождения запятой (в данном случае она является разделителем) с помощью CHARINDEX, формирую параметр от 1 до значения, выданного функцией, используя SUBSTRING и произвожу вставку приведенным вами INSERT? Затем формирую остаток строки SUBSTRINGом и повторяю действия снова до тех пор, пока не кончатся разделители?
Если я все правильно понял, то это именно то, что мне надо было =). Правда вставку, как мне кажется, лучше производить следующим выражением, оно быстрее:
Код: plaintext
1.
2.
3.
4.
5.
IF EXISTS(select strString FROM MyTable WHERE strString = @Param )
THEN
INSERT INTO MyTable (...) 
  VALUES (@Param ...)
END IF

ASCRUS
Выглядит это решение честно говоря кошмарно, про оптимизацию я вообще молчу, но работать конечно же будет :) Хотя я бы порекомендовал перед тем как его писать задасться одним маленьким вопросом - а на кой параметры в ХП передавать в виде стринговой строки с разделителем ? Может их легче на клиенте подготавливать до удобочитаемого вида, чем заниматься такими извратами с точки зрения СУБД ?

Приведенный выше пример - частный случай из следующей задачи:
В web-клиенте отображается набор записей. Пользователь по каким-либо правилам и просто так может пометить множество записей, над которым надо произвести какие-либо действия, с помощью checkbox. В основном это изменение или удаление группы записей.
Я вижу реализацию двумя вариантами:
1) Дергается ХП N-ое количество раз, изменяя или удаляя одну запись за каждый вызов.
2) В ХП передается строка, содержащая набор параметров (напр. идентификаторов), разделенных запятой, а в ХП выполняется что-то типа (упрощенно)
Код: plaintext
1.
2.
EXECUTE IMMDEDIATE('DELETE FROM MyTable 
     WHERE Param in (' || _Param || ')';
или
Код: plaintext
1.
2.
3.
EXECUTE IMMDEDIATE('UPDATE MyTable 
     SET ....
     WHERE Param in (' || _Param || ')';
Т.к. действие может выполняться над несколькими тысячами / десятками тысяч записей, то я выбрал второй вариант, т.к. он быстрее (как мне кажется).
Но иногда возникают сложности при использовании данного метода (хочется придерживаться унифицированного интерфейса между клиентом и ХП для групповых операций), иллюстрированные приведенным выше примером (иногда требуется вставка строк с недостающими значениями).

ASCRUS
Ну и вообще хотелось бы узнать, с чего навеяна такая странная форма передачи параметров - действительно обоснованной необходимостью или же просто неопытностью или не знанием правил проектировки в ASA ?

Я оставлю это на ваше усмотрение, тем не менее мне очень интересно узнать альтернативы решения в контексте данной задачи, возможно они очень облегчат мою жизнь =)

Заранее благодарю.
...
Рейтинг: 0 / 0
Добавление записей
    #32515278
Фотография ASCRUS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторПриведенный выше пример - частный случай из следующей задачи:
В web-клиенте отображается набор записей. Пользователь по каким-либо правилам и просто так может пометить множество записей, над которым надо произвести какие-либо действия, с помощью checkbox. В основном это изменение или удаление группы записей.
Сам я вебом не занимался, но на вскидку предложил бы сделать через динамический SQL вот так:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
CREATE PROCEDURE Proc (
  IN _nAnotherID integer, 
  IN _SQL long varchar
)
BEGIN
  // Обьявляем времянку передаваемых значений
  DECLARE LOCAL TEMPORARY TABLE #Values (
    strString varchar( 20 )
  ) ON COMMIT PRESERVE ROWS;

  // Выполняем переданный скрипт
  EXECUTE IMMEDIATE _SQL;

   /* Теперь все помеченные значения находятся
      в таблице #Values и дальше можем делать что хотим.
      ...
  */ 
END;
В клиенте мы формируем батч SQL-скрипт вставки в таблицу #Values на все помеченные значения. В содержании строки должно получится что то типа того:
Код: plaintext
1.
2.
3.
4.
5.
6.
_SQL = "
      INSERT INTO #Values (strString) VALUES('bbb');
      INSERT INTO #Values (strString) VALUES('ddd');
      INSERT INTO #Values (strString) VALUES('eee');
      INSERT INTO #Values (strString) VALUES('ddd');
    "
Перевод строки ставить не обязательно. Теперь достаточно вызвать процедуру и передать ей переменную _SQL, она создаст таблицу #Values, выполнит скрипт, тем самым ее заполнив нужными значениями и уже в нормальной релляционной форме можно будет запросами INSERT, UPDATE, DELETE провести необходимые операции. Этот метод будет в сотни раз быстрее работать, чем поиск запятых в цикле и операции над несчастной стринговой строкой :) На десятках тысяч записей я думаю эта процедура отработает моментально, а вот предложенный Вами метод будет в цикле выполнять 10000 запросов и займет довольно продолжительное время.

P.S. Для 9-ой версии ASA можно будет еще добиться увеличения скорости ХП, указав в описании темповой таблицы вместо "ON COMMIT PRESERVE ROWS" опцию "NOT TRANSACTIONAL".
...
Рейтинг: 0 / 0
Добавление записей
    #32515971
Действительно, великолепная идея! =)
В случае, когда выполняемое действие отличается от простых UPDATE и DELETE над множеством (WHERE IN) значений, когда приходится парсить строку, вместо того, делать это на стороне сервера и заполнять временную таблицу и/или выполнять некий набор действий над ней, можно отдать это на откуп клиенту!
Можно развить вашу мысль в сторону большей универсальности (т.к. могут меняться набор и типы данных в таблицах):
В подобных случаях можно использовать в интерфейсе между клиентом и ХП эмуляцию массива данных, представляющую собой таблицу #Array с единственным строковым полем (напр. varchar(64)). В клиенте мы формируем батч SQL-скрипт вставки в таблицу #Array на все помеченные значения в виде строковых параметров, а ХП заполняет ее и может выполнять над ней любой набор действий, в особо тяжелых случаях даже пробегаться курсором, при необходимости "кастуя" (CAST) строки к необходимому (ожидаемому) типу данных (целое, дата/время и т.д.).
Большое спасибо, мне было нужно именно такое решение!
...
Рейтинг: 0 / 0
5 сообщений из 5, страница 1 из 1
Форумы / Sybase ASA, ASE, IQ [игнор отключен] [закрыт для гостей] / Добавление записей
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]