Добрый вечер, возникла задача:

Нужно отфильтровывать SQL-запрос и создавать из него xlsx отчёт.

Фильтрация реализована с помощью хранимой процедуры, в которую из БП передаются значения, выбранные пользователем, но выгрузка в xlsx с помощью ExportToExcel выгружает только esq.

Можно ли как-нибудь перевести StoredProcedure в ESQ? Если нет, то как выгрузить StoredProcedure в xlsx?

 

Нравится

3 комментария

Добрый вечер.

 

Для этой задачи Вам нужно использовать не хранимую процедуру, а хранимую функцию, которая будет возвращать таблицу.

 

На сторонних ресурсах есть много статей, где подробно описано реализацию такой функции, например, вот одна из них Хранимые функции.

Алла Савельева,

Спасибо. Не подскажите, а как потом хранимую функцию вызвать в БП и передать в esq?

Вашу хранимую процедуру можно реализовать сразу на ESQ, не нужно делать никаких процедур, которые только усложняют жизнь.

И стандартными механизмами работать дальше с ESQ.

Показать все комментарии

Доброго времени суток, коллеги.
Клиент TerrasoftCRM 3.3.2.245
Такая проблема: на основании данного форума я сделал сервис SelectQuery:

SELECT
        1 AS [a] INTO #tmp
DROP TABLE #tmp

EXEC GetMissingDocuments
/*  AS [FakeHeader],
         AS [DocNumber],
         AS [TaskID],
        */

IF 1=0
SELECT 1 AS [FakeFooter]
FROM
        [dbo].[tbl_DatabaseInfo] AS [tbl_DatabaseInfo]

и вызывал через него хранимую процедуру. Вызывал так:
[js]
var SelectQuery = GetSingleItemByCode('sq_GetMissingDocuments', 'GetMissingDocumentsTasks');
var Result = SelectQuery.Open();
[/js]
Пока база работала на MS SQL Server 2005 все было нормально. После перехода на SQL Server 2008 R2 при вызове SelectQuery.Open() получаю ошибку "Ошибка открытия источника данных "".
Оригинальное сообщение об ошибке: Неопознанная ошибка". Причем если выполнить этот запрос в SSMS, то он выполняется корректно. В SQL Server Profiler ошибок тоже нет. На клиентском компьютере установлена версия SQL Native Client 2008 R2. Куда еще можно копнуть?

Нравится

5 комментариев

Можно переделать логику чисто на скрипт, без сервиса. Как тут.

"Зверев Александр" написал:Можно переделать логику чисто на скрипт, без сервиса.

Моя хранимая процедура возвращает таблицу. Ее можно завернуть в выходной параметр хранимой процедуры?

Можно процедуру в функцию переделать, с функциями в 2008 проблем не было. Также см. обсуждение, там тоже под новую версию переделывали.

"Зверев Александр" написал:Можно процедуру в функцию переделать

Попробую конечно, но все равно не понятно. У меня в базе есть еще одна аналогичная конструкция. Отличается тем, что ХП в ней получает параметры и результат достается через Dataset и отображается на форме. И она прекрасно работает.

Подобные способы использования что процедуры, что функции являются «хаком» и обходом стандартного поведения сервиса sq, их работа всегда и везде не гарантируется. Возможно, в 2008 что-то изменилось в движке работы с БД.

"Riptor" написал:И она прекрасно работает.

Это хорошо.:cool:

Показать все комментарии

Добрый день!
В разделе создано действие, при нажатии на которое запускается бизнес-процесс.
Смысл бизнес-процесса состоит в том, что в нем необходимо вызвать хранимую процедуру.
Т.е. бизнес-процесс состоит из трех элементов:
начальное простое событие
задание-сценарий
завершающее событие.

Вопросы:
1) как правильно вызвать хранимую процедуру
StoredProcedure storedProcedure = new StoredProcedure(UserConnection, "tsp_test") as StoredProcedure;
storedProcedure.PackageName = UserConnection.DBEngine.SystemPackageName;
storedProcedure.Execute();
return true;

подобный скрипт вызывает ошибки синтаксиса..
как правильно оформить вызов хранимой процедуры

2) как правильно передавать параметры входящие в процедуру(вызывать процедуру с параметрами)
и как правильно получить исходящие параметры хранимой процедуры

3) как правильно передавать в скрипте параметры БП во входящие параметры хранимой процедуры

4) где можно в конфигурации стандартной посмотреть вызов хранимой процедуры ( у вас есть несколько хранимых процедур в конфигурации, где можно посмотреть вызов и использование хотя бы одной из них)

Нравится

13 комментариев

Добрый день, Дарья!

1) Правильный вызов процедуры (пример):

DataValueTypeManager dataValueTypeManager = UserConnection.DataValueTypeManager; 
var dateTimeValue = new DateTime(2009, 01, 02, 22, 12, 0);
                    Stream stream = new MemoryStream(Encoding.Unicode.GetBytes("Тест большого бинарного объекта"));
                    var textDataValueType = new TextDataValueType(dataValueTypeManager);
                    var guidDataValueType = new GuidDataValueType(dataValueTypeManager);
                    var integerDataValueType = new IntegerDataValueType(dataValueTypeManager);
                    var floatDataValueType = new Float2DataValueType(dataValueTypeManager);
                    var booleanDataValueType = new BooleanDataValueType(dataValueTypeManager);
                    var dateTimeDataValueType = new DateTimeDataValueType(dataValueTypeManager);
                    var idValue = new Guid("{BCDB8392-55BC-472A-A49D-22A975E0BEF6}");
 
                    StoredProcedure storedProcedure =
                           new StoredProcedure(Page.UserConnection, "tsp_TestStoredProcedure")
                           .WithParameter("IdParameter", idValue)
                           .WithVarParameter("VarIdParameter", idValue, guidDataValueType)
                           .WithParameter("TextParameter", "Украина")
                           .WithVarParameter("VarTextParameter", "Украина", textDataValueType)
                           .WithParameter("IntegerParameter", 10)
                           .WithVarParameter("VarIntegerParameter", 10, integerDataValueType)
                           .WithParameter("FloatParameter", 3.14)
                           .WithVarParameter("VarFloatParameter", 3.14, floatDataValueType)
                           .WithParameter("BooleanParameter", true)
                           .WithVarParameter("VarBooleanParameter", false, booleanDataValueType)
                           .WithParameter("DateTimeParameter", dateTimeValue)
                           .WithVarParameter("VarDateTimeParameter", dateTimeValue, dateTimeDataValueType)
                           .WithParameter("BinaryParameter", stream)
                           .WithVarParameter("VarBinaryParameter", stream)
                           .WithOutputParameter("ResultParameter", textDataValueType) as StoredProcedure;
storedProcedure.PackageName = Page.UserConnection.DBEngine.SystemPackageName;
storedProcedure.Execute();

2. Исходящий параметр .WithOutputParameter
3. Передача параметров в хранимую процедуру описана в первом пункте.
4. Вызов хранимой процедуры, Вы можете посмотреть в BaseAdministrativeGridPage

Спасибо.

по поводу пункта № 1- как правильно вызвать процедуру.

) Вызываю по аналогии в сценарии в БП
(процедура пока без параметров)

StoredProcedure storedProcedure = new StoredProcedure(UserConnection, "tsp_test") as StoredProcedure;
storedProcedure.PackageName = UserConnection.DBEngine.SystemPackageName;
storedProcedure.Execute();
return true;

Выходит ошибка при публикации (см. вложение).
Что не так?

2) по поводу пункта № 3 - не поняла.
Как передать просто параметры входящие - понятно.
Но как в скрипте правильно обратить к параметру бизнес-процесса, чтобы его уже значение передать в параметр хранимой процедуры ?

3) где именно искать вызов хранимой процедуры в BaseAdministrativeGridPage?

1. Код помещенный в БП в ScriptTask:

StoredProcedure storedProcedure = new StoredProcedure(UserConnection, "tsp_test") as StoredProcedure;
storedProcedure.PackageName = UserConnection.DBEngine.SystemPackageName;
storedProcedure.Execute();
return true;
не вызывает ошибки компиляции. Возможно у Вас есть еще какой-то код, который приводит к ошибке?

2. По имени параметра
var temp = ProcessSchemaParameter1

