Имя: Пароль:
1C
1С v8
выполнить функцию MSSQL с помощью SQL-DMO
,
0 avz07
 
09.08.13
16:33
я раньше написал функцию в Microsoft SQL Server Management Studio. теперь хочу ее код с 1С передать на выполнение в SQL и получить результат. все организовать хочу через sql-dmo. но у меня не получается.
Пожалуйста, помогите мне пожалуйста.
вот функция:

CREATE FUNCTION RES_PO_POLYU()
RETURNS int
BEGIN
DECLARE @RES int
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME='kod_1c')
SET @RES=1;
ELSE
SET @RES=0;
RETURN @RES
END
GO
1 Jaap Vduul
 
09.08.13
16:39
2 avz07
 
09.08.13
16:55
если я правильно понял, должно быть так:

СКЛ = Новый COMObject ("SQLDMO.SQLServer");
СКЛ.Connect("10.133.100.5","1c_base","1c_base");
СтрокаПровSQL="CREATE FUNCTION RES_PO_POLYU()
                   |RETURNS int
                   |BEGIN
                   |DECLARE @RES int
                   |IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME='kod_1c')
                   |SET @RES=1;
                   |ELSE
                   |SET @RES=0;
                   |RETURN @RES
                   |END
                   |GO";
RSProv=СКЛ.Databases(Строка(БД)).ExecuteWithResults(СтрокаПровSQL);
                                 .ExecuteWithResultsAndMessages2(СтрокаПровSQL ,Messages) asQueryResults

а параметр без изменений Messages,или здесь должна быть переменная которую возвращает функция?
3 avz07
 
09.08.13
16:56
извиняюсь

RSProv=СКЛ.Databases(Строка(БД)).ExecuteWithResultsAndMessages2(СтрокаПровSQL ,Messages) asQueryResults;
                                 .
4 Новенький_2009
 
09.08.13
17:06
а не проще саму функцию в базе создать, и обычным запросом получить резалт?
5 avz07
 
09.08.13
17:13
это пример на тестовой базе.
есть бага бд по которым надо выполнять время от времени эту функцию
6 Новенький_2009
 
09.08.13
17:58
Был у меня пример где-то. Я тоже ёпся долго ;) Если найду - кину. Но я через ADO делал.
7 avz07
 
09.08.13
18:13
И от ADO не откажусь. Буду очень и очень благодарен!
8 МихаилМ
 
09.08.13
19:03
SQLDMO с мс скл 2008 не поддерживается. теперь rdo
9 avz07
 
09.08.13
19:29
если через RDO, то как осуществить подключение?
10 etc
 
09.08.13
20:54
не проще ли через ADO подсоединиться и сделать что-то типа:
ADOConnection.Execute("CREATE FUNCTION RES_PO_POLYU() ...
11 avz07
 
10.08.13
09:33
попытался так:

СтрокаСоединение="Provider=SQLOLEDB.1;
                     |Password=***;
             |Persist Security Info=True;
             |User ID=*** ;
             |Initial Catalog="+***+";
             |Data Source=*****;";
    Соединение = Новый COMОбъект("ADODB.Connection");
    Соединение.Open(СтрокаСоединение);
    Команда = Новый COMОбъект("ADODB.Command");
    Команда.CommandTimeOut = 150000;
    Команда.NamedParameters = True;
    Команда.CommandType =1;
    Команда.ActiveConnection = Соединение;
    Команда.CommandText="CREATE FUNCTION RES_PO_POLYU()
                   |RETURNS int
                   |BEGIN
                   |DECLARE @RES int
                   |IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME='kod_1c')
                   |SET @RES=1;
                   |ELSE
                   |SET @RES=0;
                   |RETURN @RES
                   |END GO";
RSProv=Новый COMОбъект("ADODB.Recordset");
    RSProv=Команда.Execute();
    RSProv.MoveFirst();

и мне выдало ошибку:

{Форма.Форма.Форма(2152)}: Ошибка при вызове метода контекста (Execute)
    RSProv=Команда.Execute();
по причине:
Произошла исключительная ситуация (Microsoft OLE DB Provider for SQL Server): Incorrect syntax near 'GO'.

в SQL эта функция работает хорошо.не могу понять, почему системе не воспринимает оператор GO??
12 oleg_km
 
10.08.13
09:44
(11) Потому что GO Это не оператор T-SQL, это оператор QA. Смело выкидываейте его и все будет работать
13 avz07
 
10.08.13
09:58
удалил GO  и заработало. но когда второй раз выполнил код мне выдало ошибку:

