Имя: Пароль:
1C
 
Выборка данных из MS SQL, передача в 1С и их дальнейшая обработка
0 Gill
 
03.08.22
13:25
Всем привет! Возникла необходимость получения данных из базы по учету контроля доступа сотрудников в здании и дальнейшая обработка этих данных в 1С.

Подключаемся к базе на SQL успешно, но но далее вываливается с ошибкой {ВнешнийОтчет.СКУД_Баулюкс.Форма.ФормаОтчета.Форма(70)}: Ошибка при вызове метода контекста (Execute):
Произошла исключительная ситуация (Microsoft OLE DB Provider for ODBC Drivers): [Microsoft][ODBC SQL Server Driver]Истекло время ожидания запроса

С значениями ConnectionTimeout и CommandTimeout пробовались играться (выствлять в О, исключать и т.д.).
Прошу подсказать, почему данный запрос не взлетает и падает с ошибкой ?)

    

///////////////////////////////////////////
//Подключение к SQL-серверу
    Попытка
        Соединение  = Новый COMОбъект("ADODB.Connection");
        Команда     = Новый COMОбъект("ADODB.Command");
        Выборка     = Новый COMОбъект("ADODB.RecordSet");
        Соединение.ConnectionString =
        "driver={SQL Server};" +
        "server="+ИмяСервераSQL+";"+
        "uid="+ПользовательSQL+";"+
        "pwd="+ПарольSQL+";"+
        "database="+БазаДанныхSQL+";";
        Соединение.ConnectionTimeout = 30;
        Соединение.CommandTimeout = 600;
        //Открытие соединение
        Соединение.Open();
        Команда.ActiveConnection   = Соединение;
        Сообщить("Успешное подключение!");
    Исключение
        Сообщить(ОписаниеОшибки());
        Возврат;
    КонецПопытки;
    
    Запрос=
    "SELECT
    |TimeVal as ДАТАВХОДА, HozOrgan as IDUser, Remark as СЧИТЫВАТЕЛЬ, NAME + FirstName + MidName as ФИО, GETDATE() as ДАТА_ВЫБОРКИ
    |FROM pLogData, pList
        |WHERE hozOrgan IN (24, 63, 248, 253, 31, 33, 136, 233, 62, 239, 141, 246, 38, 172, 202, 162, 235, 83, 87, 46, 43) AND
        |pLogData.hozOrgan = pList.ID  AND
    |TimeVal >= (select CAST('2022-08-03 00:00:05.000' as DATE)) AND
    |(Remark LIKE '%Вход   гл вход,   Считыватель 1%' OR Remark LIKE '%Выход   гл вход,   Считыватель 2%'");
    
    Попытка
        Команда.CommandText = Запрос;
        Выборка = Команда.Execute();
        Если Выборка.BOF = Ложь Тогда
            Выборка.MoveFirst();
            Пока Выборка.EOF = Ложь Цикл
                Сообщить("[TimeVal]="+Дата(Выборка.Fields("ДАТАВХОДА").Value)
                    +", [Remark]="+СокрЛП(Выборка.Fields("СЧИТЫВАТЕЛЬ").Value)
                +", [GETDATE]="+СокрЛП(Выборка.Fields("ДАТА_ВЫБОРКИ").Value)
                    +", [ФИО]="+СокрЛП(Выборка.Fields("ФИО").Value)
                    +", [HozOrgan]="+Дата(Выборка.Fields("IDUser").Value));
                Выборка.MoveNext();
            КонецЦикла;
        КонецЕсли;
    Исключение
        Сообщить(ОписаниеОшибки());
    КонецПопытки;

    /////////////////////////////////////////
    
     //Закрытия соединения
    Попытка
        Соединение.Close();
        Сообщить("Соединение закрыто!");
    Исключение
        Сообщить(ОписаниеОшибки());
    КонецПопытки;
1 Gill
 
03.08.22
13:26
&НаКлиенте
Процедура ВыполнитьОбработку(Команда)
    
    //Инициализация переменных
    ИмяСервераSQL = "";
    ПользовательSQL = "sa";
    ПарольSQL = "";
    БазаДанныхSQL = "";
    ТаблицаSQL = "pLogData";
    ТаблицаSQL2 = "pList";
    
    ///////////////////////////////////////////
    //Подключение к SQL-серверу
    Попытка
        Соединение  = Новый COMОбъект("ADODB.Connection");
        Команда     = Новый COMОбъект("ADODB.Command");
        Выборка     = Новый COMОбъект("ADODB.RecordSet");
        Соединение.ConnectionString =
        "driver={SQL Server};" +
        "server="+ИмяСервераSQL+";"+
        "uid="+ПользовательSQL+";"+
        "pwd="+ПарольSQL+";"+
        "database="+БазаДанныхSQL+";";
        Соединение.ConnectionTimeout = 30;
        Соединение.CommandTimeout = 600;
        //Открытие соединение
        Соединение.Open();
        Команда.ActiveConnection   = Соединение;
        Сообщить("Успешное подключение!");
    Исключение
        Сообщить(ОписаниеОшибки());
        Возврат;
    КонецПопытки;
    
    ТекстИнструкции=
    "SELECT
    |TimeVal as ДАТАВХОДА, HozOrgan as IDUser, Remark as СЧИТЫВАТЕЛЬ, NAME + FirstName + MidName as ФИО, GETDATE() as ДАТА_ВЫБОРКИ
    |FROM pLogData, pList
    |WHERE hozOrgan IN (24, 63, 248, 253, 31, 33, 136, 233, 62, 239, 141, 246, 38, 172, 202, 162, 235, 83, 87, 46, 43) AND
    |pLogData.hozOrgan = pList.ID  AND
    |  TimeVal >= (select CAST('2022-08-03 00:00:05.000' as DATE)) AND
    |(Remark LIKE '%Вход   гл вход,   Считыватель 1%' OR Remark LIKE '%Выход   гл вход,   Считыватель 2%'");
    
    
    Попытка
        Команда.CommandText = ТекстИнструкции;
        Выборка = Команда.Execute();
        Если Выборка.BOF = Ложь Тогда
            Выборка.MoveFirst();
            Пока Выборка.EOF = Ложь Цикл
                Сообщить("[TimeVal]="+Дата(Выборка.Fields("ДАТАВХОДА").Value)
                +", [Remark]="+СокрЛП(Выборка.Fields("СЧИТЫВАТЕЛЬ").Value)
                +", [GETDATE]="+СокрЛП(Выборка.Fields("ДАТА_ВЫБОРКИ").Value)
                +", [ФИО]="+СокрЛП(Выборка.Fields("ФИО").Value)
                +", [HozOrgan]="+Дата(Выборка.Fields("IDUser").Value));
                Выборка.MoveNext();
            КонецЦикла;
        КонецЕсли;
    Исключение
        Сообщить(ОписаниеОшибки());
    КонецПопытки;
    
    /////////////////////////////////////////
    
    
    //Закрытия соединения
    Попытка
        Соединение.Close();
        Сообщить("Соединение закрыто!");
    Исключение
        Сообщить(ОписаниеОшибки());
    КонецПопытки;
    
КонецПроцедуры
2 arsik
 
гуру
03.08.22
13:31
А в менеджере скуля этот запрос работает? И сколько работает? Может по таймауту просто откатывается
3 Gill
 
03.08.22
13:36
(2) работает, но долго (около 5 мин, админы утверждают, что это вызвано тем, что HDD на серваке этом)
4 Garykom
 
гуру
03.08.22
13:37
(0) вам нужен микросервис )) на Go
5 ИУБиПовиц
 