3. Поиском в исходных кодах
Открыть схему. Кнопка «Дополнительно» пункт меню «Открыть исходный код»

Спасибо, я посмотрю

Применение конструкции
.WithOutputParameter("ResultParameter", textDataValueType)
позволяет вызвать процедуру с исходящими параметрами.

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

Добрый день, Дарья!
Вы можете обратиться к значению, используя следующий пример кода:

var resultParameter = (string) storedProcedure.Parameters.FindByName("ResultParameter ").Value;

Добрый день еще раз!
Пытаюсь опять вызвать процедуру согласно инструкции (в БП в задании-сценарии)

DataValueTypeManager dataValueTypeManager = UserConnection.DataValueTypeManager;
var textDataValueType = new TextDataValueType(dataValueTypeManager);

StoredProcedure storedProcedure = new StoredProcedure(UserConnection, "tsp_test")
.WithOutputParameter("res_msg",textDataValueType) as StoredProcedure;

storedProcedure.PackageName = UserConnection.DBEngine.SystemPackageName;
storedProcedure.Execute();
return true;

Текст процедуры выглядит так:

CREATE procedure [dbo].[tsp_test]
as declare @res_msg nvarchar(250);
select @res_msg='1'
select @res_msg as res_msg

Процесс компилируется, но при запуске процесса элемент сценарий завершается с ошибкой

"System.Data.SqlClient.SqlException (0x80131904): Процедуре tsp_test не переданы параметры и аргументы"

О каких параметрах и аргументах может идти речь, если у процедуры этой нет вовсе входящих параметров, которые можно было бы передать?

Причем если вызвать процедуру без исходящего параметра
StoredProcedure storedProcedure = new StoredProcedure(UserConnection, "tsp_test")
as StoredProcedure;

то такой ошибки нет, сценарий выполняется.

Что-то не так с получением исходящего параметра процедуры?

Поняла в чем дело:
чтобы использовать конструкцию .WithOutputParameter("ResultParameter", textDataValueType) as StoredProcedure в скрипте,
необходимо в тексте самой процедуры прописывать параметр как OUTPUT:

CREATE procedure [dbo].[tsp_test]
(@res_msg nvarchar(250) OUTPUT)
as
select @res_msg='1'
select @res_msg as res_msg
return @res_msg

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

OUT | OUTPUT
Показывает, что параметр процедуры является выходным. Используйте параметры OUTPUT для возврата значений в вызвавший процедуру код.
В.Использование выходных параметров (OUTPUT)
В следующем примере создается процедура uspGetList. Эта процедура возвращает список товаров, цена на которые не превышает указанный предел. Данный пример поясняет использование нескольких инструкций SELECT и нескольких параметров OUTPUT. Параметры OUTPUT предоставляют внешней процедуре, пакету или нескольким инструкциям Transact-SQL доступ к значениям, заданным во время выполнения процедуры.

IF OBJECT_ID ( 'Production.uspGetList', 'P' ) IS NOT NULL 
    DROP PROCEDURE Production.uspGetList;
GO
CREATE PROCEDURE Production.uspGetList @Product varchar(40) 
    , @MaxPrice money 
    , @ComparePrice money OUTPUT
    , @ListPrice money OUT
AS
    SET NOCOUNT ON;
    SELECT p.[Name] AS Product, p.ListPrice AS 'List Price'
    FROM Production.Product AS p
    JOIN Production.ProductSubcategory AS s 
      ON p.ProductSubcategoryID = s.ProductSubcategoryID
    WHERE s.[Name] LIKE @Product AND p.ListPrice < @MaxPrice;
-- Populate the output variable @ListPprice.
SET @ListPrice = (SELECT MAX(p.ListPrice)
        FROM Production.Product AS p
        JOIN  Production.ProductSubcategory AS s 
          ON p.ProductSubcategoryID = s.ProductSubcategoryID
        WHERE s.[Name] LIKE @Product AND p.ListPrice < @MaxPrice);
-- Populate the output variable @compareprice.
SET @ComparePrice = @MaxPrice;
GO

Источник: https://msdn.microsoft.com/ru-ru/library/ms187926.aspx#Parameters

Спасибо, но вопрос не в этом заключался. Процедура, которую вы привели, просто возвращает два параметра выходных, а не выборку данных
А меня интересовало получение результатов выполнения процедуры в скрипте в bpmonline.
Например, процедура возвращает результат выполнения запроса select * from tbl_city
(это просто пример, выборка может быть сложнее), интересовало получение результата выполнения процедуры в bpmonline.
Но, наверное, мой вопрос уже не связан с темой бизнес-процессов - озвучу его в другой теме.
Спасибо

Добрый день, Дарья!

Для получения результата запроса из процедуры необходимо в процессе добавить в Usings:
Пространство имен: System.Data.IDataReader
Псевдоним: IDataReader

Вызов процедуры:

StoredProcedure storedProcedure = new StoredProcedure(UserConnection, "Test") as StoredProcedure;
storedProcedure.PackageName = UserConnection.DBEngine.SystemPackageName;
using (var dbExecutor = UserConnection.EnsureDBConnection()) {
            using (IDataReader dataReader = storedProcedure.ExecuteReader(dbExecutor)) {
                        while (dataReader.Read()) {
                                   var valueColumn1 = dataReader.GetValue(0);
                                   var operation = dataReader.GetColumnValue<int>("Operation");
                        }
            }
}
Показать все комментарии

Доброго времени суток, коллеги. При интеграции BPM с внешней БД возникла необходимость вставлять даннные из карточки BPM в таблицу на связанном сервере (Firebird 2.0). Для работы с таблицами связанного сервера содали представления. С селектами из этих представлений никаких проблем не было. Но вот с инсертами и апдейтами возникла проблемка - после инсерта(апдейта или делита) транзакции подвисали минут на 5 и выполнить очередной запрос к этому представлению было невозможно.
Нашли выход из этой ситуевины:
1. Создали на связанном сервере хранимую процедуру (пишет данные в таблицу и возвращает одно значение).
2. На sql сервере в представлении создали триггер который срабатывает на инсерт, пинает хранимку на связанном сервере и передает параметры в эту хранимку.
3. В карточку BPM добавили кнопку и повесили на нее скрипт которые инсертит данные из полей карточки в представление.
После данные манипуляций все работает отлично, данные инсертятся, транзакции не подвисают.

Но вот возник вопросик. Как я написал в первом пункте, хранимка возвращает одно значение и мы не можем приложить ума как его перехватить чтобы вернуть это значение в текстовое поле в карточку BPM. Ниже код хранимки, триггера и скрипта инсерта.

Код хранимки.

BEGIN

INSERT INTO NAPRAVLENIE(NAPRAVLENIE.NAPRAVLENIE_NUM,NAPRAVLENIE.USLUGA_1) VALUES (:NUM,:U1);
NEW_OUTPARAM=gen_id(BP_GEN,1);

  SUSPEND;
END

Код триггера.