{Форма.Форма.Форма(2152)}: Ошибка при вызове метода контекста (Execute)
    RSProv=Команда.Execute();
по причине:
Произошла исключительная ситуация (Microsoft OLE DB Provider for SQL Server): There is already an object named 'RES_PO_POLYU' in the database.

как выполнять эту функцию повторно? возможно удалять ее после выполнения?
14 ДенисЧ
 
10.08.13
10:01
дык проверяй на наличие перед созданием...
15 avz07
 
10.08.13
10:10
и если такая уже существует то удалять или повторить выполнение уже существующей?
16 ДенисЧ
 
10.08.13
10:13
(15) это уже тебе решать :-)
Я бы вообще фуннкцией для такого запроса не заморачивался...
17 etc
 
10.08.13
14:24
только можно было проще:

    Соединение = Новый COMОбъект("ADODB.Connection");
    Соединение.Open(СтрокаСоединение);
    Соединение.Execute("CREATE FUNCTION RES_PO_POLYU()
                   |RETURNS int
                   |BEGIN
                   |DECLARE @RES int
                   |IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME='kod_1c')
                   |SET @RES=1;
                   |ELSE
                   |SET @RES=0;
                   |RETURN @RES
                   |END GO");
18 avz07
 
15.08.13
16:25
спасибо, но к сожалению так не подойдет, потому что без оператора GO пакет не передаст на исполнение..а этот GO вообще есть возможность заменить или что-то в этом роде??
19 ДенисЧ
 
15.08.13
16:28
(18) "без оператора GO пакет не передаст на исполнение"

Слушай... Поделись рецептиком.. Что такое забористое ты выпил?
20 avz07
 
15.08.13
17:39
я чего-то не совсем понимаю в материале ...?
21 avz07
 
15.08.13
17:43
Соединение = Новый COMОбъект("ADODB.Connection");    Соединение.Open(СтрокаСоединение);    Соединение.Execute("IF OBJECT_ID(N'dbo.REZ',N'FN')IS NOT NULL
                          |DROP FUNCTION dbo.REZ;
                          //|GO
               |CREATE FUNCTION dbo.REZ()
               |RETURNS int
                          |BEGIN
                          |DECLARE @RES int
                          |IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME='kod_1c')
                          |SET @RES=1;
                          |ELSE
                          |SET @RES=0;
                          |RETURN(@RES);
                          |END");
22 avz07
 
15.08.13
17:46
как тут без GO?
23 avz07
 
15.08.13
18:00
а если с GO, то вот такая ошибка:

{Форма.Форма.Форма(2136)}: Ошибка при вызове метода контекста (Execute)
    Соединение.Execute("IF OBJECT_ID(N'dbo.REZ',N'FN')IS NOT NULL
по причине:
Произошла исключительная ситуация (Microsoft OLE DB Provider for SQL Server): Incorrect syntax near 'GO'.
24 Зойч
 
15.08.13
18:02
(22) какая ошибка без го?
25 avz07
 
15.08.13
18:05
{Форма.Форма.Форма(2136)}: Ошибка при вызове метода контекста (Execute)
    Соединение.Execute("IF OBJECT_ID(N'dbo.REZ',N'FN')IS NOT NULL
по причине:
Произошла исключительная ситуация (Microsoft OLE DB Provider for SQL Server): 'CREATE FUNCTION' must be the first statement in a query batch.
26 avz07
 
15.08.13
18:06
возможно я неверно написал, возможно чего-то не знаю, не понимаю хорошо. подскажите или сбросьте какую-то литературу где такая ситуация описана.
27 avz07
 
15.08.13
19:56
а может через TADODataSet?
28 etc
 
15.08.13
20:49
раздели на 2 execut_а:

Соединение.Execute("IF OBJECT_ID(N'dbo.REZ',N'FN')IS NOT NULL DROP FUNCTION dbo.REZ;");

Соединение.Execute("CREATE FUNCTION dbo.REZ()
               |RETURNS int
               |BEGIN
               |DECLARE @RES int
               |IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME='kod_1c')
               |SET @RES=1;
               |ELSE
               |SET @RES=0;
               |RETURN(@RES);
               |END");
29 etc
 
15.08.13
20:51
"GO — это не инструкция Transact-SQL; это команда, распознаваемая программами sqlcmd и osql, а также редактором кода среды Среда SQL Server Management Studio.
Программы SQL Server интерпретируют команду GO как сигнал о том, что им следует отправить текущий пакет инструкций Transact-SQL экземпляру SQL Server."

... "потому что гладиолус"
30 avz07
 
15.08.13
21:03
спасибо за помощь!
я к этому дочитался. Но если разделить на две части, не увеличится ли время выполнения?
31 etc
 
15.08.13
21:12
Даже если бы это увеличивало время выполнения на пару секунд, у тебя что создание функции самая часто используеая операция? Наверняка максимум 1 раз за сессию.
32 avz07
 
16.08.13
11:39
нет. хочется, чтобы все было правильно, минимизировано.
33 ДенисЧ
 
16.08.13
11:40
(32) Один раз создавай. Она что, у тебя каждый день меняется?
34 avz07
 
19.08.13
12:24
еще один вопрос: "как вывести результат если я сделаю через два execut_а"?
35 avz07
 
19.08.13
12:25
имею в виду результат выполнения функции
36 ДенисЧ
 
19.08.13
12:30
у адодб есть возможность NextRecordset() сказать...
37 avz07
 
19.08.13
12:32
ДенисЧ, буду очень благодарен, если подскажете
38 Serginio1
 
19.08.13
12:32
РекордСет=Command.Execute();

Резулт="";
Пока РекордСет<>неопределено Цикл
    Если РекордСет.Fields.Count>0 Тогда
        Поле=РекордСет.Fields(0);
        Стр=Поле.Name+" "+Поле.Value;
        Если ЗначениеЗаполнено(Резулт) тогда
            Резулт=Резулт+"
            |"+Стр
        иначе
            Резулт=Стр;
        КонецЕсли;
    КонецЕсли;
    РекордСет=РекордСет.NextRecordSet();
КонецЦикла;
Сообщить(Резулт);
39 avz07
 
19.08.13
12:34
тоесть, после этого:

Соединение.Execute("CREATE FUNCTION dbo.REZ()
               |RETURNS int
               |BEGIN
               |DECLARE @RES int
               |IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME='kod_1c')
               |SET @RES=1;
               |ELSE
               |SET @RES=0;
               |RETURN(@RES);
               |END");

будет идти (38)
40 Serginio1
 
19.08.13
12:39
CREATE FUNCTION dbo.REZ() тебе ничего не вернет.
Результат возвращает Select (не помню как там насчет No Count)
41 avz07
 
19.08.13
12:44
да, я что-то не то написал ..
42 avz07
 
19.08.13
12:45
сначала я создаю функцию, а потом мне ее надо вызвать, чтобы она выполнилась
43 avz07
 
19.08.13
12:49
вот жаль, я не умею это делать. с ADO первый раз работать начал
44 Serginio1
 
19.08.13
12:57
Если тебе нужно единажды вызвать можешь посмотреть в сторону CTE http://msdn.microsoft.com/en-us/library/ms190766(v=sql.105).aspx
45 avz07
 
19.08.13
13:01
да. эта функция будет вызывать 1 раз, только когда будет запускаться внешняяобработка с ней
46 avz07
 
19.08.13
13:18
что-то я не совсем понял эту статью..
возможно у кого-то есть какой-то пример?
47 Serginio1
 
19.08.13
13:29
48 Serginio1
 
19.08.13
15:04
49 avz07
 
19.08.13
16:15
какое отношение имеет рекурсивный запрос к моей функции?
50 avz07
 
19.08.13
16:17
вот что у меня получилось, но это не отражает результат:

СтрокаСоединение="Provider=SQLOLEDB.1;
                     |Password=1c_base;
                     |Persist Security Info=True;
                     |User ID=1c_base ;
                     |Initial Catalog="+БД+";
                     |Data Source=10.133.100.5;";
    Соединение = Новый COMОбъект("ADODB.Connection");
    Соединение.Open(СтрокаСоединение);
    Соединение.Execute("IF OBJECT_ID(N'dbo.REZ',N'FN')IS NOT NULL DROP FUNCTION dbo.REZ;");
                         
    Соединение.Execute("CREATE FUNCTION dbo.REZ()
                       |RETURNS int
                          |BEGIN
                          |DECLARE @RES int
                          |IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME='kod_1c')
                          |SET @RES=1;
                          |ELSE
                          |SET @RES=0;
                          |RETURN(@RES);
                          |END");  
    CMD = Новый COMОбъект("ADODB.Command");
    CMD.ActiveConnection = Соединение;
    CMD.CommandText="dbo.REZ";
    RecordSet=Новый COMОбъект("ADODB.Recordset");    
    RecordSet=CMD.Execute();
    Результ="";
    Пока RecordSet<>Неопределено Цикл
    Если RecordSet.Fields.Count>0 Тогда
        Поле=RecordSet.Fields(0);
        Стр=Поле.Name+" "+Поле.Value;
        Если ЗначениеЗаполнено(Результ) Тогда
            Результ=Результ+""+Стр
        Иначе
            Результ=Стр;
        КонецЕсли;
    КонецЕсли;    
    RecordSet=RecordSet.NextRecordSet();
    КонецЦикла;
    Сообщить(Результ);
51 Serginio1
 
19.08.13
16:23
А где "Select dbo.REZ as Result"
52 Serginio1
 
19.08.13
16:24
"Select dbo.REZ() as Result"
53 Serginio1
 
19.08.13
16:28
И тебе не нужен NextRecordSet(); он нужен когда вызываются несколько Select
Проще использовать такой синтаксис
Соединение.Execute("IF OBJECT_ID(N'dbo.REZ',N'FN')IS  NULL
|Begin
|CREATE FUNCTION dbo.REZ()
                       |RETURNS int
                          |BEGIN
                          |DECLARE @RES int
                          |IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME='kod_1c')
                          |SET @RES=1;
                          |ELSE
                          |SET @RES=0;
                          |RETURN(@RES);
                          |END
End");  

или разделять запросы через ;
54 avz07
 
19.08.13
18:51
за (52) огромное спасибо!
55 avz07
 
19.08.13
18:54
попытался модифицировать код скл и столкнулся с той же ошибкой: не уникальное имя функции в пакете. вот код:

IF OBJECT_ID(N'dbo.REZ',N'FN')IS NOT NULL
BEGIN
   DROP FUNCTION dbo.REZ;
END
ELSE
BEGIN    
  CREATE FUNCTION dbo.REZ()
  RETURNS int
  BEGIN
  DECLARE @RES int
  IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME='kod_1c')
   SET @RES=1;
  ELSE
   SET @RES=0;
  RETURN(@RES);
  END
END
56 Serginio1
 
20.08.13
10:27
(55) Ну дык

IF OBJECT_ID(N'dbo.REZ',N'FN')IS NOT NULL
BEGIN
   DROP FUNCTION dbo.REZ;
END;
  
  CREATE FUNCTION dbo.REZ()
  RETURNS int
  BEGIN
  DECLARE @RES int
  IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME='kod_1c')
   SET @RES=1;
  ELSE
   SET @RES=0;
  RETURN(@RES);
  END;