03.08.22
13:38
Я в скуле не оч хорошо понимаю. А FROM pLogData, pList их не надо джойнить? AND
    |pLogData.hozOrgan = pList.ID  AND
Как я понимаю эти таблицы перемножаются, потом условие накладывается?
6 arsik
 
гуру
03.08.22
13:41
(3) Ну блин сделай для начала
Соединение.ConnectionTimeout = 3000;
Соединение.CommandTimeout = 3000;

Если все гладко, тогда запрос начинай оптимизировать. Там сразу видно какая то хуерага.
7 Ёпрст
 
03.08.22
14:08
(0) запрос перепиши по человечьи.. использовать inner join с like + or... ну такое
8 Ёпрст
 
03.08.22
14:09
ну и вот это select CAST('2022-08-03 00:00:05.000' as DATE) тоже , полный пэ
9 1Сергей
 
03.08.22
14:44
а там реально в скуле поля так называются?
10 kittystark
 
03.08.22
14:49
(7) чет не увидел иннерджойна, разве через запятую это он ?

к (5)  даю +1
FROM pLogData, pList - декартово произведение - отсюда и тормоза
11 Ёпрст
 
03.08.22
14:51
(10)
cross join + where на pLogData.hozOrgan = pList.ID
это inner join
12 arsik
 
гуру
03.08.22
14:54
Предлагаю подключится через внешний источник данных. Там и запросы можно по человечьи написать.
13 Garykom
 
