Консультация № 167400
15.05.2009, 22:57
0.00 руб.
0 10 2
Здравствуйте, коллеги.

Есть такой вопрос -

Имеем SQL Server 2005 с некой базой данных.

Имеем внутри БД хранимую процедуру StoreProcA, которая выполняет несколько INSERT (что является невозможностью превращения её в функцию, к сожалению) и возвращает некое значение -- SELECT @RetVal

Имеем вторую хранимю процедуру StoreProcB, которая выполняет простой SELECT.

Задача:

вызвать процедуру StoreProcA внутри SELECT'а процедуры StoreProcB. То есть вот так:

SELECT
field1,
field2,
field3,
(StoreProcA field1,field2,field3) as field4
from SomeTable
where SomeThing = @SomeThing

Есть, конечно, вариант сначала вызвать процедуру StoreProcB и затем в С# в цикле вызывать процедуру StoreProcA и вносить возвращаемое значение в поле field4, но хотелось бы это решить средствами SQL, если это вообще возможно, а то поиски в Google ощутимых результатов не дали.

Заранее всем благодарен за помощь.

Обсуждение

Неизвестный
16.05.2009, 22:33
общий
это ответ
Здравствуйте, Иоффе Мэир Вэлевич!

Для вашей задачи может быть эффективным использование курсора - возможно существуют диалекты SQL которые позволяют подобные конструкции - то T-SQL к ним явно не оносится. А вот работа с курсором - имхо вероятно то что вам надо.
4
Неизвестный
16.05.2009, 22:59
общий
это ответ
Здравствуйте, Иоффе Мэир Вэлевич!
1) решение: можно из StoreProcA вернуть тип таблицу, тогда из нее в нее банально можно будет делать SELECT, ну и объединить (JOIN) его с остальными результатами
2) А чем Вас не устраивают стандартные OUT параметры хранимых процедур? Для примера:
CREATE PROCEDURE [dbo].[StoreProcA] (@ret int OUT)
AS
-- There Somereal stuff, then return needed values:
SET @ret = 77
GO

Далее, уже в StoreProcB:

DECLARE @somevar int;
EXEC test.test @somevar OUT

SELECT
field1,
field2,
field3,
@somevar as field4
from SomeTable
where SomeThing = @SomeThing

....
3
Не, не то. Внимательнее читайте вопрос.
Неизвестный
17.05.2009, 23:42
общий
Varkon, да, такая мысль меня посещала, но я решил не лезть в дебри SQL Server'a и не трогать то, что простому смертному трогать не положено :-))

Hubbitus, нет, Ваш вариант "не канает", к сожалению.
Обратите внимание на вопрос.

SELECT
field1,
field2,
field3,
(StoreProcA field1,field2,field3) as field4

У меня StoreProcA принимает параметрами поля возвращаемые в SELECT. соответственно исполнять эту процедуру перед этим селеком не имеет никакого смысла, так как неоткуда брать входные параметры для неё.

Ладно, я пока сделал так, как говорил (вызываю StoreProcA в цикле в программе), возможно позже оптимизирую как-нибудь. возможно с триггером каким или ещё чего придумаю.
Неизвестный
18.05.2009, 00:15
общий
Да, не доглядел, прошу прощения, не подойдет так.

Тут дело в том, почему собственно нельзя изменять данные в UDF, что в подобном запросе, если StoreProcA будет изменять данные, которые в даннывй момент выбираются, может возникнуть неопроеделенная ситуация, даже при должном уровне изоляции и нельзя гарантировать целостность данных.

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

Если Вам нужно именно на каждый ряд вызывать эту процедуру и изменять данные, то наверное только курсор. Это не сложно совсем, но обычно блокирует таблицу на время обработки.

Может быть Вы подробнее опишете задачу и предметную область, и вместе попробуем придумать как это все переделать красивее?
Неизвестный
18.05.2009, 14:03
общий
не, блокировка таблицы не пойдёт. проблема в том, что к этой таблице должна быть куча запросов (точнее там с 10-ок таблиц в запросе) и на каждую возвращённую запись нужно создать сессию и вносить данные в две "черновые" таблицы.
Речь идёт о запросах цен на номера в гостинице. а "черновые" таблицы это непосредственно таблица с данными о найдёном номере (тип комнаты, цена, кол-во человек в номере, дата приезда, дата отъезда и т.д.),
а вторая таблица это цены по дням, так что у меня там ещё и цикл стоит, который забивает цены на все даты в запросе.

нужно это для того, чтобы снизить нагрузку на таблицы и не запускать Select на 10-ок таблиц ещё и для внутреннего пользования, а просто пойти с номером сессии в черновую таблицу и взять все необходимые данные из всего лишь одной таблицы.
Если пользователь осуществляет заказ, то сессия обновляется и в неё дописывается номер заказа.
Если не осуществляет, то сессия удаляется когда пользователь закырвает страницу или когда кончается Session на сервере.

это, в принципе, сокращённая модель происходящего.

но, как я уже сказал, я сейчас делаю это на сервере - сначала StoreProcB, а потом в цикле StoreProcA.
можно сказать, что проблема решена малой кровью.
Неизвестный
18.05.2009, 14:09
общий
То есть денормализация. А триггер повесить нельзя? И что, на каждый такой select во вспомогательных таблицах появляются кучи записей? Тоже как-то не хорошо, если оно позже не надо будет, то нагрузка лишняя получится.

А индексированные вьюхи не спасут производительность, без формирования дополнительных табдиц и денормализации БД?
Неизвестный
19.05.2009, 21:13
общий
нельзя повесить тригер. не хочет он вешаться на SELECT.
Да, на каждую запись возвращённую из SELECT нужно делать несколько INSERT. Так работает система. не я её придумывал и это самый оптимальный вариант.

не думаю, что "индексированиые вьюхи" смогут помочь. Я, правда, не очень хорошо помню что это такое (я всё таки не специализируюсь на SQL), но если я всё таки не ошибаюсь, то - нет.
Неизвестный
20.05.2009, 00:15
общий
Индексированные вьюхи, это по сути и есть денормализация БД, только несколько неявная. Суть в том, что можно создать вьюху (представление, view), скажем выборки из множества таблиц, в том числе с подзапросами и вычисляемыми полями. А потом, чтобы это работало быстрее, построить на необходимых (всех) столбцах скажем кластерный индекс, обеспечив таким образом покрытие индексом наиболее частых запросов. Получится что и данные будут "живые", и работать все будет весьма шустро (естестенно за счет размера индексов и разбухания БД, но Вы и так это делаете вручную, а тут хоть не нужно будет следить за актуальностью)
Неизвестный
21.05.2009, 08:43
общий
ок. нужно будет попробовать.
Хотя я и не уверен, что это сработает.

Спасибо за помощь.
Неизвестный
25.05.2009, 09:32
общий
Иоффе Мэир Вэлевич:
а если разбить запрос на два ?
первый запрос формирует данные во временную таблицу, а процедура StoreProcA уже будет возвращать требуемый набор данных ?
а что если перенести исходный запрос в процедуру StoreProcA ?
Это возможно ? тогда в рамках этой процедуры выполняем всю обработку и возвращаем требуемый набор данных.
Форма ответа