USE [BPMonline]
GO
/****** Object:  Trigger [dbo].[IOI_napr]    Script Date: 03/11/2015 17:56:44 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[IOI_napr]ON [dbo].[napr]
INSTEAD OF INSERT
AS
BEGIN
declare @U1 varchar(250)
declare @NUM varchar (250)
declare @NAP_NUM varchar (250)
SET @U1=(SELECT i.USLUGA_1 FROM inserted i)
SET @NUM=(SELECT i.NAPRAVLENIE_NUM FROM inserted i)
execute ('select * from BP_nap_ins('''+@NUM+''','''+@U1+''')') at DMS
 
END;

Код скрипта инсерта кнопки.

var U1=Page.TextEdit5.Value; // для теста передаем только 1 значение
var insert = new Insert(UserConnection).Into("napr").Set("USLUGA_1", Column.Parameter(U1)).Execute();
        return true;

если вы полнить инсерт из sql менеджера то в результах я вижу, что хранимка вернула значение.

каким оброзом можно запихнуть возвращаемое значение в переменную и использовать ее дальше в BPM ?
Спасибо что дочитали :)

Нравится

25 комментариев

если в скрипт кнопки добавить

Page.TextEdit14.SetValue(insert);

то в TextEdit14 пишется 1 (единица), но передоваемое значение не равно 1.

Попробуйте указанный код, вместо Insert

var selectSQL = new CustomQuery(UserConnection, sqlText);
using (var dbExecutor = UserConnection.EnsureDBConnection()) {
	using(var dr = selectSQL.ExecuteReader(dbExecutor)) {
		while (dr.Read()) {
			PreviousMonth = dr.GetValue(0).ToString();
		}
	}
}

Спасибо за ответ, пошли немного другим путем. Запихнули текст триггера еще в одну хранимку, и через OPENQUERY пнули хранимку на связанном сервере. Таким макаром удалось вернуть значение в переменную. Сейчас бытаюсь разобраться как вызвать хранимку из формы.

может кому не сложно написать коды вызова хранимки:

в хранимку передаем значение из поля TextEdit5.
вернуть значение нужно в TextEdit14

почитал немного тут http://www.community.terrasoft.ru/blogs/7708

вот, что наваял:

var U1=Page.TextEdit5.Value;
//var NAP_NUM = null;
var dataValueTypeManager = (DataValueTypeManager)UserConnection.AppManagerProvider.GetManager("DataValueTypeManager");
var proc = new StoredProcedure(UserConnection, "BNS_to_DMS");
StoredProcedure.WithParameter(U1);
StoredProcedure.WithOutputParameter("NAP_NUM", dataValueTypeManager.GetInstanceByName("Text"));
using (DBExecutor dbExecutor = UserConnection.EnsureDBConnection()) {
        dbExecutor.StartTransaction(System.Data.IsolationLevel.ReadUncommitted);
        Page.DataSource.ActiveRow.Save();
        StoredProcedure.Execute(dbExecutor);}
SetCloseStatus(1);
//Connector.DBEngine.ExecuteCustomSQL(SQLText);
//var insert = new Insert(UserConnection).Into("napr").Set("USLUGA_1", Column.Parameter(U1)).Execute();
 	Page.TextEdit14.SetValue(NAP_NUM);
	return true;

но валится много ошибок при компиляции.

PS: извиняйте что туплю, я не программист

код хранимки

USE BPMonline;
IF OBJECT_ID ( 'dbo.BPM_to_DMS', 'P' ) IS NOT NULL 
    DROP PROCEDURE dbo.BPM_to_DMS;
GO
CREATE PROCEDURE dbo.BPM_to_DMS
    @U1 varchar(250),
    @NAP_NUM varchar (250) OUTPUT
    --@U2 varchar (250) 
  AS 
 
    SET NOCOUNT ON;
 
 set @NAP_NUM = (select * from OPENQUERY (dms,'select * from BP_nap_ins(''+@U1+'')'))
 
 GO

итак, удалось запустить хранимку, передать ей значение в U1, но никак не могу разобраться как вернуть из нее значение в TextEdit14. необходимое значение возвращается в NAP_NUM.

код вызова хранимки:

var U1=Page.TextEdit5.Value;
//var NAP_NUM;
var dataValueTypeManager = (DataValueTypeManager)UserConnection.AppManagerProvider.GetManager("DataValueTypeManager");
var storedProcedure = new StoredProcedure(UserConnection, "BPM_to_DMS");
storedProcedure.WithParameter(U1);
storedProcedure.WithOutputParameter("NAP_NUM", dataValueTypeManager.GetInstanceByName("Text"));
using (DBExecutor dbExecutor = UserConnection.EnsureDBConnection()) {
        dbExecutor.StartTransaction(System.Data.IsolationLevel.ReadUncommitted);
        storedProcedure.Execute(dbExecutor);
				dbExecutor.CommitTransaction();
}
 
 	//Page.TextEdit14.SetValue(NAP_NUM);
	return true;

можно хотябы пример похожий (в примере с поиском дублей ничего не понятно)

PS: когда все допилю обещаю написать полный мануал по вызову хранимой процедуры на связанном сервере firebird 2.0

Добрый день. А почему Вы не используете тот пример, что я вам скинул? Им тоже можна "дергать" хранимые процедуры и получать значения

"Олейников Владимир Владимирович" написал:

Добрый день. А почему Вы не используете тот пример, что я вам скинул? Им тоже можна "дергать" хранимые процедуры и получать значения


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

там все очень просто. UserConnection - Переменная которая хранит в себе параметры подключения.
sqlText - сюда можно запихнуть любой SQL запрос, в том числе и вызов хранимой процедуры.

while (dr.Read()) {
PreviousMonth = dr.GetValue(0).ToString();
}

"dr" - сохраняет в себе структуру возвращенных данных

"Олейников Владимир Владимирович" написал:

там все очень просто. UserConnection - Переменная которая хранит в себе параметры подключения.

sqlText - сюда можно запихнуть любой SQL запрос, в том числе и вызов хранимой процедуры.

while (dr.Read()) {

PreviousMonth = dr.GetValue(0).ToString();

}

"dr" - сохраняет в себе структуру возвращенных данных


спасибо, будем пробовать

а как таким сполобом передать значение в хранимку?
тоеть я должен передать в хранимую процедуру куча значений и вернуть из нее одно.

забал сказать что хранимка возвращает не просто число, а текст, по сути номер направления ( пример 15326/2015)

"Олейников Владимир Владимирович" написал:

там все очень просто. UserConnection - Переменная которая хранит в себе параметры подключения.

sqlText - сюда можно запихнуть любой SQL запрос, в том числе и вызов хранимой процедуры.

while (dr.Read()) {

PreviousMonth = dr.GetValue(0).ToString();

}

"dr" - сохраняет в себе структуру возвращенных данных

Владимир, ругается на PreviousMonth,

The name 'PreviousMonth' does not exist in the current context
DMSEditPage.cs
2918

PreviousMonth - это локальная переменная, которая создается и туда записывается значение. Можете вместо этого кода вписать
следующий код
Page.TextEdit14.SetValue(dr.GetValue(0).ToString());
только вместо "0" подставте нужный индекс. Посмотрите какой он по счету в выборке в запросе

"Олейников Владимир Владимирович" написал:

PreviousMonth - это локальная переменная, которая создается и туда записывается значение. Можете вместо этого кода вписать

следующий код

Page.TextEdit14.SetValue(dr.GetValue(0).ToString());

только вместо "0" подставте нужный индекс. Посмотрите какой он по счету в выборке в запросе


Владимир, попробовал подставить Page.TextEdit14.SetValue(dr.GetValue(0).ToString());

скрипт отрабатывает но в TextEdit14 ничего не возвращает(пробовал разные индексы(0 1 2), а вообще запись по счету первая).

вот текст скрипта, вашим методом я так и не разобралмя как вызвать хранимку с передачей в нее параметров.

var U1=Page.TextEdit5.Value;
//var result = 5;
var dataValueTypeManager = (DataValueTypeManager)UserConnection.AppManagerProvider.GetManager("DataValueTypeManager");
var storedProcedure = new StoredProcedure(UserConnection, "BPM_to_DMS");
storedProcedure.WithParameter(U1);
storedProcedure.WithOutputParameter("NAP_NUM", dataValueTypeManager.GetInstanceByName("Text"));
using (var dbExecutor = UserConnection.EnsureDBConnection()) {
        dbExecutor.StartTransaction(System.Data.IsolationLevel.ReadUncommitted);
       // storedProcedure.Execute(dbExecutor);
	{
        using(var dr =storedProcedure.ExecuteReader(dbExecutor)) {
                while (dr.Read()) {
                     Page.TextEdit14.SetValue(dr.GetValue(0).ToString());
 
                }
        }
}
			dbExecutor.CommitTransaction();
 
}
 
 
	return true;

Профайлер перехватывает выполнение и показывает что в @NAP_NUM вернулось нужное значение

Попробуйте в дебаге посмотреть что вам возвращает переменная "dr" и все увидите

var dataValueTypeManager = (DataValueTypeManager)UserConnection.AppManagerProvider.GetManager("DataValueTypeManager");
var proc = new StoredProcedure(UserConnection, "BNS_to_DMS");
StoredProcedure.WithParameter(U1);
StoredProcedure.WithOutputParameter("NAP_NUM", dataValueTypeManager.GetInstanceByName("Text"));
using (DBExecutor dbExecutor = UserConnection.EnsureDBConnection()) {
        dbExecutor.StartTransaction(System.Data.IsolationLevel.ReadUncommitted);
        Page.DataSource.ActiveRow.Save();
        StoredProcedure.Execute(dbExecutor);}
SetCloseStatus(1);
//Connector.DBEngine.ExecuteCustomSQL(SQLText);
//var insert = new Insert(UserConnection).Into("napr").Set("USLUGA_1", Column.Parameter(U1)).Execute();
        Page.TextEdit14.SetValue(NAP_NUM);
        return true;

Вместо этого кода напишите мой

"Олейников Владимир Владимирович" написал:

var dataValueTypeManager = (DataValueTypeManager)UserConnection.AppManagerProvider.GetManager("DataValueTypeManager");

var proc = new StoredProcedure(UserConnection, "BNS_to_DMS");

StoredProcedure.WithParameter(U1);

StoredProcedure.WithOutputParameter("NAP_NUM", dataValueTypeManager.GetInstanceByName("Text"));

using (DBExecutor dbExecutor = UserConnection.EnsureDBConnection()) {

        dbExecutor.StartTransaction(System.Data.IsolationLevel.ReadUncommitted);

        Page.DataSource.ActiveRow.Save();

        StoredProcedure.Execute(dbExecutor);}

SetCloseStatus(1);

//Connector.DBEngine.ExecuteCustomSQL(SQLText);

//var insert = new Insert(UserConnection).Into("napr").Set("USLUGA_1", Column.Parameter(U1)).Execute();

        Page.TextEdit14.SetValue(NAP_NUM);

        return true;

Вместо этого кода напишите мой


Владимир, простите что туплю, но я не знаю как через ваш код вызвать хранимку и передать в нее параметр, межете пример привести? если не сложно

вот что выдает дебагер

var sqlText = string.Format("ProcName {0},{1}", "value1", "value2")

Объявляем переменную, в которой хранится вызов хранимой процедуры с переметрами "value1", "value2"

var selectSQL = new CustomQuery(UserConnection, sqlText);
using (var dbExecutor = UserConnection.EnsureDBConnection()) {
        using(var dr = selectSQL.ExecuteReader(dbExecutor)) {
                while (dr.Read()) {
                        PreviousMonth = dr.GetValue(0).ToString();
                }
        }
}

хранимая процедура вызывается как и любая SQL функция здесь

"Олейников Владимир Владимирович" написал:

хранимая процедура вызывается как и любая SQL функция здесь


спасибо за ответ, вот что вышло,

var U1=Page.TextEdit5.Value;
var Proc = string.Format("BPM_TO_DMS {0},{1}", "U1", "NAP_NUM");
	var selectSQL = new CustomQuery(UserConnection, Proc);
using (var dbExecutor = UserConnection.EnsureDBConnection()) {
        using(var dr = selectSQL.ExecuteReader(dbExecutor)) {
                while (dr.Read()) {
                        Page.TextEdit14.SetValue(dr.GetValue(1).ToString());
                }
        }
}
return true;

но при выполнении ничего не происходит, дебагер выдал все переменные по null, профайлер вы дал просто строку "BPM_TO_DMS U1,NAP_NUM" куда копать?

var Proc = string.Format("BPM_TO_DMS {0},{1}", "U1", "NAP_NUM");

Вы не коректно написали, UI Надо писать без кавычек, это имя переменной, в которой хранится значение передаваемой в хранимку переменной.

"Олейников Владимир Владимирович" написал:

Вы не коректно написали, UI Надо писать без кавычек, это имя переменной, в которой хранится значение передаваемой в хранимку переменной.


Владимир, если написать таким образом то просит объявить переменную NAP_NUM, если ее объявить то просит записать туда какаое-нить значение. Если передать туда 2 значения то процедура не срабатывает т.к. в процедуре ожидается 1 параметр входящий и 1 исходящий, а таким образом мы передаем туда 2 входящих. Может подскажите каким образом обявить NAP_NUM исходящим параметром? Спасибо.

В качестве параметров я привел пример. Вы можете их вообще туда не передавать, или передать сколько угодна. Вы передайте, те переметры, что Вам надо

var Proc = string.Format("BPM_TO_DMS {0},{1} ...", "U1", "NAP_NUM", ...);

"Олейников Владимир Владимирович" написал:

В качестве параметров я привел пример. Вы можете их вообще туда не передавать, или передать сколько угодна. Вы передайте, те переметры, что Вам надо

var Proc = string.Format("BPM_TO_DMS {0},{1} ...", "U1", "NAP_NUM", ...);


Владимир, это я понял, но мне нужно передать в хранимку 1 параметр, и хранимка должна вернуть 1 параметр. для этого в хранимке объявлен переменная NAP_NUM OUTPUT (в которую возвращается результат работы хранимки). елси вызывать хранимку через var proc = new StoredProcedure то там можно указать какой из параметров входящий а какой выходящий. Может вы подскажете каким образом в вашем скрипте указать что NAP_NUM это OUTPUT параметр? спасибо за помощь

В конце хранимки сделать выборку нужного вам параметра

DECLARE @d INT = 0
-- Какие-то действия с переменной
SELECT  @d
Показать все комментарии

Добрый день!
Задача: Есть хранимая процедура tsp_MakeMeHappy которая формирует таблицу за 18 секунд, в клиенте нужно отобразить ProgressBar с отображением процесса (т.е палочки в ProgressBar должны бегать).
Для решения задачи предложен следующий код:

            var ProgressCaptionMessage = "Формирование таблицы для счастья";    
            var Caption = 'Формирование таблицы для счастья';
        var Prompt = '';
        var WithCancel = false;
        var ShowModal = false;

        var ProgressWindow = BeginProcessingProgress(Self, Caption, Prompt,WithCancel, ShowModal);
        ControlPaySectionWorkspace.ProgressWindow = ProgressWindow;
        SetAttribute(ProgressWindow, 'NotifyObject', Self);
                InternalSetCaptionForProcessingProgress(ProgressWindow, Self, ProgressCaptionMessage);

        var Parameters = CreateSPParameters();
        var SQLText = 'exec [dbo].[tsp_MakeMeHappy]';
        Connector.DBEngine.ExecuteCustomSQL(SQLText, Parameters);
       
                var     Complete = 100;
                MoveProcessingProgress(ProgressWindow, Complete, WithCancel);  
                EndProcessingProgress(ProgressWindow, WithCancel);     

Проблема в том, что на строчке Connector.DBEngine.ExecuteCustomSQL(SQLText, Parameters); мы уходим в SQL Server на 18 секунд, и никак не можем отобразить процесс работы в ProgressBar. Так как сколько будет выполняться процедура в общем случае не понятно, но хотелось бы отобразить процесс работы, именно в ProgressBar. Я понимаю что для отображения часиков (на курсоре) можно написать System.BeginProcessing(); ... System.EndProcessing(); но это будет не красиво. Просто ставить

        Complete = 50;
        MoveProcessingProgress(ProgressWindow, Complete, WithCancel);  

перед вызовом хранимой процедуры, тоже не лучшее решение. Получать параметры с ХП - не выход, так как мы их получим после отработки всей процедуры. Многопоточности, на сколько я знаю, в JScript'е нет.
Просьба поделиться опытом, как можно отобразить процесс работы хранимой процедуры

Нравится

2 комментария

АльфаКрыса, универсального решения нет, всегда будет кастомное - никто не скажет вам сколько времени необходимо sql серверу на вашу ХП. Самым простым и оптимальным решением будут "часики", сложным и притянутым "за уши" - шаги в процедуре покрыть записью в какую-то таблицу, а в конфигурации по таймеру мониторить ее и рисовать шаги в прогрессе, но о времени выполнения они скажут мало.

Александр, спасибо за Ваш ответ.

Показать все комментарии

Задача
В БП проверить контрагента в базе по реквизитам и дальше заполнить реквизиты нового заказчика, если такого нет в базе.

(требование клиента)
Через сервис окна в Terrasoft запрашиваются реквизиты у пользователя :
- Наименование;
- Регион;
- Город;
- Телефон;

Создаем форму wnd_name_reg_city_phone унаследуем ее от wnd_BaseEdit, в Невизуальные компоненты добавляем даталинки на справочники датасетов ds_City и ds_State. Добавляем 4 ре контрола два из них LookupControl (для выбора справочников, заметьте НЕ LookupDataControl) и два Edit контрола.

edtName – Edit возвращает значение текст
edtState – LookupControl возращает ID выбранного региона
edtCity – LookupControl возращает ID выбранного города
edtPhone - возвращает значение текст

Получаем следующую форму (сама форма в прикрепленных файлах)
1
Далее для того что бы считывать логику необходимо подключить (создать) к окну скрипт. Выберете контрол Ok, событие OnClick два раза кликните на колонку Значение, дальше дизайнер предложить вам создать скрипт

На событие Ок, пропишем логику считывания значений, и запись их в атрибуты окна, для последующей передачи их в БП

//-----------------------------------------------------------------------------
// wnd_name_reg_city_phoneScript
//-----------------------------------------------------------------------------


function btnOKOnClick(Control) {

var AccountName = edtName.Value;
var AccountStateID = edtState.Value;
var AccountCityID = edtCity.Value;
var AccountPhone =  edtPhone.Value

SetAttribute(Control.ParentWindow, 'AccountName',AccountName);
SetAttribute(Control.ParentWindow, 'AccountStateID',AccountStateID);
SetAttribute(Control.ParentWindow, 'AccountCityID',AccountCityID);
SetAttribute(Control.ParentWindow, 'AccountPhone',AccountPhone);
         SendNotify(Control.ParentWindow, MSG_OK);
}


function Main() {
         var Window = Services.GetNewItemByUSI('wnd_name_reg_city_phone');
         Window.IsDesigning = false;        
         Window.Prepare();
         Window.Show();      
}

function Main() в данном коде необходима для реализации возможности и вызова окна по нажатию F9
Создаем БП
В БП следует создать параметры
2
Элемент Открытие окна в следующем варианте с следующими опциями
3

4
Каждый из параметров должен быть установлен с следующей опцией
5
6
Предварительный вид БП будет следующим видом
7
Элемент scr это скрипт, в котором мы считаем параметры с Окна, и запустим хранимую процедуру Базы данных, которая реализует выборку из базы по условию:

(требование клиента)
Name содержит N &
StateID содержит P &
CityID содержит G &
(Communication1 содержит T) или (Communication2 содержит T) или (Communication3 содержит T) или (Communication4 содержит T) или (Communication5 содержит T)

Хранимая процедура будет иметь вид:

CREATE  procedure [dbo].[tsp_check_name_reg_city_phone]
      @AccountName nvarchar(250),
      @AccountStateID uniqueidentifier ,
      @AccountCityID uniqueidentifier,
      @AccountPhone nvarchar(250),
      @Result int output
  AS
begin
      declare @AccountNameLike nvarchar(300)
      declare @AccountPhoneLike nvarchar(300)
     
    SET @AccountNameLike = '%'+ @AccountName + '%';
    SET @AccountPhoneLike= '%'+ @AccountPhone + '%';


DELETE FROM  tbl_Account_b;

INSERT INTO [dbo].[tbl_Account_b]
SELECT [ID]
      ,[CreatedOn]
      ,[ModifiedOn]
      ,[Name]
      ,[CreatedByID]
      ,[ModifiedByID]
      ,[OfficialAccountName]
      ,[PrimaryContactID]
      ,[TerritoryID]
      ,[AnnualRevenue]
      ,[EmployeesNumber]
      ,[OwnerID]
      ,[CampaignID]
      ,[AddressTypeID]
      ,[Address]
      ,[CityID]
      ,[StateID]
      ,[ZIP]
      ,[CountryID]
      ,[ActivityID]
      ,[FieldID]
      ,[Communication1]
      ,[Communication2]
      ,[Communication3]
      ,[Communication4]
      ,[Communication5]
      ,[Communication1TypeID]
      ,[Communication2TypeID]
      ,[Communication3TypeID]
      ,[Communication4TypeID]
      ,[Communication5TypeID]
      ,[Description]
      ,[AccountTypeID]
      ,[Code]
      ,[TaxRegistrationCode]
      ,[SettledCredit]
      ,[PostponementPayment]
FROM [dbo].[tbl_Account]
WHERE [Name] LIKE @AccountNameLike
AND [StateID] = @AccountStateID
AND [CityID] = @AccountCityID
AND (
   [Communication1] LIKE @AccountPhoneLike
OR [Communication2] LIKE @AccountPhoneLike
OR [Communication3] LIKE @AccountPhoneLike
OR [Communication4] LIKE @AccountPhoneLike
OR [Communication5] LIKE @AccountPhoneLike
)

 SET @Result = (SELECT count(*) FROM  [dbo].[tbl_Account_b]);

end  

Возращает процедура количество записанных данных.

Причем подразумевается что таблица tbl_Account_b есть, ее можно создать к примеру запросом

SELECT * INTO tbl_Account_b FROM tbl_Account WHERE 1 = 0

Дальше в БП мы должны вызвать данную процедуру.

В элементе scr в БП пишем код (предварительно подключив скрипты scr_DB, scr_WindowUtils,scr_WorkflowUtils)
9

function Item3OnExecute(ScriptItem, IsComplete) {
var vAccountNameBP = WFGetParamValue(ScriptItem.ParentItems.ParentDiagram, 'AccountNameBP');
var vAccountStateIDBP = WFGetParamValue(ScriptItem.ParentItems.ParentDiagram, 'AccountStateIDBP');
var vAccountCityIDBP = WFGetParamValue(ScriptItem.ParentItems.ParentDiagram, 'AccountCityIDBP');
var vAccountPhoneBP = WFGetParamValue(ScriptItem.ParentItems.ParentDiagram, 'AccountPhoneBP');


var Parameters = CreateSPParameters();
CreateSPParameter(Parameters, 'AccountName', pdtString, vAccountNameBP);
CreateSPParameter(Parameters, 'AccountStateID', pdtString, vAccountStateIDBP);
 CreateSPParameter(Parameters, 'AccountCityID', pdtString, vAccountCityIDBP);
CreateSPParameter(Parameters, 'AccountPhone', pdtString, vAccountPhoneBP);

CreateSPParameter(Parameters, 'OutTest', pdtInteger, 0);
Parameters.ItemsByName('OutTest').ParamType = 1;

var SQLText =
'exec dbo.tsp_check_name_reg_city_phone :AccountName, :AccountStateID, :AccountCityID,:AccountPhone,:OutTest OUTPUT';
Connector.DBEngine.ExecuteCustomSQL(SQLText, Parameters);

var res = Parameters.ItemsByName('OutTest').ValAsInt;
WFSetParamValue(ScriptItem.ParentItems.ParentDiagram, 'Acc_count', res);  
}

В строчках WFSetParamValue(ScriptItem.ParentItems.ParentDiagram, 'Acc_count', res);
Мы записываем полученное значение с процедуры в параметр БП 'Acc_count', после чего в элементе test_res в качестве примера выводим полученное значение.

Дальше по параметру 'Acc_count' можно анализировать значение переменной, и в зависимости от этого создавать нового контрагента

Окончательный вид всех параметров БП
9
Все сервисы прикреплены к данному сообщению

Нравится

Поделиться

2 комментария

Алексей, почему вы используете varchar вместо nvarchar? Вы потеряете юникод.
Создавать таблицу tbl_Account_b лучше запросом:

SELECT * INTO tbl_Account_b FROM tbl_Account Where 1 = 0

Таким образом у вас tbl_Account_b будет пустая, а не содержать всех Контрагентов.

Александр, спасибо за замечания, исправил предыдущий пост.

Показать все комментарии

Запустить хранимую процедуру без параметров можно следующим программным кодом:

var dataValueTypeManager = (DataValueTypeManager)UserConnection.AppManagerProvider.GetManager("DataValueTypeManager");

var storedProcedure = new StoredProcedure(UserConnection, "tsp_Anny");
using (DBExecutor dbExecutor = UserConnection.EnsureDBConnection()) {
        dbExecutor.StartTransaction(System.Data.IsolationLevel.ReadUncommitted);
        storedProcedure.Execute(dbExecutor);
        dbExecutor.CommitTransaction();
}
return true;

Нравится

Поделиться

10 комментариев

Добрый день, хороший пример, как быть с параметрами
Пример

declare
i integer;
begin
"test1"('10700947',i);
end;

На BPMonline я написал так, но могу получить исходящий параметр

int k =0;
var storedProcedure = new StoredProcedure(userConnection,"test1");

storedProcedure.WithParameter("10700947");
storedProcedure.WithParameter(k);
storedProcedure.Execute();

Пример запуска хранимой процедуры с параметрами можно посмотреть в процессе карточки слияния дублей.

var storedProcedure = new StoredProcedure(UserConnection, "tsp_MergeDuplicates");
storedProcedure.WithParameter(Column.Const(EntityPrimaryColumnValue));
storedProcedure.WithParameter(Column.Const(entitiesToMerge));
storedProcedure.WithParameter(Column.Const(Page.DataSource.Schema.UId));
storedProcedure.WithOutputParameter("return_value", dataValueTypeManager.GetInstanceByName("Integer"));
storedProcedure.WithOutputParameter("error_message", dataValueTypeManager.GetInstanceByName("Text"));
using (DBExecutor dbExecutor = UserConnection.EnsureDBConnection()) {
	dbExecutor.StartTransaction(System.Data.IsolationLevel.ReadUncommitted);
	Page.DataSource.ActiveRow.Save();
	storedProcedure.Execute(dbExecutor);
	if (storedProcedure.Parameters.Count > 0) {
		int result = (int)storedProcedure.Parameters[0].Value;
		string errorMessage = storedProcedure.Parameters[1].Value as string;
		if (result != 0) {
			dbExecutor.RollbackTransaction();
			throw new Exception(errorMessage);
		}
	}	
	dbExecutor.CommitTransaction();	
}
SetCloseStatus(1);

А есть пример получения из хранимой данные курсора из пакета оракл

Пример пакета

CREATE OR REPLACE PACKAGE INT4DB."tspkg_PaymentSchedule" AS
    TYPE  "TypeCursorSchedule" IS REF CURSOR;
    PROCEDURE "GetProducts"(IDin IN NUMBER,DEP_IDin IN NUMBER, result_cursor IN OUT 
"TypeCursorSchedule");
   END "tspkg_PaymentSchedule";
/
CREATE OR REPLACE PACKAGE BODY INT4DB."tspkg_PaymentSchedule"  AS
   PROCEDURE "GetProducts"(IDin IN NUMBER, DEP_IDin IN NUMBER, result_cursor IN OUT "TypeCursorSchedule")
   IS
    v_cursor "TypeCursorSchedule";
   BEGIN
       OPEN v_cursor FOR
            SELECT  code
            FROM   colvir.ZHAS_VIU_GRAF@T_CRM_CORT2
            WHERE ID =  IDin --817514550
            AND      DEP_ID = DEP_IDin;-- 2;
 
       result_cursor := v_cursor;
   END "GetProducts";
   END"tspkg_PaymentSchedule";
/

Сам попытался написать, но ругается на dataValueTypeManager

		var dataValueTypeManager = (DataValueTypeManager)userConnection.AppManagerProvider.GetManager("DataValueTypeManager");
		var storedProcedure = new StoredProcedure(userConnection,"GetProducts");
		storedProcedure.WithParameter("817514550");
		storedProcedure.WithParameter("2");
		storedProcedure.WithOutputParameter("return_value", dataValueTypeManager.GetInstanceByName("REFCursor???"));   
		storedProcedure.PackageName = "tspkg_PaymentSchedule";

Уточните, пожалуйста, какая у Вас версия и сборка BPMonline?

BPMOnline Версия 5.1.1.139

Для версии 5.1 запуск хранимой процедуры осуществляется иначе. Пример:

var contactSchemaId = new Guid("16BE3651-8FE2-4159-8DD0-A803D4683DD3"); //передаваемый в процедуру параметр
var storedProcedure = new StoredProcedure(UserConnection, "tsp_GloballySearchForDuplicates");
storedProcedure.WithParameter(Column.Const(contactSchemaId));
using (var dbExecutor = UserConnection.EnsureDBConnection()) {
	storedProcedure.Execute(dbExecutor);
}
 
StoredProcedure setRecordPositionProcedure = new StoredProcedure(Page.UserConnection, "tsp_SetRecordPosition")
                .WithParameter("TableName", RightsSchemaName)
                .WithParameter("PrimaryColumnName", "Id")
                .WithParameter("PrimaryColumnValue", primaryColumnValue)
                .WithParameter("GrouppingColumnNames", RightsGrouppingColumnNames)
                .WithParameter("Position", position);
setRecordPositionProcedure.PackageName = Page.UserConnection.DBEngine.SystemPackageName;
setRecordPositionProcedure.Execute();

А я вот не совсем понял как запускать процедуру с параметрами. Без параметров запускается, хотя тоже не все понятно)
Например, что у нас хранится в dataValueTypeManager?
Как мне надо описать в BPMonline и запустить процедуру, которая должна получить входящим параметром ID текущего пользователя, ну и например № договора, из которого она запускается?

Версия BPMonline 5.2

Для того, чтобы получить идентификатор записи активной строки реестра из процесса карточки реестра, используйте следующую конструкцию:

Guid actId =Page.DataSource.ActiveRow.GetTypedColumnValue<Guid>("Id");

Соответственно, потом этот идентификатор следует передать в хранимую процедуру.

dataValueTypeManager - это ядровый менеджер, который в данном конкретном случае необходим, чтобы привести получаемый из процедуры параметр к определенному типу.

Анна, а не могли бы вы привести пример, о котором я говорил в предыдущем комментарии:

"D.T." написал:

Как мне надо описать в BPMonline и запустить процедуру, которая должна получить входящим параметром ID текущего пользователя, ну и например № договора, из карточки которого она запускается?

Версия BPMonline 5.2

Guid contractId =Page.DataSource.ActiveRow.GetTypedColumnValue<Guid>("Id"); //если мы в реестре договоров
Guid currentUser = UserConnection.CurrentUser.ContactId;
 
var dataValueTypeManager = (DataValueTypeManager)UserConnection.AppManagerProvider.GetManager("DataValueTypeManager");
 
var storedProcedure = new StoredProcedure(UserConnection, "tsp_MergeDuplicates");
 storedProcedure.WithParameter(contractId);
 storedProcedure.WithParameter(currentUser);
 
 storedProcedure.WithOutputParameter("return_value", dataValueTypeManager.GetInstanceByName("Integer"));
 storedProcedure.WithOutputParameter("error_message", dataValueTypeManager.GetInstanceByName("Text"));
using (DBExecutor dbExecutor = UserConnection.EnsureDBConnection()) {
         dbExecutor.StartTransaction(System.Data.IsolationLevel.ReadUncommitted);
         Page.DataSource.ActiveRow.Save();
         storedProcedure.Execute(dbExecutor);
         if (storedProcedure.Parameters.Count > 0) {
                 int result = (int)storedProcedure.Parameters[0].Value;
                 string errorMessage = storedProcedure.Parameters[1].Value as string;
                 if (result != 0) {
                         dbExecutor.RollbackTransaction();
                         throw new Exception(errorMessage);
                 }
         }       
         dbExecutor.CommitTransaction(); 
}
 SetCloseStatus(1);
Показать все комментарии

Помогите разобраться с хранимой процедурой:

В ХП передается ID документа(@DocID) и сумма заголовков подчиненных документов (@child) для записи в поле ChildDocSum tbl_Document

ALTER PROCEDURE [dbo].[doc_child]
@DocID uniqueidentifier,
@child nvarchar(2000)
AS
BEGIN
UPDATE tbl_Document
SET ChildDocSum = @child
WHERE ID = @DocID
END

Запускаю я ее из скрипта следующим образом:
var Params = System.CreateObject('TSObjectLibrary.Parameters');
AddParameter(Params, pdtGUID, ParentID).Name = 'DocID';
AddParameter(Params, pdtString, ChildParentTitle).Name = 'child';
var SQL = "exec doc_child :DocID, child";
Connector.DBEngine.ExecuteCustomSQL(SQL, Params);

но вместо суммы заголовков подчиненных документов, сформированных в переменной ChildParentTitle в tbl_Document записывается строка child.

В чем может быть дело? В передаче параметров в ХП или в самой процедуре?

Версия TSCRM 3.3.1.72 на MSSQL2005

Нравится

5 комментариев

Юрий, Вы пропустили двоеточие:
var SQL = "exec doc_child :DocID, :child";

Юрий, еще как вариант запустить профайлер и посмотреть реальный запрос к серверу при запуске ХП. А какой смысл этой процедуры? Это можно сделать простым Update.

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

Сервис UpdateQuery. Но действительно могут быть нюансы насчет доступа. Тогда Вам необходимо еще раздать доступ public на запуск ХП.

Действительно дело было в двоеточии.
Александр, большое спасибо.

Показать все комментарии

Здравствуйте!

Проблема такова: имеется хранимая процедура, в неё передаю параметры, она возвращает 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

Буду благодарен за любую помощь!

Нравится

42 комментария

Видимо нужно указать Parameters.ItemsByName('isEnought').ParamType = 1.

Так как у IParameter свойство ParamType: InputOutputParamTypeEnum по-умолчанию имеет значение 0, т.е. входящий:

enum _InputOutputParamTypeEnum {
		ioptInput = 0,
		ioptOutput = 1,
		ioptInputOutput = 2
	} InputOutputParamTypeEnum;

Большое спасибо, Александр!!!

Действительно, пропустил указать тип параметра.
Теперь работает:

var Parameters = CreateSPParameters();
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

Рано тему закрывать! Новая проблема :)

При тестирование на обычной (MS SQL) конфигурации выходной параметр заполняется, но, при тестирование через WebServices - параметр НЕ заполняется!

В чем фишка?

--
Cogito, ergo sum

Думаю что фишка в ядре. Скорее всего вебсервисы просто не учитывают тот факт что параметр может возвращаться. Может как-то переделать на использование запроса с кастомной колонкой?

Разработчики пообещали сделать сборку 3.3.0.51, где будет исправлена эта ошибка... Ждем-с-с...

--
Cogito, ergo sum

Сегодня добавил для Web сервисов возможность возвращать результаты ExecuteCustomSQL через Output параметры. Обращайтесь в поддержку за сборкой 3.3.0.51.

Александр, большое спасибо!

--
Cogito, ergo sum

Я так понимаю, что описанный здесь способ вернуть результат работы хранимой процедуры в версии 3.0.2.244 не предусмотрен.
Как вернуть результат?

Посмотрите здесь и дальше по комментариям - способ возвращения через SelectQuery с использованием CustomSQL-колонок. При этом в конце хранимой процедуры должен быть Select, который возвращает необходимый результат.

а можно подробней? не совсем понятен принцип... каким образом получить результат из сервиса SelectQuery? в конце ХП создал select, а как то что он возвращает увязать с SelectQuery?
там еще рекомендуют создать поле (Result), но как его создать, если выбор возможен только из полей таблицы из секции FROM?

Результат Вы получаете в колонки запроса. Например, если в конце ХП Вы выполняете такой запрос:

select Field1, Field2, Field3 from tbl_Table
...

то в самом сервисе SelectQuery необходимо создать CustomSQL-колонки с названиями Field1, Field2, Field3. Причём в свойство "Текст SQL" первой из них Вам необходимо вставить вызов ХП:

1 as [a] into #tmp
drop table #tmp
 
EXEC ProcedureName :ParamName
 
/*

А для таблицы блока FROM сервиса запроса необходимо прописать алиас "*/--" (без двойных кавычек). Это необходимо, чтобы закомментировать остальной текст запроса.