гуру
03.08.22
14:55
(12) а админы то на сервере дадут?
14 arsik
 
гуру
03.08.22
15:08
Через адо дают, а из 1С не дадут?
15 tan76
 
03.08.22
16:38
(12) плюсую, этот будет удобно в работе
16 Garykom
 
гуру
03.08.22
16:45
(14) через адо как ни странно проще чем ВИД
17 Garykom
 
гуру
03.08.22
16:45
(15) пробовал сам реально это "удобно"?
причем не на домашнем/локальном компе а на серверах разных?
18 arsik
 
гуру
03.08.22
16:59
(17) На старой работе ФИАС (постгре) через внешний источник подключен. Работает быстро, жрать не просит. Что тебе еще надо?
19 arsik
 
гуру
03.08.22
17:00
+(18) 150 магазинов (баз) по стране. В центре база ФИАСА.
20 arsik
 
гуру
03.08.22
17:03
Можно и тяп-ляп на адо сделать. Но кто после будет разбираться? А тут неплохой и удобный слой абстракции который позволят нормальные запросы к внешним данным писать.
21 Garykom
 
гуру
03.08.22
17:15
(20) мне надо чтобы если схема внешней БД поменялась
или даже банально она уехала на другой сервер
или сменила тип СУБД с MSSQL на PostgreSQL или прочие Oracle, MySQL/MariaDB
то можно было легко и просто продолжать юзать без админских прав и конфигуратора
22 Garykom
 
гуру
03.08.22
17:16
И я не за ADO. И не за ВИД.
Лично мое мнение внешняя прокладка (микросервис) на Go и вызвать его из 1С.
23 СеменовСемен
 
03.08.22
17:18
(21) если структура поменяется, тотбез конфигуратора не обойтись
24 mikecool
 
03.08.22
17:19
(22) а кто будет твой МС править при этих изменениях в источнике?
25 Garykom
 
гуру
03.08.22
17:21
(23) подразумевал что для задачи типа (0) надо просто
Тип СУБД
Адрес/IP сервера СУБД
Логин
Пароль
Текст SQL запроса

И просто вызываем, получая результат в JSON, который о обрабатываем в 1С
26 ptiz
 
03.08.22
17:21
(3) Долго - из-за кривого запроса, нет нормального соединения (уже написали выше).
Пример:
    СтрокаЗапроса = "
                    |SELECT
                    |    pLogData.TimeVal,
                    |    pLogData.Par4,
                    |    pList.Name + ' ' + pList.FirstName + ' ' + pList.MidName
                    |FROM pLogData
                    |    LEFT JOIN pList
                    |        on pList.ID = pLogData.HozOrgan
                    |    WHERE (Par3 = 41) AND (Event = 28) and not pList.Name is null
                    |        and pLogData.TimeVal >= " + ДатаСтрокойВSQL(ДатаНачала) + "
                    |        and pLogData.TimeVal <= " + ДатаСтрокойВSQL(КонецДня(ДатаОкончания));
27 Garykom
 
гуру
03.08.22
17:21
(25)+ Пусть схема меняется пофиг, лишь бы запрос выполнялся
Ну или меняем текст запроса sql
28 Garykom
 
гуру
03.08.22
17:22
(24) микросервис универсальный, его править не надо
29 Garykom
 
гуру
03.08.22
17:23
(25)+ забыл Порт и ИмяБазы
30 Garykom
 
гуру
03.08.22
17:28
(28)+ и даже если править
у меня исходник Go внутри 1С лежит

package main

import (
    "encoding/json"
    "fmt"

    "io/ioutil"
    "log"

    "os"

    _ "github.com/jackc/pgx/stdlib"
    "github.com/jmoiron/sqlx"
)

type Params struct {
    Server   string `json:"server"`
    Port     string `json:"port"`
    Database string `json:"database"`
    User     string `json:"user"`
    Password string `json:"password"`
    Query    string `json:"query"`
}

func readJSON(filename string) Params {
    file, _ := ioutil.ReadFile(filename)
    params := Params{}

    if err := json.Unmarshal(file, &params); err != nil {
        fmt.Println(err)
        panic(err)
    }

    return params
}