57 avz07
 
20.08.13
15:38
Serginiol, большое спасибо за Вашу помощь! Я и так, как вы мне сбросили, пробовал делать. К сожалению ошибка все та же..
58 Serginio1
 
20.08.13
15:53
Смотрим http://msdn.microsoft.com/ru-ru/library/ms186755.aspx
такая конструкция должна работать

IF OBJECT_ID (N'dbo.REZ', N'FN') IS NOT NULL
    DROP FUNCTION dbo.REZ;

CREATE FUNCTION dbo.REZ()
http://msdn.microsoft.com/ru-ru/library/ms190324.aspx
FN = скалярная функция SQL

Для проверки сделай запрос
Select OBJECT_ID (N'dbo.REZ', N'FN')
59 Ёпрст
 
20.08.13
15:57
(58) не будет
60 Ёпрст
 
20.08.13
15:57
работать
61 avz07
 
20.08.13
16:17
да, такая конструкция работает, но с переключателем GO, который информирует об окончании пакета иструкций. А в пакете инструкций, имя функции должно быть уникальное (без повторений). Эту уникальность обеспечивал переключатель GO.
разве что ADO интерпретирует его самостоятельно. Потому, что в СКЛ так работать не будет.
62 Ёпрст
 
20.08.13
16:20
(61) чего-й то ты всё перепутал
63 avz07
 
20.08.13
16:22
(58), я читал эти статьи.
Возможно я что-то пропустил. но будто правельно все сделал и в Менеджере СКЛ, когда пробовал все пахало. А когда начал подстраиваться под 1С, то возникли трудности.
64 Serginio1
 
20.08.13
16:50
(59) а так

DECLARE @RES int;

  IF OBJECT_ID (N'dbo.REZ', N'FN') IS NOT NULL
    
   SET @RES=1;
  ELSE
   SET @RES=0;

Select @RES as СуществуетФункция;
65 Serginio1
 
20.08.13
16:54
(63) У меня такие конструкции

Стр="
     |BEGIN TRAN;
     |If OBJECT_ID('TempDB.dbo.#TempPrice') is not NULL DROP TABLE  #TempPrice;
     |Declare @ТекущаяДата as datetime= GetDate()