Далее, после получения экземпляра этого SelectQuery и установки значений необходимых параметров результат выполнения ХП можно так: var Dataset = SelectQuery.Open();

Поля датасета будут содержать результат выполнения.

Что касается совета Дениса:

"в конце процедуры напишите что-то типа
select 1 as [Result]
а в SelectQuery создайте поле
Result - целого типа"

это частный случай того, что я написал выше (если хранимая процедура не возвращает ничего, "заставляем" её вернуть фиктивный результат в колонку запроса).

"SSV" написал:там еще рекомендуют создать поле (Result), но как его создать, если выбор возможен только из полей таблицы из секции FROM?

Именно поэтому рекомендуется создавать CustomSQL-колонки. В них не обязательно выбирать поля из таблицы блока FROM. Более того, в этом запросе абсолютно все колонки должны быть типа CustomSQL, а таблица желательно такая, которая содержит одну строку (чтобы ХП не выполнялась столько раз, сколько записей в таблице). Поэтому, поскольку таблица tbl_DatabaseInfo всегда должна содержать только одну запись, и мы не собираемся ни выбирать из неё информацию, ни выполнять над ней никаких операций, используется именно эта таблица.

Загрузите сервис из примера, и Вы увидите, что он удовлетворяет всем описанным требованиям.