func postgres(arg1 string, arg2 string) string {

    request := readJSON(arg1)

    result := ""

    connectionString := "postgres://" + request.User + ":" + request.Password + "@" + request.Server + ":" + request.Port + "/" + request.Database + "?sslmode=disable"

    db, err := sqlx.Connect("pgx", connectionString)
    if err != nil {
        fmt.Println(err)
    }

    a := []map[string]interface{}{}

    rows, err := db.Queryx(request.Query)
    for rows.Next() {
        results := make(map[string]interface{})
        err = rows.MapScan(results)
        if err != nil {
            log.Fatalln(err)
        }
        a = append(a, results)
    }

    b, _ := json.Marshal(a)

    result = string(b)

    return result
}

func main() {
    argsWithoutProg := os.Args[1:]
    fmt.Println(len(argsWithoutProg))

    arg1 := os.Args[1]
    arg2 := os.Args[2]

    str := postgres(arg1, arg2)

    f, err := os.Create(arg2)
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    _, err2 := f.WriteString(str)
    if err2 != nil {
        log.Fatal(err2)
    }

}

И по кнопочке перекомпилится при необходимости в .exe

Данный пример чисто под PostgreSQL заточен, но несложно переписать под разные СУБД
31 NorthWind
 
04.08.22
08:00
(11) по идее, на скорость это не должно влиять. Пишут простые соединения и в where, это проще и короче, и работает по скорости также.
32 NorthWind
 
04.08.22
08:03
А запрос тормозит из-за лайков скорее всего.
33 NorthWind
 
04.08.22
08:04
Хотя это неточно, нужно смотреть обьем таблиц и что проиндексировано, а что нет
34 Garykom
 
гуру
04.08.22
08:54
(32) больше там нечему тормозить, только лайки
35 Shur1cIT
 
04.08.22
09:06
(0) Как всегда все не читал, почему бы не организовать через внешние источники данных? далее делаешь запрос через обчный конструктор запросов к этим таблицам
36 Gill
 
05.08.22
10:24
Господа (и дамы тоже) худо-бедно выборку из SQl получили, теперь продолжение истории:

Нам в итоге нужно данные из SQL (в частности поле IDUSer как-то синхронизировать с реквизитом в справочнике Сотрудники 1С прикрутив например реквизит такой же ID какой-нибудь) и из РЕГИСТРА СВЕДЕНИЙ "Состояния сотрудников" получить текущее кадровое состояние сотрудника (Работает, В отпуске, на больничном и т.д.).

В итоге нужен отчет следующего вида (с отбором по периоду):

N    Time val            IDUser      Remark          Cотрудник в 1С   Кадровое состояние
1    04.08.2022 7:10:06    248      Считыватель 1,      Иванов И.И.      Работает
2                                                          Петров П.П.      В отпуске
3    04.08.2022 7:45:12    200       Считыватель 1,      Сидоров И.И.     Работает
4                                                          Гринчук П.П.     На больничном

Что порекомендуете, какие будут мысли?
37 Gill
 
05.08.22
10:26
(36)
Данные сейчас выгружены в соответствующую Табличную часть на форме отчета СКД
38 Gill
 
05.08.22
10:45
ну как бы вопрос в следующем: как обратится к ТЧ на форме отчета в СКД, далее связать с соответствующим регистром и выгрузить в отчет?
39 ptiz
 
05.08.22
11:16
(38) Пихаешь всё в таблицу значений (добавляя туда физ лиц, их кадровые данные) и отдаешь в СКД.
40 Gill
 
05.08.22
11:20
(39) можно пример пожалуйста?
41 arsik
 
гуру
05.08.22
11:35
(40) Давай мы за тебя еще и зарплату будем получать.
42 Gill
 
05.08.22
11:39
(41) А как же помощь ближнему ?
43 Ёпрст
 
05.08.22
11:45
(36) в своей табличке SQl проапдейть табличку с полем IDUSer, в которую запихаешь iddref справочника пользователи.
Усё. И доп реквизит не нужон будет
44 Garykom
 
гуру
05.08.22
12:01
(42) Так то ближнему. А ты явно далек от 1С...
45 Gill
 
05.08.22
12:44
Так и не нашёл решения.
Всем участникам  За Советы  по существу спасибо,  намёки в (41) ,(44) оставлю без комментариев)
46 mikecool
 
05.08.22
12:47
(28) то бишь все собирается на лету...
47 Garykom
 
гуру
05.08.22
13:21
(46) все необходимое
микросервис один раз написал и юзаешь с разными параметрами для разных внешних sql баз
запрос sql просто строковый параметр
48 Garykom
 
гуру
05.08.22
13:23
(47)+ минус ado что оно под линуксом не пашет как и на фреше
тут же плюс что поднял микросервис и даже из фреша можно обращаться
2 + 2 = 3.9999999999999999999999999999999...