прекрасно работают. В пакетном запросе операторы разделяются ;
66 Ёпрст
 
20.08.13
16:55
автору надо просто делать как в (28) и привет..

т.е делать отдельными запросами дроп и креайт функции .. и усё.
67 Serginio1
 
20.08.13
17:19
(66) Можно и так, только можно и в одно пакетном запросе. Просто на семерке в 1с++ приходится включать
set nocount on

ТекстЗапроса="
        |set nocount on
        |if exists (select * from tempdb..sysobjects where id=object_id('tempdb..%Имя%') and sysstat & 0xf = 3 )
        |  drop table %Имя%;
        |"+СтрCreate+"
        |set nocount off
        |";
        рс_=СоздатьОбъект("ODBCRecordset");
        рс_.УстБД(ИБ);
        рс_.ВыполнитьИнструкцию(СтрЗаменить(ТекстЗапроса,"%Имя%",ИмяТаб));
        рс.Подготовить(СтрЗаменить(СтрInsert,"%Имя%",ИмяТаб));
        рс.ВыполнитьSQL_ИзТЗ(ТЗ,100);
68 Ёпрст
 
20.08.13
17:26
(67) да нет пакета в адо
69 Ёпрст
 
20.08.13
17:26
вот и ошибки у него валются..
70 Serginio1
 
20.08.13
17:29
(68) Есть возможность выполнения нескольких операторов разделенных точкой с запятой. А вот откуда у него ошибки это вопрос и какой у него MS SQL
71 Serginio1
 
20.08.13
17:50
По set nocount on разобрался


http://www.sql.ru/forum/2652/ispolnenie-skripta-iz-adodb-mozhet-i-off
В ADO Insert возвращает recordset если set nocount off
72 avz07
 
20.08.13
18:20
MS SQL 2008, не R2
73 avz07
 
20.08.13
18:25
вот что сделал я:

СтрокаСоединение="Provider=SQLOLEDB.1;
                     |Password=1c_base;
                     |Persist Security Info=True;
                     |User ID=1c_base ;
                     |Initial Catalog="+БД+";
                     |Data Source=10.133.100.5;";
    Соединение = Новый COMОбъект("ADODB.Connection");
    Соединение.Open(СтрокаСоединение);
    Соединение.Execute("IF OBJECT_ID(N'dbo.REZ',N'FN')IS NOT NULL DROP FUNCTION dbo.REZ;");
    Соединение.Execute("CREATE FUNCTION dbo.REZ()
                       |RETURNS int
                          |BEGIN
                          |DECLARE @RES int
                          |IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME='kod_1c')
                          |SET @RES=1;
                          |ELSE
                          |SET @RES=0;
                          |RETURN(@RES);
                          |END");  
    CMD = Новый COMОбъект("ADODB.Command");
    CMD.ActiveConnection = Соединение;
    CMD.CommandText="SELECT dbo.REZ() AS Result";
    
    RecordSet=Новый COMОбъект("ADODB.Recordset");    
    RecordSet=CMD.Execute();
    Результ="";
    Если RecordSet.Fields.Count>0 Тогда
        Поле=RecordSet.Fields(0);
        Стр=Поле.Value;
        Если ЗначениеЗаполнено(Результ) Тогда
            Результ=Результ+""+Стр
        Иначе
            Результ=Стр;
        КонецЕсли;
    КонецЕсли;
74 Serginio1
 
20.08.13
18:29
А 56 что выдает?
75 avz07
 
20.08.13
18:44
в 1С пишет что ошибка метода Execute по причине:произошло исключительная ситуация...
А Менеджер СКЛ видает такое:
Сообщение 111, уровень 15, состояние 1, строка 6
'CREATE FUNCTION' must be the first statement in a query batch.
Сообщение 178, уровень 15, состояние 1, строка 14
A RETURN statement with a return value cannot be used in this context.
подчеркивает CREATE FUNCTION dbo.REZ()
76 avz07
 
20.08.13
18:49
обидно что мне не получается написать все одним пакетом, но надо сдать задание ..
если кто-то посоветует еще что-небуть, буду сердечно благодарен.
а так, всем спасибо за участие в обсуждении!
77 Serginio1
 
20.08.13
18:59
Да смутно припоминаю на ограничения для функций, что они дожны быть первыми в пакетном запросе. Так, что ничего страшного.
78 avz07
 
20.08.13
19:01
Serginio1, вам отдельное спасибо за активное участие и помощь!
79 Serginio1
 
21.08.13
10:25