в конце процедуры у меня такой селект:

select @ContractNewID as Result

в SelectQuery я вставил CustomSQL-поле с именем Result, в поле "Текст SQL" что-нибудь нужно писать? ибо всё вроде бы и работает, но в Result ничего не передается...

Свойство "Текст SQL" первой из колонок необходимо заполнить текстом:

1 AS [a] INTO #tmp
DROP TABLE #tmp
 
EXEC ProcedureName :ParamName
 
/*

В Вашем случае колонка единственная - её свойство "Текст SQL" так же необходимо заполнить. Вместо ProcedureName необходимо указать название Вашей процедуры, далее, если необходимо, - входящие параметры.

вот вложил созданный сервис. далее текст из скрипта:

SQ_SP = Services.GetNewItemByUSI('sq_ResultSP');
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 возвращается пустая строка...:sad:

Попробуйте запустить профайлер перед выполнением SQ_SP.Open() и посмотреть, какой запрос он возвращает. Потом выполните этот запрос с помощью Query Analyzer или SQL Server Management Studio и посмотрите на результат, а также на значения параметров, которые передаются в процедуру. Возможно, это подскажет дальнейшее направление анализа проблемы.

вот что показывает профайлер:

exec sp_executesql N'SELECT
	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 есть?

хм... вот только что-то непонятно как это передается дата... но ошибок не выдает, всё отрабатывает правильно...

да, в Result возвращается GUID...
но - в том виде в котором этот запрос был скопирован из профайлера, он не выполняется, если убрать у даты лишние кавычки, то всё проходит на ура...

Попробуйте при установке параметров использовать Values:

SQ_SP = Services.GetNewItemByUSI('sq_ResultSP');
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 колонки запроса привести её к нужному типу:

1 as [a] into #tmp drop table #tmp  EXEC spChangeLegalPerson_AddNewContract :ContractOldID, :NewAccountID, cast(:CertificateDate as datetime) /*

Также мне кажется, что поскольку значения параметров берутся из одного и того же датасета, достаточно будет в хранимку передавать значение поля ID, а остальные значения непосредственно получать в процедуре. Количество запросов от этого не должно измениться (тот же Select, который Вы выполняете для открытия датасета Dataset, будет выполняться в хранимой процедуре).

пробовал использовать Values, в профайлере запрос имеет тот же вид, но при этом выполняется без проблем... попытка привести параметр к типу datetime порождает ошибку - что-то о неправильном параметре... результат в поле Result процедура не возвращает... может и такого способа моя версия не поддерживает? а ADO позволяет это сделать?

Да, ADO должен позволять даже в 3.0.2.

Но возможно, быстрее будет переписать хранимую процедуру, как я писал выше:

"Лабьяк Олег Игоревич" написал:поскольку значения параметров берутся из одного и того же датасета, достаточно будет в хранимку передавать значение поля ID, а остальные значения непосредственно получать в процедуре.

Насколько я понимаю, проблема только в параметре типа datetime, а с параметром ID типа uniqueidentifier проблем возникнуть не должно.

проблем с datetime нет, проблема с возвратом уникального идентификатора. прийдется формировать его на стороне клиента и передавать в процедуру, а это не есть хорошо...

Можете выложить текст процедуры?

ALTER PROCEDURE [dbo].[spChangeLegalPerson_AddNewContract]
(
@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 внутри процедуры генерируется только один раз, и больше нигде не меняется. Я попробовал воспроизвести, используя Ваш запрос и оставив в теле процедуры только строки

SET @ContractNewID = newid()
SELECT @ContractNewID AS Result

Результат возвращался корректно. Проверял на версии 3.0.2.231. Почему не работает у Вас - пока версий нет.

Кстати, заметил, что выложенная Вами процедура требует 4 входящих параметра. Вы учли это в Вашем запросе?

Также попробуйте в тексте процедуры взять Result в квадратные скобки или заменить на другой алиас в процедуре и запросе.

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

Приходится поднимать тему в связи с переходом на SQL2008.

1 AS [a] INTO #tmp
DROP TABLE #tmp
 
EXEC ProcedureName :ParamName
 
/*

при попытке выполнить метод Open() появляется ошибка о том, что комментарий должен быть завершен... вероятно побороть это нельзя?
Тогда каким образом можно вернуть значение из ХП в версии 3.0.2.244?

У Вас точно алиас таблицы в блоке FROM такой: */-- ?

