Здравствуйте!
Проблема такова: имеется хранимая процедура, в неё передаю параметры, она возвращает 1 или 0.
В SQL студио работает на ура! В TS CRM x25 3.3.0.42 (MS SQL 2005) - не могу получить результат хранимки!
var Parameters = CreateSPParameters();
CreateSPParameter(Parameters, 'InvoiceID', pdtGUID, InvoiceID);
CreateSPParameter(Parameters, 'StoreID', pdtGUID, StoreID);
CreateSPParameter(Parameters, 'isEnought', pdtInteger, 0);
var SQLText = 'exec dbo.tsp_IsEnoughtOfferingInStore :InvoiceID, :StoreID, :isEnought OUTPUT';
Connector.DBEngine.ExecuteCustomSQL(SQLText, Parameters);
var IsEnought = Parameters.ItemsByName('isEnought').ValAsInt;
параметр 'isEnought' постоянно 0
Смотрел: http://community.terrasoft.ua/blogs/2171 и http://community.terrasoft.ua/node/1852
Буду благодарен за любую помощь!
Комментарии
Видимо нужно указать Parameters.ItemsByName('isEnought').ParamType = 1.
Так как у IParameter свойство ParamType: InputOutputParamTypeEnum по-умолчанию имеет значение 0, т.е. входящий:
ioptInput = 0,
ioptOutput = 1,
ioptInputOutput = 2
} InputOutputParamTypeEnum;
Большое спасибо, Александр!!!
Действительно, пропустил указать тип параметра.
Теперь работает:
CreateSPParameter(Parameters, 'InvoiceID', pdtGUID, InvoiceID);
CreateSPParameter(Parameters, 'StoreID', pdtGUID, StoreID);
CreateSPParameter(Parameters, 'isEnought', pdtInteger, 0);
Parameters.ItemsByName('isEnought').ParamType = 1; // It!
var SQLText = 'exec dbo.tsp_IsEnoughtOfferingInStore :InvoiceID, :StoreID, :isEnought OUTPUT';
Connector.DBEngine.ExecuteCustomSQL(SQLText, Parameters);
var IsEnought = Parameters.ItemsByName('isEnought').ValAsInt;
--
Cogito, ergo sum
--
www.it-sfera.com.ua
Рано тему закрывать! Новая проблема :)
При тестирование на обычной (MS SQL) конфигурации выходной параметр заполняется, но, при тестирование через WebServices - параметр НЕ заполняется!
В чем фишка?
--
Cogito, ergo sum
--
www.it-sfera.com.ua
Думаю что фишка в ядре. Скорее всего вебсервисы просто не учитывают тот факт что параметр может возвращаться. Может как-то переделать на использование запроса с кастомной колонкой?
Разработчики пообещали сделать сборку 3.3.0.51, где будет исправлена эта ошибка... Ждем-с-с...
--
Cogito, ergo sum
--
www.it-sfera.com.ua
Сегодня добавил для Web сервисов возможность возвращать результаты ExecuteCustomSQL через Output параметры. Обращайтесь в поддержку за сборкой 3.3.0.51.
Александр, большое спасибо!
--
Cogito, ergo sum
--
www.it-sfera.com.ua
Я так понимаю, что описанный здесь способ вернуть результат работы хранимой процедуры в версии 3.0.2.244 не предусмотрен.
Как вернуть результат?
Посмотрите здесь и дальше по комментариям - способ возвращения через SelectQuery с использованием CustomSQL-колонок. При этом в конце хранимой процедуры должен быть Select, который возвращает необходимый результат.
С уважением,
Олег Лабьяк,
инженер-программист,
группа компаний Terrasoft.
а можно подробней? не совсем понятен принцип... каким образом получить результат из сервиса SelectQuery? в конце ХП создал select, а как то что он возвращает увязать с SelectQuery?
там еще рекомендуют создать поле (Result), но как его создать, если выбор возможен только из полей таблицы из секции FROM?
Результат Вы получаете в колонки запроса. Например, если в конце ХП Вы выполняете такой запрос:
...
то в самом сервисе SelectQuery необходимо создать CustomSQL-колонки с названиями Field1, Field2, Field3. Причём в свойство "Текст SQL" первой из них Вам необходимо вставить вызов ХП:
DROP TABLE #tmp
EXEC ProcedureName :ParamName
/*
А для таблицы блока FROM сервиса запроса необходимо прописать алиас "*/--" (без двойных кавычек). Это необходимо, чтобы закомментировать остальной текст запроса.
Далее, после получения экземпляра этого SelectQuery и установки значений необходимых параметров результат выполнения ХП можно так: var Dataset = SelectQuery.Open();
Поля датасета будут содержать результат выполнения.
Что касается совета Дениса:
"в конце процедуры напишите что-то типа
select 1 as [Result]
а в SelectQuery создайте поле
Result - целого типа"
это частный случай того, что я написал выше (если хранимая процедура не возвращает ничего, "заставляем" её вернуть фиктивный результат в колонку запроса).
Именно поэтому рекомендуется создавать CustomSQL-колонки. В них не обязательно выбирать поля из таблицы блока FROM. Более того, в этом запросе абсолютно все колонки должны быть типа CustomSQL, а таблица желательно такая, которая содержит одну строку (чтобы ХП не выполнялась столько раз, сколько записей в таблице). Поэтому, поскольку таблица tbl_DatabaseInfo всегда должна содержать только одну запись, и мы не собираемся ни выбирать из неё информацию, ни выполнять над ней никаких операций, используется именно эта таблица.
Загрузите сервис из примера, и Вы увидите, что он удовлетворяет всем описанным требованиям.
С уважением,
Олег Лабьяк,
инженер-программист,
группа компаний Terrasoft.
в конце процедуры у меня такой селект:
в SelectQuery я вставил CustomSQL-поле с именем Result, в поле "Текст SQL" что-нибудь нужно писать? ибо всё вроде бы и работает, но в Result ничего не передается...
Свойство "Текст SQL" первой из колонок необходимо заполнить текстом:
DROP TABLE #tmp
EXEC ProcedureName :ParamName
/*
В Вашем случае колонка единственная - её свойство "Текст SQL" так же необходимо заполнить. Вместо ProcedureName необходимо указать название Вашей процедуры, далее, если необходимо, - входящие параметры.
С уважением,
Олег Лабьяк,
инженер-программист,
группа компаний Terrasoft.
вот вложил созданный сервис. далее текст из скрипта:
SQ_SP.Parameters.ItemsByName('ContractOldID').Value = Dataset.ValAsStr('ContractID');
SQ_SP.Parameters.ItemsByName('NewAccountID').Value = Dataset.ValAsStr('AccountToID');
SQ_SP.Parameters.ItemsByName('CertificateDate').Value = Dataset.ValAsDateTime('CertificateDate');
var DatasetResult = SQ_SP.Open();
var IDNewContract = DatasetResult.ValAsGUID('Result');
в IDNewContract возвращается пустая строка...
Попробуйте запустить профайлер перед выполнением SQ_SP.Open() и посмотреть, какой запрос он возвращает. Потом выполните этот запрос с помощью Query Analyzer или SQL Server Management Studio и посмотрите на результат, а также на значения параметров, которые передаются в процедуру. Возможно, это подскажет дальнейшее направление анализа проблемы.
С уважением,
Олег Лабьяк,
инженер-программист,
группа компаний Terrasoft.
вот что показывает профайлер:
1 AS [a] INTO #tmp
drop table #tmp
EXEC spChangeLegalPerson_AddNewContract @P1, @P2, @P3
/* AS [Result]
FROM
[tbl_DatabaseInfo] AS [*/--]',N'@P1 varchar(38),@P2 varchar(38),@P3 datetime','{461DA3E2-8F2D-488B-A175-1F17356ECFAD}','{69D74C53-113C-493A-8F1A-7C6733B58FCE}',''2010-11-03 00:00:00:000''
т.е. передается всё что нужно...
А результат выполнения этого запроса в Management Studio есть?
С уважением,
Олег Лабьяк,
инженер-программист,
группа компаний Terrasoft.
хм... вот только что-то непонятно как это передается дата... но ошибок не выдает, всё отрабатывает правильно...
да, в Result возвращается GUID...
но - в том виде в котором этот запрос был скопирован из профайлера, он не выполняется, если убрать у даты лишние кавычки, то всё проходит на ура...
Попробуйте при установке параметров использовать Values:
SQ_SP.Parameters.ItemsByName('ContractOldID').Value = Dataset.Values('ContractID');
SQ_SP.Parameters.ItemsByName('NewAccountID').Value = Dataset.Values('AccountToID');
SQ_SP.Parameters.ItemsByName('CertificateDate').Value = Dataset.Values('CertificateDate');
var DatasetResult = SQ_SP.Open();
var IDNewContract = DatasetResult.ValAsGUID('Result');
Если дата будет не в нужном формате, можно в тексте SQL колонки запроса привести её к нужному типу:
Также мне кажется, что поскольку значения параметров берутся из одного и того же датасета, достаточно будет в хранимку передавать значение поля ID, а остальные значения непосредственно получать в процедуре. Количество запросов от этого не должно измениться (тот же Select, который Вы выполняете для открытия датасета Dataset, будет выполняться в хранимой процедуре).
С уважением,
Олег Лабьяк,
инженер-программист,
группа компаний Terrasoft.
пробовал использовать Values, в профайлере запрос имеет тот же вид, но при этом выполняется без проблем... попытка привести параметр к типу datetime порождает ошибку - что-то о неправильном параметре... результат в поле Result процедура не возвращает... может и такого способа моя версия не поддерживает? а ADO позволяет это сделать?
Да, ADO должен позволять даже в 3.0.2.
Но возможно, быстрее будет переписать хранимую процедуру, как я писал выше:
Насколько я понимаю, проблема только в параметре типа datetime, а с параметром ID типа uniqueidentifier проблем возникнуть не должно.
С уважением,
Олег Лабьяк,
инженер-программист,
группа компаний Terrasoft.
проблем с datetime нет, проблема с возвратом уникального идентификатора. прийдется формировать его на стороне клиента и передавать в процедуру, а это не есть хорошо...
Можете выложить текст процедуры?
С уважением,
Олег Лабьяк,
инженер-программист,
группа компаний Terrasoft.
(
@ContractOldID uniqueidentifier,
@NewAccountID uniqueidentifier,
@CreateByID uniqueidentifier,
@CertificateDate datetime
)
AS
declare @TableName varchar(128)
declare @FieldName varchar(128)
declare @StrSelectSQL varchar(4096)
declare @StrInsertSQL_Fields varchar(4096)
declare @StrInsertSQL_Values varchar(4096)
declare @ContractNewID uniqueidentifier
BEGIN
SET @ContractNewID = newid()
exec dbo.spCreateInsert 'tbl_Contract', @ContractOldID, @ContractNewID, @NewAccountID, @CertificateDate, @CreateByID, @StrInsertSQL_Fields output
execute (@StrInsertSQL_Fields)
exec dbo.spCreateInsert 'tbl_ContractRight', @ContractOldID, @ContractNewID, @NewAccountID, @CertificateDate, @CreateByID, @StrInsertSQL_Fields output
execute (@StrInsertSQL_Fields)
declare CurTable cursor FOR
SELECT so.name FROM dbo.sysobjects so
INNER JOIN INFORMATION_SCHEMA.COLUMNS ic ON so.name = ic.table_name
WHERE so.xtype = 'U' AND so.name LIKE 'tbl_%' AND ic.column_name = 'ContractID'
ORDER BY so.name
open CurTable
fetch next FROM CurTable INTO @TableName
while (@@fetch_status = 0)
begin
print @TableName
IF (@TableName = 'tbl_working')
begin
fetch next FROM CurTable INTO @TableName
continue
end
print @StrInsertSQL_Fields
exec dbo.spCreateInsert @TableName, @ContractOldID, @ContractNewID, @NewAccountID, @CreateByID, @CertificateDate, @CreateByID, @StrInsertSQL_Fields output
IF (@StrInsertSQL_Fields IS NOT NULL)
begin
execute (@StrInsertSQL_Fields)
end
fetch next FROM CurTable INTO @TableName
end
close CurTable
deallocate CurTable
SELECT @ContractNewID AS Result
END
Мне кажется, принципиальной разницы не будет, формируется ли значение @ContractNewID внутри процедуры или формируется в конфигурации с помощью Connector.GenGUID() и передаётся в качестве параметра.
Насколько я понял, значение @ContractNewID внутри процедуры генерируется только один раз, и больше нигде не меняется. Я попробовал воспроизвести, используя Ваш запрос и оставив в теле процедуры только строки
SELECT @ContractNewID AS Result
Результат возвращался корректно. Проверял на версии 3.0.2.231. Почему не работает у Вас - пока версий нет.
Кстати, заметил, что выложенная Вами процедура требует 4 входящих параметра. Вы учли это в Вашем запросе?
Также попробуйте в тексте процедуры взять Result в квадратные скобки или заменить на другой алиас в процедуре и запросе.
С уважением,
Олег Лабьяк,
инженер-программист,
группа компаний Terrasoft.
да, конечно же все параметры передаются и процедура отрабатывает правильно. попробую скобки и другой алиас...
Приходится поднимать тему в связи с переходом на SQL2008.
DROP TABLE #tmp
EXEC ProcedureName :ParamName
/*
при попытке выполнить метод Open() появляется ошибка о том, что комментарий должен быть завершен... вероятно побороть это нельзя?
Тогда каким образом можно вернуть значение из ХП в версии 3.0.2.244?
У Вас точно алиас таблицы в блоке FROM такой: */-- ?
С уважением,
Олег Лабьяк,
инженер-программист,
группа компаний Terrasoft.
извиняюсь, не доглядел... СПСБ...
только значение не возвращается всё равно, точнее возвращается NULL, хотя я точно знаю, что должна быть осмысленная строка... если запрос из профайлера выполнить в студии, то значение есть, но оно не попадает в датасет...
ХП:
@IDBalSys integer
AS
BEGIN
declare @StatusAccount varchar(250)
execute ('BEGIN SRVC.SERVICES_PKG.GETCLIENTSTATUSCRM(?,?); END;', @IDBalSys, @StatusAccount output) AT DEVELOPER;
SELECT @StatusAccount
END
скрипт:
SelectQuery.Parameters.ItemsByName('IDBalSys').Value = IDBalSys;
var DatasetResult = SelectQuery.Open();
var StatusAccount = DatasetResult.Values('StatusAccount');
в прицепе файл сервиса...
Думаю, для решения проблемы необходимо изменить последнюю строку хранимой процедуры следующим образом:
Дело в том, что процедура в том виде, в котором она есть сейчас, возвращает результат в колонку с неопределённым именем. А Вам необходимо получить результат из колонки "StatusAccount".
С уважением,
Олег Лабьяк,
инженер-программист,
группа компаний Terrasoft.
СПСБ!
Здравствуйте!
Есть хранимая процедура, которая возвращает запрос (4 поля).
Подскажите, пожалуйста, каким образом их все вывести?
Вероятно должно быть так: одно поле должно быть создано, как описано в сообщениях 28 и 29, а остальные должны быть просто созданы, а вот в ХП, в результирующем запросе все 4 поля должны быть описаны, как в сообщении 31, т.е. каждому полю должен соответствовать псевдоним в точности повторяющий название поля в сервисе...
Здравствуйте, Марина.
В хранимой процедуре Вам нужно создать четыре исходящих параметра, присвоить им значения результатом запроса, и далее в коде создать четыре исходящих параметра, запустить хранимую процедуру, и считать их значения.
Приблизительный код:
(хранимая процедура)
@isEnought1 [uniqueidentifier] output,
@isEnought2 [varchar](250) output,
@isEnought3 [varchar](250) output,
@isEnought4 [uniqueidentifier]output
AS
BEGIN
SET @isEnought1 = (SELECT ID FROM tbl_Account WHERE ID = '{5F982A3D-0AAC-4306-8DBF-5F2327987615}')
SET @isEnought2 = (SELECT Name FROM tbl_Account WHERE ID = '{5F982A3D-0AAC-4306-8DBF-5F2327987615}')
SET @isEnought3 = (SELECT OfficialAccountName FROM tbl_Account WHERE ID = '{5F982A3D-0AAC-4306-8DBF-5F2327987615}')
SET @isEnought4 = (SELECT OwnerID FROM tbl_Account WHERE ID = '{5F982A3D-0AAC-4306-8DBF-5F2327987615}')
END
GO
(код скрипта)
{
var Parameters = CreateSPParameters();
CreateSPParameter(Parameters, 'isEnought1', pdtGUID, 0);
CreateSPParameter(Parameters, 'isEnought2', pdtString, 0);
CreateSPParameter(Parameters, 'isEnought3', pdtString, 0);
CreateSPParameter(Parameters, 'isEnought4', pdtGUID, 0);
Parameters.ItemsByName('isEnought1').ParamType = 1; // It!
Parameters.ItemsByName('isEnought2').ParamType = 1; // It!
Parameters.ItemsByName('isEnought3').ParamType = 1; // It!
Parameters.ItemsByName('isEnought4').ParamType = 1; // It!
var SQLText = 'exec dbo.tspTest3 :isEnought1 OUTPUT, :isEnought2 OUTPUT, :isEnought3 OUTPUT, :isEnought4 OUTPUT';
Connector.DBEngine.ExecuteCustomSQL(SQLText, Parameters);
var IsEnought1 = Parameters.ItemsByName('isEnought1').Value;
var IsEnought2 = Parameters.ItemsByName('isEnought2').Value;
var IsEnought3 = Parameters.ItemsByName('isEnought3').Value;
var IsEnought4 = Parameters.ItemsByName('isEnought4').Value;
}
С уважением,
Олейник Дмитрий
Эксперт 3-й линии поддержки
Спасибо! Получилось