Просмотр полной версии : Есть ли спецы по MS SQL server
Из за ограничения оборудования, пришлось переехать с постгре на сабж. Кроме множества мелких непоняток, которые решил своими силами возник такой-вот вопросец:
Имеется процедура, следующего содержания, немного поскипано:
-- Получаем номер "базы", на которой расположен наш завод
SELECT @wid = wp_id FROM plants WHERE id = @pid;
-- Создаем "ручной" талон
INSERT INTO tickets (volume, wp_id, car_no, in_no) VALUES (@kl, @wid, '---', '-1');
SET @tid = IDENT_CURRENT('tickets');
-- Обновляем статус талона на "Выполняется"
INSERT INTO v_te (ticket_id, st, plant_id, line_id) VALUES (@tid, 3, @pid, @lid);
Она работает, но идент поле (id, тут не показано) получается с приращением +2, а не +1, как описано в DDL таблицы. Тригеров никаких нет. Чо за дела?
В BOL сказано, что такие приращения могут быть из-за ошибок в инсерте, но здесь ошибок не происходит.
Нипаанятно!
id - AUTO_INCREMENT ? на ум приходит сделать выборку select max(id) перед инсертом и вставлять id "руками"
---------- Сообщение добавлено в 19:18 ---------- Предыдущее сообщение было в 19:18 ----------
тьфу, не глянул ms sql... ну смысл ты понял
AlikForever
22.10.2012, 20:52
Из за ограничения оборудования, пришлось переехать с постгре на сабж. Кроме множества мелких непоняток, которые решил своими силами возник такой-вот вопросец:
Имеется процедура, следующего содержания, немного поскипано:
-- Получаем номер "базы", на которой расположен наш завод
SELECT @wid = wp_id FROM plants WHERE id = @pid;
-- Создаем "ручной" талон
INSERT INTO tickets (volume, wp_id, car_no, in_no) VALUES (@kl, @wid, '---', '-1');
SET @tid = IDENT_CURRENT('tickets');
-- Обновляем статус талона на "Выполняется"
INSERT INTO v_te (ticket_id, st, plant_id, line_id) VALUES (@tid, 3, @pid, @lid);
Она работает, но идент поле (id, тут не показано) получается с приращением +2, а не +1, как описано в DDL таблицы. Тригеров никаких нет. Чо за дела?
В BOL сказано, что такие приращения могут быть из-за ошибок в инсерте, но здесь ошибок не происходит.
Нипаанятно!
Какой таблицы, v_te? Точно IDENTITY(1,1)? Можешь Script Table->Create To сделать?
PS: и если уже взялся за извраты, то лучше SCOPE_IDENTITY, а то мало ли кто вклинится между вызовами ;)
на ум приходит сделать выборку select max(id)
Принципиально - нет, база многопользовательская.
Какой таблицы, v_te?
нет, "tickets". v_te - вьюшка с таблицы ticket_events с триггером на вставку такого вида:
UPDATE ticket_events SET ... WHERE ...
INSERT INTO ticket_events () VALUES ()
Нужно для "версионности" таблицы эвентов (ну, как курсы валют), что бы потом можно было проследить порядок изменения статуса талона.
Точно IDENTITY(1,1)?
Точно, проверил в первую очередь, на всякий случай пересоздал таблицу.
Кстати, сейчас заметил, что и в ticket_events та же шляпа.
то лучше SCOPE_IDENTITY
Смотрел на нее, но не разобрался в майкрософтовских терминах. И вроде, как я понял IDENT_CURRENT - тот же SCOPE, только с фильтром по имени таблицы. Но попробую, спасибо.
и если уже взялся за извраты,
Обычная ситуация со вставкой в master-detail отношения. В нормальных СУБД влет решается генераторами. Если есть штатное решение для MS - с удовольствием выслушаю, так как таких таблиц у меня несколько.
ЗЫ. Можно, конечно, это перенести в контроллер, но в постгре это занимает 3 строки, и все работает, в MS - 3 строки, все работает, но с непонятным глюком, в контроллере мне это выйдет по 200 строк кода на каждое отношение.
AlikForever
22.10.2012, 21:58
Смотрел на нее, но не разобрался в майкрософтовских терминах. И вроде, как я понял IDENT_CURRENT - тот же SCOPE, только с фильтром по имени таблицы. Но попробую, спасибо.
Ну тут дело в параллельных транзакциях, если какая-нить транзакция вклинится после твоего инсерта и выполнит еще сверху свой инсерт - то IDENT_CURRENT вернет тебе последнее значение и ты неправильно связку сделаешь. а SCOPE_IDENTITY по идее должен то что надо вернуть. Но я этим не пользуюсь никогда.
Обычная ситуация со вставкой в master-detail отношения. В нормальных СУБД влет решается генераторами. Если есть штатное решение для MS - с удовольствием выслушаю, так как таких таблиц у меня несколько.
решается созданием отдельной таблички sequence, в которой для каждой таблички по имени счетчик лежит. Для получения-и-инкремента можно хранимку написать типо getNextID(table_name) (это если не через контроллер делать).
вот как-то так (стырил тока что в нете), оформить тока как функцию.
CREATE TABLE Sequence(Name VARCHAR(50) NOT NULL, ID INT NOT NULL DEFAULT(0))
--- тут вот CREATE FUNCTION
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
BEGIN TRAN
UPDATE Sequence WITH(HOLDLOCK) SET ID = ID + 1 WHERE Name = 'Table1'
SELECT ID FROM Sequence WHERE Name = 'Table1'
COMMIT TRAN
ЗЫ. Можно, конечно, это перенести в контроллер, но в постгре это занимает 3 строки, и все работает, в MS - 3 строки, все работает, но с непонятным глюком, в контроллере мне это выйдет по 200 строк кода на каждое отношение.
так как ты написал должно работать нормально - проблема где-то в другом месте. автоинкремент где-то два раза вызывается, возможно первый раз валится с ошибкой. Если дамп базы дашь - могу поискать.
---------- Сообщение добавлено в 20:54 ---------- Предыдущее сообщение было в 20:50 ----------
PS: про триггеры вообще забудь как страшный сон ;)
---------- Сообщение добавлено в 20:58 ---------- Предыдущее сообщение было в 20:54 ----------
Кстати, начиная с MS SQL 2011 говорят появились нормальные sequence, так что если можешь поставить его - то дерзай :)
можно хранимку написать типо getNextID(table_name)
Тут тоже конкуренция возможна, при одновременном запросе от двух транзакций.
PS: про триггеры вообще забудь как страшный сон
Ок, переделаю все на процедуры ))
автоинкремент где-то два раза вызывается
Это понятно, BOL так сразу и намекает.
Если дамп базы дашь - могу поискать.
Завтра скину, если тебе не лень )
AlikForever
22.10.2012, 22:20
Тут тоже конкуренция возможна, при одновременном запросе от двух транзакций.
да не, запись с именем таблицы до commit залочится, с этим все ок.
Завтра скину, если тебе не лень )
да, кидай - я думаю быстро разберусь :) Можешь попробовать тригер и вьюшку прибить сперва и попробовать )
запись с именем таблицы до commit залочится
MS все еще на блокировках? Уууу, как все запущено ) Я, конечно, слышал, что MS SQL "не айс", но все как-то не верил )
Ок, завтра перепишу логику на хранимках, и если останутся траблы, скину скриптик.
ЗЫ. У меня 2005 (контроллер заявляет поддержку только его). Ну, и еще он EXPRESS, так как баз нужно много, а ограничение на 4 гига данных для меня не является ограничением, максимум метров 20-30 будут.
AlikForever
23.10.2012, 01:09
MS все еще на блокировках? Уууу, как все запущено ) Я, конечно, слышал, что MS SQL "не айс", но все как-то не верил )
ЭЭЭ, а как ты себе по другому это представляешь?)) Когда две транзакции пытаются обновить одну запись - кто-то же должен подождать? (в смысле блокировка на запись)
---------- Сообщение добавлено в 00:09 ---------- Предыдущее сообщение было в 00:06 ----------
Ну, и еще он EXPRESS, так как баз нужно много, а ограничение на 4 гига данных для меня не является ограничением, максимум метров 20-30 будут.
Это даже не объемы))
PS: с MS SQL все более-менее норм, кстати, не знаю чего ты так категорично) Просто триггерами-шмигерами ее грузить не надо и индексы где нужно включать - в остальном все зависит от кривизны рук больше)
ЭЭЭ, а как ты себе по другому это представляешь?))
Не, я не дорос, но люди, версионность (http://ru.wikipedia.org/wiki/MVCC)уже придумали )
не знаю чего ты так категорично)
Очень много вроде есть - но работает либо с ограничением, либо как с триггерами - лучше не использовать.
Реально полезное пока нашел только одно - простой инкрементальный бэкап.
AlikForever
23.10.2012, 11:54
Не, я не дорос, но люди, версионность (http://ru.wikipedia.org/wiki/MVCC)уже придумали )
"Этот способ управления позволяет добиться того, что пишущие транзакции не блокируют читающих, и читающие транзакции не блокируют пишущих." - у 2005+ по идее тоже должно быть все ок с этим.
А ты попробуй на своей старой базе обновить одну запись из двух потоков. В одном потоке обнови и не комить, а из второго обновление запусти.
Очень много вроде есть - но работает либо с ограничением, либо как с триггерами - лучше не использовать.
Реально полезное пока нашел только одно - простой инкрементальный бэкап.
для твоих объемов данных у MS SQL нет проблем, есть мелкие неудобства скорее))
Переделал на процедурку - то же самое. дамп во вложении (переименовать в db_dump.7z и распаковать).
Интересует процедурка cmt. Вызов:
cmt 6, 1, 1
Она за раз создает по одной новой записи в таблицах tickets и ticket_events. Вызывать можно несколько раз с одними и теми же параметрами.
есть мелкие неудобства скорее))
MS SQL - мелкие неудобства???
Простой отказ от тригеров приводит к появлению кучи "копипаста" по процедурам, много одних и тех же действий в разных местах, что в скором будущем приведет к тому, что вносить изменения в БД будет сложнее, чем переписать с нуля.
А чего стоит непонятный запрет на использование инсертов в функциях?
А возврат табличных данных из процедуры? Во первых что бы эту возможность, нужно инет переыть (в BOL нету описания), так еще и о типизации возвращаемых значений можно забыть (что опять же на сопровождении сказывается).
А выполнить select из процедуры, возвращающей табличные данные? А транспонирование результата запроса?
Это еще не все, с чем я столкнулся за неполный месяц общения.
ЗЫ. Самые лучшие решение (исходя из моей практики) простые и, соответственно, красивые. При этом они еще и надежные выходят. А тут все на костылях и обертках получается.
AlikForever
23.10.2012, 18:12
Переделал на процедурку - то же самое. дамп во вложении (переименовать в db_dump.7z и распаковать).
Интересует процедурка cmt. Вызов:
cmt 6, 1, 1
Она за раз создает по одной новой записи в таблицах tickets и ticket_events. Вызывать можно несколько раз с одними и теми же параметрами.
У меня сработало нормально. за два раза создались tickets c id 64,65 и ticket_events - 74,75. Все ок :)
PS: и называй все сущности в единственном числе, вроде как принято так :)
---------- Сообщение добавлено в 17:12 ---------- Предыдущее сообщение было в 17:07 ----------
Может MDF файл пришли?
PS: и называй все сущности в единственном числе, вроде как принято так
У меня наименования пришли из Delphi. Там такая была была система (Strings, но StringList, Events).
У меня сработало нормально. за два раза создались tickets c id 64,65 и ticket_events - 74,75. Все ок
Ну, вот ) У меня перед отправкой - 61 и 63 и 71 и 73. После этого сделал дамп и отправил. И это не EXPRESS, это полный MSSQL.
Вот как к такому относится? )
---------- Сообщение добавлено в 18:14 ---------- Предыдущее сообщение было в 18:13 ----------
Может MDF файл пришли?
Админа БД у нету уже. Завтра попробую.
AlikForever
23.10.2012, 18:23
MS SQL - мелкие неудобства???
Простой отказ от тригеров приводит к появлению кучи "копипаста" по процедурам, много одних и тех же действий в разных местах, что в скором будущем приведет к тому, что вносить изменения в БД будет сложнее, чем переписать с нуля.
А чего стоит непонятный запрет на использование инсертов в функциях?
А возврат табличных данных из процедуры? Во первых что бы эту возможность, нужно инет переыть (в BOL нету описания), так еще и о типизации возвращаемых значений можно забыть (что опять же на сопровождении сказывается).
А выполнить select из процедуры, возвращающей табличные данные? А транспонирование результата запроса?
Это еще не все, с чем я столкнулся за неполный месяц общения.
ЗЫ. Самые лучшие решение (исходя из моей практики) простые и, соответственно, красивые. При этом они еще и надежные выходят. А тут все на костылях и обертках получается.
"простой отказ от триггеров" - тебя должно выворачивать уже при одном упоминании этого слова)) это не простой отказ)
PS: по поводу всего остального - когда у тебя будут таблицы по несколько десятков (сотен) миллионов записей, ты и про все остальные слова забудешь) Будешь только радоваться когда поиск в индексе отработал быстро :) И при этом содержание самого индекса не вырубает общую производительность в ноль :)
---------- Сообщение добавлено в 17:23 ---------- Предыдущее сообщение было в 17:18 ----------
У меня наименования пришли из Delphi. Там такая была была система (Strings, но StringList, Events).
---
Админа БД у нету уже. Завтра попробую.
Поставь у себя на компе хотя бы даже экспресс, и базу из скриптов своих же подними. Если будет все ок - покажи админу бидэ и спроси wtf :)
PS: ох уж этот дельфи ;)
У тебя объемы большие, логика простая, у меня объемы маленькие, логика сложная. На клиента ее вынести не могу и не хочу - принципиально неверно.
Поэтому и бухтю ) Я же даже не с ораклом сравниваю, с опенсорсом.
Вот, кстати, как без триггеров решить проблему (сидю и думаю):
В таблице допускается множество записей с одинаковым значением поля "ID" и значением поля "ST" <> 3 (допустим). Если "ST" = 3, то такая запись для указанного "ID" должна быть только одна.
Еще, похожая: тоже, только ("CL" is null) и ("CL" is not null)
У постгре - это разделяемые индексы. Тут такого не нашел, думал триггер повесить.
по несколько десятков (сотен) миллионов записей, ты и про все остальные слова забудешь)
Кстати, вспомнил, как года 3 назад, когда заморачивались с GIS, вопрос быстрого поиска в огромных объемах очень красиво решился кластеризацией таблиц (штатная фишка постгре и оракла) по основным критериям поиска.
AlikForever
23.10.2012, 22:10
У тебя объемы большие, логика простая, у меня объемы маленькие, логика сложная. На клиента ее вынести не могу и не хочу - принципиально неверно.
Поэтому и бухтю ) Я же даже не с ораклом сравниваю, с опенсорсом.
Вот, кстати, как без триггеров решить проблему (сидю и думаю):
В таблице допускается множество записей с одинаковым значением поля "ID" и значением поля "ST" <> 3 (допустим). Если "ST" = 3, то такая запись для указанного "ID" должна быть только одна.
Еще, похожая: тоже, только ("CL" is null) и ("CL" is not null)
У постгре - это разделяемые индексы. Тут такого не нашел, думал триггер повесить.
Никогда не решал вопросы бизнес-логики на уровне базы, вот никогда :) База это просто структура данных с какими-то отношениями, не надо ее перегружать всяким мусором)
---------- Сообщение добавлено в 21:10 ---------- Предыдущее сообщение было в 21:04 ----------
Кстати, вспомнил, как года 3 назад, когда заморачивались с GIS, вопрос быстрого поиска в огромных объемах очень красиво решился кластеризацией таблиц (штатная фишка постгре и оракла) по основным критериям поиска.
Кластеризация это просто файловое хранилище по кластеру раскидывают? ну это вопрос больше к админам..
Никогда не решал вопросы бизнес-логики на уровне базы, вот никогда
Ну, у каждого свои недостатки ))
Кластеризация это просто файловое хранилище по кластеру раскидывают?
не, боунсеры - это отдельная тема. Тут примерно так:
Есть у тебя 100 сотрудников, у каждого тыщамильенов записей. И тебе очень часто нужны данные по одному или нескольким сотрудникам. Если грубо, то кроме основной таблицы, создаются 100 таблиц (для каждого сотрудника). И тогда, если нам нужно выбрать все документы какого-либо сотрудника, нет необходимости перывать все 100 тыщ мильенов записей, нужно обратиться к таблице этого сотрудника, и пересмотреть только одну тыщу мильенов (на самом деле меньше, принимая во внимание индексы). Т.е. скорость поиска увеличивается на 2 порядка (примерно).
AlikForever
24.10.2012, 01:18
не, боунсеры - это отдельная тема. Тут примерно так:
Есть у тебя 100 сотрудников, у каждого тыщамильенов записей. И тебе очень часто нужны данные по одному или нескольким сотрудникам. Если грубо, то кроме основной таблицы, создаются 100 таблиц (для каждого сотрудника). И тогда, если нам нужно выбрать все документы какого-либо сотрудника, нет необходимости перывать все 100 тыщ мильенов записей, нужно обратиться к таблице этого сотрудника, и пересмотреть только одну тыщу мильенов (на самом деле меньше, принимая во внимание индексы). Т.е. скорость поиска увеличивается на 2 порядка (примерно).
мб это? Шардирование (http://ru.wikipedia.org/wiki/%D0%A8%D0%B0%D1%80%D0%B4%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5) aka партиционирование. В реальности геморрой еще тот, и проработка структуры базы требуется серьезная. Проблема в том что секции по каким-то условиям задаются, а эти условия не всегда получается проследить. Мы у себя уже несколько раз поднимали этот вопрос, но как-то все на потом откладывается. :)
PS: в MS SQL тоже есть такое ;) http://www.sql.ru/articles/mssql/2005/073102partitionedtablesandindexes.shtml
AlikForever, вот еще загадко. Тока что возникла.
Преамбле:
То же оборудование. Каждый лишний запрос в нем превращается в 20-40 строк кода и время реакции увеличивается в 3 раза. Соответственно, пытаемся свести их к минимуму.
Задача:
Вставить запись, получить ее код, что бы насовать потом этой записи "подчиненных" в другую таблицу. Одним запросом.
На постгре, естественно "SELECT * FROM func(a,b,c,d)", где в func можно повставлять в сотню таблиц сотню записей, и вернуть то что нуна.
В MS - засада. Процедура вызывается EXEC, нужно где-то декларировать переменную, как ее потом вернуть в виде набора из одной записи с одним полем - непонятно.
Пробовал UDF.
CREATE FUNCTION dbo.p_ti_create ( @wpid TINYINT, --- Код завода
@plid TINYINT, --- Код завода (может быть 0)
@liid TINYINT, --- Код линии (может быть 0)
@in_no VARCHAR(15),
@car_no VARCHAR(10),
@prid INT, --- Код товара
@reid INT, --- Код рецепта
@vol FLOAT --- Заданый объем
)
RETURNS @out table (id int)
AS
BEGIN
DECLARE @tid INT;
INSERT INTO tickets (wp_id, in_no, car_no, product_id, recipe_id, volume)
VALUES (@wpid, @in_no, @car_no, @prid, @reid, @vol);
SET @tid = SCOPE_IDENTITY();
INSERT @out (id) VALUES(@tid);
INSERT INTO ticket_events (ticket_id, plant_id, line_id, st)
VALUES (@tid, @plid, @liid, 1);
RETURN
END
Ругаиццо на инсерты (первый и последний), типа они контекст рушат
Как быть?
Подумал, может как-то сформировать строку, содержащую сразу все записи и передать ее на выполнение процедуре? Есть у него какой-нить толковый разборщик строк? Типа strtok
- - - Добавлено - - -
И может знаешь простой способ аналога LIMIT?
Подумал, я наверное неверно поступаю. Навязываю свое видение. Короче. Есть структура:
struct p_data
id: int
mix_of_fields: <int, real, time>
end_struct
struct portion
id: int
mix_of_fields: <int, real, time>
data: array [0..15] of p_data
end_struct
struct history
id: int
mix_of_fields: <int, real, time>
portions: array [0..19] of portion
end_struct
т.е. структура "история" имеет несколько подструктур "порции", в каждой порции - некоторое кол-во данных.
Нужно это дело сохранить по соответствующим таблицам.
И есть хитрость. Данная структура может заполняться долго (порядка 10-15 мин), а базу нужно держать как можно актуальнее.
Поэтому, создан "обходчик", который раз в секунду обходит структуру, находит те записи, у которых id = 0, но остальные данные заполнены и в зависимости от того, на каком "подуровне" он находится, формирует SQL на запись данного элемента. Затем присваивает код новой записи полю id и в следующий раз ее пропускает. После того, как все уровни будут заполнены и записаны, миссия считается выполненной.
AlikForever
28.08.2013, 23:07
sansa, какие-то странные условия у вас там :) а каких-нить batch insert-ов не используете? Т.е. надо чтоб вся логика в одной процедуре была?
PS: кстати почему очередь на обновление не сделали, зачем бегать каждый раз по структуре?
- - - Добавлено - - -
Вот нашел прикольный пример. Передают в параметры функции XML, а дальше его парсят.
http://stackoverflow.com/questions/1069311/passing-an-array-of-parameters-to-a-stored-procedure
PS: я просто на работе уже года 4 как функций не писал, в базе даже FK уже не встришь у нас. :) Расскажи попроще что нужно, что-то я до сих пор не понял в чем проблема. По идее если ты передашь в функцию все нужные параметры, то внутри можно сделать будет что угодно.
AlikForever
28.08.2013, 23:23
Вот гигантский обзор http://www.sommarskog.se/arrays-in-sql-2005.html
а каких-нить batch insert-ов не используете?
Вот код, который в "цикле" читает 10 записей по одному полю из базы данных (на самом деле полей 4, но они на сервере упаковываются в строку, потому распарсить ее быстрее, чем читать по одному).
CASE step OF rbuBDC_CONNECT:
strcpy(ADR(ErrMsg), ADR(''));
codi.enable:= TRUE;
codi.DBCD:= DBCDCurr;
step:= rbuBDC_CONNECT_r;
rbuBDC_CONNECT_r:
codi();
step:= CheckDbConnected(codi.status, step, rbuBDC_CONNECT_DONE, rbuBDC_ERROR);
rbuBDC_CONNECT_DONE:
step:= rbuDB_RD_BU_COMP;
(********************************************************************
* Чтение компонентов бункеров
********************************************************************)
rbuDB_RD_BU_COMP:
rbuDBUBuSQL(ADR(vSQL), PlantID, GLine1.ID);
dbs.enable:= TRUE;
dbs.connectionIdent:= codi.ident;
dbs.pSqlStatement:= ADR(vSQL);
step:= rbuDB_RD_BU_COMP_r;
rbuDB_RD_BU_COMP_r:
dbs();
I:= 1;
step:= CheckDbStatus(dbs.status, step, rbuDB_RD_BU_COMP_FNR, rbuBDC_ERROR);
rbuDB_RD_BU_COMP_FNR: // Получение следующей записи
bunker_id:= 0;
component_id:= 0;
fnr.enable:= TRUE;
fnr.connectionIdent:= codi.ident;
step:= rbuDB_RD_BU_COMP_FNR_r;
rbuDB_RD_BU_COMP_FNR_r:
fnr();
step:= CheckDbStatus(fnr.status, step, rbuDB_RD_BU_COMP_GD, rbuDB_RD_BU_COMP);
rbuDB_RD_BU_COMP_GD: // получение упакованых данных (поле dat)
gd(enable:= TRUE, connectionIdent:= codi.ident,
columnIdx:= 1,
dataType:= DB_SQL_CHAR,
pData:= ADR(s1),
dataSize:= SIZEOF(s1)
);
step:= CheckDbStatus(gd.status, step, rbuDB_RD_BU_COMP_GD_Parse, rbuBDC_ERROR);
rbuDB_RD_BU_COMP_GD_Parse: // рапаковка строки по полям
n:= toktoud(ADR(s1), ADR(bunker_id), DEF_DELIM);
n:= strtok(n, ADR(bun), DEF_DELIM, SIZEOF(bun));
n:= toktoud(n, ADR(component_id), DEF_DELIM);
n:= strtok(n, ADR(bucn), DEF_DELIM, SIZEOF(bun));
step:= rbuDB_RD_BU_COMP_GD_DONE;
rbuDB_RD_BU_COMP_GD_DONE: // Запись считана (если 10, выходим, иначе снова в цикл)
IF IDXValid(bunker_id, BUNKER_COUNT) THEN
BUParams[bunker_id].CoID:= component_id;
BUParams[bunker_id].Name:= bun;
BUParams[bunker_id].CoN:= bucn;
I:= I + 1;
IF (I <= BUNKER_COUNT) THEN
step:= rbuDB_RD_BU_COMP_FNR;
ELSE
step:= rbuDB_RD_TICKET;
END_IF
ELSE
step:= rbuBDC_ERROR;
END_IF
rbuBDC_ERROR:
I:= 0;
ErrMsg:= 'Unknown DB error!';
gem.enable:= TRUE;
gem.connectionIdent:= codi.ident;
gem.pErrorMessage:= ADR(ErrMsg);
gem.errorMessageSize:= SIZEOF(ErrMsg);
step:= rbuBDC_ERROR_r;
rbuBDC_ERROR_r:
gem();
IF I < 20 THEN
step:= CheckDbStatus(gem.status, step, rbuBDC_ERROR_DONE, rbuBDC_ERROR_r);
ELSE
step:= rbuBDC_ERROR_DONE;
END_IF
I:= I + 1;
rbuBDC_ERROR_DONE:
DBError[0]:= TRUE;
IF TEP.Q THEN
step:= rbuBDC_DISCONNECT;
END_IF
rbuBDC_DISCONNECT:
codi.done:= TRUE;
step:= rbuBDC_DISCONNECT_r;
rbuBDC_DISCONNECT_r:
codi();
IF (codi.status = 0) AND (codi.ident = 0) THEN
step:= rbuBDC_CONNECT;
END_IF
END_CASE;
Выполняется он около 5 сек (порядка 50 раз вызывается по кругу, пока не дойдет до конца). А там у меня 20*16 записей. Да на каждую по 2 запроса, если новый id читать следом другим запросом.
Как ты думаешь, при таком коде еще не созрела мысль воспользоваться все-таки одним запросом? ))
Передают в параметры функции XML, а дальше его парсят.
думал, но это подходит для записи всей структуры целиком. А по ТЗ необходимо содержимое БД близкое по времени к структуре. Т.е. для данного случая, нужно ожидать пока вся структура заполнится.
- - - Добавлено - - -
Расскажи попроще что нужно, что-то я до сих пор не понял в чем проблема. По идее если ты передашь в функцию все нужные параметры, то внутри можно сделать будет что угодно.
Нужно:
Выполнить один запрос с параметрами, который вставит параметры в указанную таблицу, и вернет ID вставленной записи.
т.е
SELECT id FROM insert_fields_to_table1(@id, @f1, @f2, @f3)
AlikForever
29.08.2013, 00:27
Нужно:
Выполнить один запрос с параметрами, который вставит параметры в указанную таблицу, и вернет ID вставленной записи.
т.е
Ну, пишешь функцию которая делает insert и возвращает SCOPE_IDENTITY. Почему не подходит?
Вот пример с гугла, по идее работать должен:
CREATE PROCEDURE [dbo].[INS_FlightNewLeg]
@leg1 int,
@leg2 int,
@leg3 int,
@NewLegID int OUTPUT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO FlightLegs
Values(
@leg1,@leg2,@leg3
)
SELECT @NewLegID = SCOPE_IDENTITY()
END
- - - Добавлено - - -
думал, но это подходит для записи всей структуры целиком. А по ТЗ необходимо содержимое БД близкое по времени к структуре. Т.е. для данного случая, нужно ожидать пока вся структура заполнится.
я думал у тебя записи пачками накапливаются и ты хочешь пачками их записывать (одним селектом).
Вот пример с гугла, по идее работать должен:
А теперь запрос, как ее вызвать из клиента?
AlikForever
29.08.2013, 01:22
А теперь запрос, как ее вызвать из клиента?
ну если клиент SQL, то как-то так
declare @myRes int
exec [dbo].[INS_FlightNewLeg] @leg1 = 1, @leg2 = 2, @leg3 = 3, @NewLegID = @myRes output
А если нет, то все от языка зависит.
если JDBC, то вот так (с гугла своровано, но похоже на правду)
CallableStatement proc = connection.prepareCall("{ ? = call dbo.mySproc() }");
proc.registerOutParameter(1, Types.INTEGER);
proc.execute();
int returnValue = proc.getInt(1);
PS: у тебя какой клиент? я думаю гугл и с ним поможет :)
- - - Добавлено - - -
Кстати, если у тебя только id возвращается, то лучше сделать так:
Using Return
The last way to get data back from a stored procedure is also the most limiting. It only returns a single numeric value. This is most commonly used to return a status result or error code from a procedure. Consider this procedure:
CREATE PROC dbo.TestReturn (@InValue int)
AS
Return @Invalue
GO
The following script calls the TestReturn stored procedure:
DECLARE @ReturnValue INT
EXEC @ReturnValue = TestReturn 3
SELECT ReturnValue=@ReturnValue
AlikForever
29.08.2013, 01:26
и тогда твоя процедурка будет вроде:
CREATE PROCEDURE [dbo].[INS_FlightNewLeg]
@leg1 int,
@leg2 int,
@leg3 int
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO FlightLegs
Values(
@leg1,@leg2,@leg3
)
return SCOPE_IDENTITY()
END
PS: ну и вызов какой-то такой EXEC @ReturnValue = [dbo].[INS_FlightNewLeg] 1,2,3
ну и вызов какой-то такой EXEC @ReturnValue = [dbo].[INS_FlightNewLeg] 1,2,3
А как @ReturnValue мне прочитать в своей программе? Это из процедуры другую можно так вызывать. Ведь @ReturnValue - не набор данных. Можно через временную таблицу - но это опять 2 запроса.
Алик, можешь еще помочь? Не нашел на просторах решения, сам в силу незнания пока не могу.
Есть древовидная таблитсо: pt (id:int, parent_id: int, n:varchar(20))
Добавляю в нее поле с новомодной для 2008 фишкой "hierarchyid". В итоге, имеем, pt (id:int, parent_id: int, n:varchar(20), hid:hierarchyid)
Задача. Обновить поле hid в соответствии с id, parent_id. Тригеры на вставку/обновление ослилил с помощью TechNet, все новые данные вставляются и обновляются нормально (если, конечно hid уже заполнен). А вот существующие... Как не получаиццо, второй день. Пример от MS предназначен только для 1 уровня вложения, а выгружать/удалять/загружать обратно данные, и не труъ и невозможно, много таблиц с зависимостями.
Перевод: zCarot