извиняюсь, не доглядел... СПСБ...
только значение не возвращается всё равно, точнее возвращается NULL, хотя я точно знаю, что должна быть осмысленная строка... если запрос из профайлера выполнить в студии, то значение есть, но оно не попадает в датасет...
ХП:

ALTER PROCEDURE [dbo].[spAccountStatus] 
	@IDBalSys integer
AS
BEGIN
	declare @StatusAccount varchar(250)
	execute ('BEGIN SRVC.SERVICES_PKG.GETCLIENTSTATUSCRM(?,?); END;', @IDBalSys, @StatusAccount output) AT DEVELOPER;
	select @StatusAccount
END

скрипт:

var SelectQuery = Services.GetNewItemByUSI('sq_StatusAccount');
SelectQuery.Parameters.ItemsByName('IDBalSys').Value = IDBalSys;
var DatasetResult = SelectQuery.Open();
var StatusAccount = DatasetResult.Values('StatusAccount');

в прицепе файл сервиса...

Думаю, для решения проблемы необходимо изменить последнюю строку хранимой процедуры следующим образом:

  SELECT @StatusAccount as [StatusAccount]

Дело в том, что процедура в том виде, в котором она есть сейчас, возвращает результат в колонку с неопределённым именем. А Вам необходимо получить результат из колонки "StatusAccount".

СПСБ!

Здравствуйте!

Есть хранимая процедура, которая возвращает запрос (4 поля).

Подскажите, пожалуйста, каким образом их все вывести?

Вероятно должно быть так: одно поле должно быть создано, как описано в сообщениях 28 и 29, а остальные должны быть просто созданы, а вот в ХП, в результирующем запросе все 4 поля должны быть описаны, как в сообщении 31, т.е. каждому полю должен соответствовать псевдоним в точности повторяющий название поля в сервисе...

Здравствуйте, Марина.

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

Приблизительный код:

(хранимая процедура)

CREATE PROCEDURE tspTest
@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

(код скрипта)

function Main()
{
 
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;	
}

Спасибо! Получилось

у меня по аналогии не получается:

ALTER procedure [dbo].[mySQLProc]
@Result [varchar](250) output
AS
 begin         
         SET @Result = (SELECT TOP 1 Name FROM tbl_Account)
 end
var Parameters = CreateSPParameters();
CreateSPParameter(Parameters, 'Result', pdtString, 0);
Parameters.ItemsByName('Result').ParamType = 1; // It!
var SQLText = 'exec dbo.mySQLProc :Result OUTPUT';
 
Connector.DBEngine.ExecuteCustomSQL(SQLText, Parameters);
var Result = Parameters.ItemsByName('Result').Value;
Log.Write(1, Result.ValAsStr);

Не получается, потому что хранимая процедура в MS SQL не возвращает строки.

Можно сделать хранимку такую:

ALTER procedure [dbo].[mySQLProc] --@Result varchar(250) output
AS
 begin         
         SELECT Name FROM tbl_Account WHERE Name Like '%Контакт%'
 end

и в MS SQL Managment Studio запросом:

DECLARE @Result varchar(250)
EXECUTE [dbo].[mySQLProc]
print @Result

будет выводиться нормальное значение, но при этом не ясно, как передать результат выборки в Terrasoft, так как ExecuteCustomSQL в Террасофте работает только с параметрами. Возможно у DBEngine есть еще какие лбо полезные методы, помимо ExecuteCustomSQL, но я их не обнаружил.

написал такую хранимку:

ALTER procedure [dbo].[mySQLProc]
@Result [varchar](250) output
AS
 begin         
         SELECT Name as Result FROM tbl_Account WHERE Name Like '%Контакт%'
 end

в MS SQL запрос

EXECUTE [dbo].[mySQLProc] @Result
print @Result

работает!!!

но передать строку в террасофт пока не получилось, пробовал такие скрипты:

var Parameters = System.CreateObject('TSObjectLibrary.Parameters');
         var ReturnParameter = Parameters.CreateItem();
         ReturnParameter.Name = 'Result';
         ReturnParameter.ParamType = 1;            
         ReturnParameter.DataType = 2;
         Parameters.Add(ReturnParameter);
         var sql = 'exec myProc :Result output';
         Connector.DBEngine.ExecuteCustomSQL(sql, Parameters);
         Label01.Caption = Parameters.ItemsByName('Result').ValAsStr;
         Log.Write(1, Parameters.ItemsByName('Result').ValAsStr);

и

var Parameters = CreateSPParameters();
		 CreateSPParameter(Parameters, 'Result', pdtString, 0);
		 Parameters.ItemsByName('Result').ParamType = 1; // It!
		 var SQLText = 'exec dbo.mySQLProc :Result OUTPUT';
		 Connector.DBEngine.ExecuteCustomSQL(SQLText, Parameters);
		 var Result = Parameters.ItemsByName('Result').Value;
		 Log.Write(1, Result.ValAsStr); 

так тоже строку не возвращает:

		 var Parameters = System.CreateObject('TSObjectLibrary.Parameters');
         var ReturnParameter = Parameters.CreateItem();
         ReturnParameter.Name = 'Result';
        ReturnParameter.ParamType = 1;           
        ReturnParameter.DataType = pdtString;
         Parameters.Add(ReturnParameter);
         Connector.DBEngine.ExecuteCustomSQL("SELECT :Result = Name FROM tbl_Account WHERE Name Like '%Контакт%'", Parameters);
         Log.Write(1, Parameters.ItemsByName('Result').Value+"");

Процедуру надо переделать:

alter procedure [dbo].[mySQLProc]
@Result nvarchar(250) output
AS
 begin         
         SELECT @Result = Name FROM tbl_Account WHERE Name Like '%Контакт%'
 end

Так будет работать, проверили!

"Виталий Ковалишин" написал:

Процедуру надо переделать:

ALTER procedure [dbo].[mySQLProc]

@Result nvarchar(250) output

AS

 begin        

         SELECT @Result = Name FROM tbl_Account WHERE Name LIKE '%Контакт%'

 end

Так будет работать, проверили!

--

www.it-sfera.com.ua

А скрипт в террасофте какой должен быть для этого кода?
Перепробовали массу скриптов с этим вариантом хранимой процедуры.

"Виталий Ковалишин" написал:

Процедуру надо переделать:

ALTER procedure [dbo].[mySQLProc]

@Result nvarchar(250) output

AS

 begin        

         SELECT @Result = Name FROM tbl_Account WHERE Name LIKE '%Контакт%'

 end

Так будет работать, проверили!

--

www.it-sfera.com.ua

Все получилось! Спасибо Виталию! С этим запросом заработал срипт:
var Parameters = Sy

stem.CreateObject('TSObjectLibrary.Parameters');
var ReturnParameter = Parameters.CreateItem();
         var ReturnParameter = Parameters.CreateItem();
         ReturnParameter.Name = 'Result';
         ReturnParameter.ParamType = 1;            
         ReturnParameter.DataType = 3;
         Parameters.Add(ReturnParameter);
Parameters.ItemsByName('Result').ParamType = 1; // It!
var SQLText = 'exec dbo.mySQLProc :Result OUTPUT';
Connector.DBEngine.ExecuteCustomSQL(SQLText, Parameters);
var rez = Parameters.ItemsByName('Result').ValAsStr;
Log.Write(1, rez+"");                
Показать все комментарии

Нравится

Поделиться

1 комментарий

Немного отредактировал процедуру и вывел отдельно функцию подбора товара и стоимости, в зависимости от метода расчета стоимости :)


--
«Настоящий руководитель чувствует ситуацию нутром, управляет людьми исключительно сердцем и может вдохнуть живую душу в проект, команду или всю организацию», - Tom DeMarco “The Deadline”

Показать все комментарии