Здравствуйте! Мне нужно на время выполнения моего скрипта отменить проверку на дубли, которая происходит во время инсерта очередной записи (проверку я делаю сам при импорте данных с excel). Возможно ли отключить эту проверку?

Нравится

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

нашел аттрибут Connector.Attributes('IsDuplicatesCheckDisabled'), который отвечает за включение/выключение поиска дублей. Тема закрыта)

Добрый день, Антон.
Также в версии 3.4.0 имеется возможность воспользоваться визуальными инструментами для настройки правила поиска дублей: Файл::Настройки::Правила поиска дублей.

duplicatescheck.png

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

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

Причина тому - разные наборы колонок в сервисе таблицы и полей в реальной таблице в БД. Такие поля могли возникнуть при удалении ошибочно созданных колонок в сервисе tbl_... или же созданы при помощи СУБД для нужд какой-то интеграции или работы хранимой процедуры. Обычно такие невидимые поля никак не проявляются и никому не мешают, но попытка объединения дублей на такой таблице порождает ошибку "wrong number or types of arguments in call to".

Чтобы всё заработало, пришлось создать такие поля в сервисе таблицы. Во избежание конфликтов, изначальные поля с данными были переименованы, а после сохранения сервиса переименованы обратно:

ALTER TABLE "tbl_Account"
RENAME COLUMN "SecretField" TO "SecretField1";

--сохраняем в TSAdmin сервис таблицы с новой колонкой SecretField

ALTER TABLE "tbl_Account" DROP COLUMN "SecretField";

ALTER TABLE "tbl_Account"
RENAME COLUMN "SecretField1" TO "SecretField";

Такой подход можно использовать и при разворачивании пакета исправлений, включающего сервисы и SQL-запросы.

Если же скрытые поля явно не нужны, их можно просто удалить одной лишь командой:

ALTER TABLE "tbl_Account" DROP COLUMN "SecretField";

После исправления таблицы стоит заново сгенерировать для неё настройки поиска дублей.

Но лучше всего сразу создавать новые поля в таблицах Terrasoft только посредством TSAdmin или TSClient, а не средствами СУБД.

Нравится

Поделиться

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

Настраивая механизм поиска дублей в проекте на Terrasoft 3.X, работающем на базе Oracle, для таблицы контактов получал ошибку при попытке объединить дубли. При автоматической генерации хранимых процедур для объединения дублей возникло несоответствие порядка двух полей в таблице, что и привело к проблемам. В сгенерированной серверной логике они были в одном порядке, а на стороне клиентского приложения они перебирались в другом. Поля назывались, для примера, Com1 и Communication.

При этом ошибка воспроизводилась, если поиск дублей настраивали из клиента Terrasoft на одном компьютере и не воспроизводилась, если настраивали на другом. К сожалению или к счастью, первым компьютером был мой.

Как оказалось, причина возникновения проблемы была в этом фрагменте хранимой процедуры:

 SELECT   column_name,
                 data_type,
                 data_precision,
                 data_scale,
                 char_length,
                 char_used
          FROM   all_tab_columns
         WHERE   table_name = 'tbl_Contact'
                 AND owner = SYS_CONTEXT ('USERENV', 'CURRENT_SCHEMA')
      ORDER BY   column_name;

На первый взгляд безобидная строка

ORDER BY column_name

сортирует различно в зависимости от локали на компьютере, откуда запускаем TSClient или Toad!

На моём ПК, если посмотреть:

 SELECT * FROM nls_session_parameters;

Получим:

Цитата:
NLS_LANGUAGE RUSSIAN
NLS_TERRITORY RUSSIA
NLS_CURRENCY р.
NLS_ISO_CURRENCY RUSSIA
NLS_NUMERIC_CHARACTERS ,
NLS_CALENDAR GREGORIAN
NLS_DATE_FORMAT DD.MM.RR
NLS_DATE_LANGUAGE RUSSIAN
NLS_SORT RUSSIAN
NLS_TIME_FORMAT HH24:MI:SSXFF
NLS_TIMESTAMP_FORMAT DD.MM.RR HH24:MI:SSXFF
NLS_TIME_TZ_FORMAT HH24:MI:SSXFF TZR
NLS_TIMESTAMP_TZ_FORMAT DD.MM.RR HH24:MI:SSXFF TZR
NLS_DUAL_CURRENCY р.
NLS_COMP BINARY
NLS_LENGTH_SEMANTICS BYTE
NLS_NCHAR_CONV_EXCP FALSE

Вот из-за чего проблема! Надо использовать вместо RUSSIAN режим сортировки BINARY, где цифры расположены впереди латинских букв. А в RUSSIAN – позади. И в хранимке для объединения дублей передаются поля таблицы не в том порядке, что в ядре программы-клиента. Использование функции NLSSORT принудительно сортирует нужным образом.

Проблемная строка была заменена на:

      ORDER BY  NLSSORT(column_name, 'NLS_SORT=BINARY');

Модификации подверглись tsp_GenerateSearchSP, tsp_GenerateLiveSearchSP, tsp_GenerateDuplicateSearch, и tsp_GenerateDuplicateMerge. В новых версиях Terrasoft 3.X изменение внесено, остальным рекомендую исправить самостоятельно.

Нравится

Поделиться

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

duplicate_hash_list_entry

searchrule
Если делал ты когда-то
Поиск дублей в Террасофте
И при правила настройке
Получал внезапный, страшный
Duplicate hash list entry.
Нужно посмотреть таблицу
И на select query тоже.
В select query затаились
Поломавшиеся фильтры.
А в таблице, несомненно,
Есть поля с заглавьем длинным
вроде PreviouslyGuarFullRepaidother.
Их не любят процедуры,
что готовят поиск дублей.
Если мы поправим фильтры,
Поля переименуем,
Будет поиск дубликатов
создаваться без ошибок!

Нравится

Поделиться

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

Отлично:smile:

Спасибо, Александр, будем знать.

Также появление сабжа возможно, если на базу забыли перенести таблицу TempTable. Её код:

DROP TABLE "TempTable" CASCADE CONSTRAINTS;
 
CREATE GLOBAL TEMPORARY TABLE "TempTable"
(
  ID         VARCHAR2(38 BYTE),
  VALUE      VARCHAR2(2000 BYTE),
  CREATEDON  DATE
)
ON COMMIT DELETE ROWS
NOCACHE;

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

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

Долго не мог понять, почему если я вношу телефон в "Средство связи 1", а такой же указан в "Средство связи 2" другого контакта, то CRM меня не предупреждает?
Вижу, не только меня этот вопрос интересует...
http://community.terrasoft.ua/forum/topic/4121
Как можно решить?

Мой вариант (предлагаю использовать процедуру, для быстроты поиска)

CREATE PROCEDURE [dbo].[tsp_CheckForDoublet] (
        @ID AS uniqueidentifier,
        @Communication1 AS nvarchar(250),
        @Communication2 AS nvarchar(250),
        @Communication3 AS nvarchar(250),
        @Communication4 AS nvarchar(250),
        @NumOfDigits AS int,
        @ReturnResult AS int = 0 OUTPUT
        )
AS

SET @ReturnResult = 0

IF EXISTS (SELECT [ID] FROM [dbo].[tbl_Contact] WHERE
[ID] > @ID AND (  
RIGHT(REPLACE(REPLACE([Communication1], '-', ''), ' ', ''), @NumOfDigits) IN (@Communication1, @Communication2, @Communication3, @Communication4)
OR
RIGHT(REPLACE(REPLACE([Communication2], '-', ''), ' ', ''), @NumOfDigits) IN (@Communication1, @Communication2, @Communication3, @Communication4)
OR
RIGHT(REPLACE(REPLACE([Communication3], '-', ''), ' ', ''), @NumOfDigits) IN (@Communication1, @Communication2, @Communication3, @Communication4)
OR
RIGHT(REPLACE(REPLACE([Communication4], '-', ''), ' ', ''), @NumOfDigits) IN (@Communication1, @Communication2, @Communication3, @Communication4)
) ) SET @ReturnResult = 1

RETURN

Процедура вылавливает дубли даже с тире и пробелами :lol:
8-032-229-99-99 и 2299999 - в данном случае считаются дублями. Если Вас это не устраивает, просто в параметр NumOfDigits большое количество символов для обработки

CreateSPParameter(Parameters, 'NumOfDigits', pdtInteger, 12);

Добавим права доступа на запуск данной процедуры группой "Все пользователи"

Правим событие в файле scr_Contact

function SelfOnDatasetBeforePost(Dataset, DoPost) {

..........
/* START */
        var Parameters = CreateSPParameters();
        CreateSPParameter(Parameters, 'ID', pdtGUID, Dataset('ID'));
        CreateSPParameter(Parameters, 'Communication1', pdtString, Dataset('Communication1'));
        CreateSPParameter(Parameters, 'Communication2', pdtString, Dataset('Communication2'));
        CreateSPParameter(Parameters, 'Communication3', pdtString, Dataset('Communication3'));
        CreateSPParameter(Parameters, 'Communication4', pdtString, Dataset('Communication4'));
        CreateSPParameter(Parameters, 'NumOfDigits', pdtInteger, 7); //количество символов
        CreateSPParameter(Parameters, 'isDoublet', pdtInteger, 0);
        Parameters.ItemsByName('isDoublet').ParamType = 1;
        var SQLText = 'exec dbo.tsp_CheckForDoublet :ID, :Communication1, :Communication2, :Communication3, :Communication4, :NumOfDigits, :isDoublet OUTPUT';
        Connector.DBEngine.ExecuteCustomSQL(SQLText, Parameters);
        var isDoublet = Parameters.ItemsByName('isDoublet').ValAsInt;  
        if (isDoublet == 1) {
                var Message = 'Дублируются средства связи!';
                ShowWarningDialog(Message);
                DoPost.Value = false; // не сохранять в базу
        }
/* END */
}

Доработки - возвращать массив ID и заполнять реестр нового окна ссылками на контактов, с возможностью "перейти к" (В данном варианте мы не знаем где именно дубль, но зато проверяем по всей базе, даже если отсутствуют права на чтение)

Развиваем идею здесь!

Нравится

Поделиться

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

"Виталий Ковалишин aka samael" написал:но зато проверяем по всей базе, даже если отсутствуют права на чтение

:twisted:

"Underscore a.k.a. _" написал::twisted:

Спасибо! А "плюс Адин" где? :wink:

--
www.it-sfera.com.ua

Сорри, забыл. Плюсанул :)

Оооо, другое дело!

Спасибо! :biggrin:

--
www.it-sfera.com.ua

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

SelfOnDatasetBeforePost

BeforePost может же быть и при редактировании существующей записи.

Согласен!
Нужно добавить проверку на ID :wink:
подправим...

--
www.it-sfera.com.ua

"Раловец Ольга" написал:BeforePost может же быть и при редактировании существующей записи.

Да что Вы говорите /*шепотом так и с большими круглыми глазами*/ :) Но проверка дублей делается только при вставке, или я ошибаюсь?

"Underscore a.k.a. _" написал:Но проверка дублей делается только при вставке, или я ошибаюсь?

"Да что Вы говорите" (с) я вижу вызов процедуры прямо в обработчике события DatasetBeforePost, или я ошибаюсь?

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

Не ошибаетесь, ровно 10.

"Underscore a.k.a. _" написал:Там жирных 10 точек стоит

Надо же посчитали :)
Ну и что что точки?
Нигде не написано, что проверку делать надо только при вставке записи. Кроме того это логически не правильно. Проверку делать надо и при обновлении записи.

"Агутин Алексей" написал:Проверку делать надо и при обновлении записи.

Не согласен, это будет напряжно на каждое изменение ее делать. По крайней мере сейчас она делается только на вставку.

"Раловец Ольга" написал:Не ошибаетесь, ровно 10.

Учите матчасть, мадам. Ну и не ленитесь смотреть в исходники.

Поулыбался над комментами :smile:

Виталий, огромное спасибо.
Но нубский вопрос - Куда вставлять данную процедуру?
И можно полностью разжевать, а?
______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

Как малые дети! :lol:

1. Проверка и так на стороне сервера (процедуры), не должно быть напрягов :)
2. Можно не на датасет а на карточку повесить, тогда она не будет закрываться (как это сейчас происходит и мы заново должны все набирать из-за одного телефона)
3. Да, точек 10 - но это случайно получилось
4. Сегодня постараюсь подправить процедуру на проверку по ID (вместо баловства - могли бы и помочь) -- уже подправил
5. После - полностью разъясню куда и что вставить (я о процедуре) :)

Спасибо, не ожидал такого бурного обсуждения! :biggrin:

--
www.it-sfera.com.ua

"Евгений Лемеш" написал:Поулыбался над комментами

Видать вчера магнитные бури были. Сам себе удивляюсь :)

"Биккинин Т.Р." написал:Куда вставлять данную процедуру?

Вам необходимо открыть SQL Server Management Studio на сервере и выполнить данный скрип - процедура будет создана. После, добавить права доступа (иначе, только Supervisor сможет нею воспользоваться):

GRANT EXECUTE ON PROCEDURE [dbo].[tsp_CheckForDoublet] TO public

Дальше код в админке :)

Это быстрое решение, для большего удобства пользования, оно еще нуждается в доработке... :lol:

--
www.it-sfera.com.ua

Виталий, добрый день.
Добрался до Вашего ответа.
Скрипт на сервере прошел, но на

 
GRANT EXECUTE ON PROCEDURE [dbo].[tsp_CheckForDoublet] TO public 

выдает следующее:
Server: Msg 156, Level 15, State 1, Line 1
Incorrect syntax near the keyword 'PROCEDURE'.

Что я делаю не так?
______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

GRANT EXECUTE ON [dbo].[tsp_CheckForDoublet] TO public 

А так?

Копи-пейст он до добра не доводит :)

Ольга,

Server: Msg 208, Level 16, State 11, Line 1
Invalid object name 'dbo.tsp_CheckForDoublet'.

______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

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

Ольга,

в том то и дело, что процедура создалась успешно, только я не понял для какой именно базы. на сервере у меня их 3 лежит. Таким же образом добавляю grant execute, но она не проходит. ______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

Для начала нужно определиться с именем нужной базы данных :) Приблизительная последовательность действий: открываем SQL Server Management Studio, подключаемся к серверу, далее слева в инспекторе объектов разворачиваем ветку "Databases" и останавливаемся на той, в которой хотим создать процедуру. Далее нажимаем кнопочку "New Query", откроется окно редактирования и появится еще одна строчка в меню, там будет выпадающий список, в котором выбрана та база данных, на которой мы стояли в инспекторе объектов. Если сразу нажать "New Query", то будет выбрана бд "master".

Ольга, спасибо. Пошел проверять. Отпишусь позднее.
______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

Вот, что называется отсутствие знаний!
Ольга, все сделал, как Вы сказали, обе процедуры прошли успешно. Добавил функцию в скрипт scr_Contact, но новая функция не работает.
Вот так выглядит теперь функция SelfOnDatasetBeforePost:

function SelfOnDatasetBeforePost(Dataset, DoPost) {
	var ContactsDataset = Dataset;
	Contact.NeedActualizeCommunication = GetFieldsValuesAreChanged(Dataset,
		'Communication1', 'Communication2', 'Communication3',
		'Communication4', 'Communication1TypeID', 'Communication2TypeID',
		'Communication3TypeID', 'Communication4TypeID');
	Contact.NeedActualizeAddress = GetFieldsValuesAreChanged(Dataset, 'Address',
		'CountryID', 'AddressTypeID', 'StateID', 'CityID', 'TerritoryID');
	Contact.NeedActualizeCareer = GetFieldsValuesAreChanged(Dataset, 'AccountID',
		'JobID','JobTitle','DepartmentID');
	/* MODULE CAMPAIGNS */
	Contact.NeedActualizeCampaign = GetFieldsValuesAreChanged(Dataset,
		'CampaignID');
	/* ENDMODULE CAMPAIGNS */
	if(!IsEmptyValue(Dataset.Values('AccountID')))
	{
	Dataset.Values('WorkName') = Dataset.Values('Name')+' , '+GetDatasetFieldValueByID('ds_Account',Dataset.Values('AccountID'),'Name');
	}
	else
	{
	Dataset.Values('WorkName') = Dataset.Values('Name');
}
 
        Contact.IsAppend = (Dataset.State == dstInsert);  
        //SetItemSystemNumber('Contact', Dataset, 'ClientNumber');
 
    var Parameters = CreateSPParameters();
        CreateSPParameter(Parameters, 'ID', pdtGUID, Dataset('ID'));
        CreateSPParameter(Parameters, 'Communication1', pdtString, Dataset('Communication1'));
        CreateSPParameter(Parameters, 'Communication2', pdtString, Dataset('Communication2'));
        CreateSPParameter(Parameters, 'Communication3', pdtString, Dataset('Communication3'));
        CreateSPParameter(Parameters, 'Communication4', pdtString, Dataset('Communication4'));
        CreateSPParameter(Parameters, 'NumOfDigits', pdtInteger, 7); //количество символов
        CreateSPParameter(Parameters, 'isDoublet', pdtInteger, 0);
        Parameters.ItemsByName('isDoublet').ParamType = 1;
        var SQLText = 'exec dbo.tsp_CheckForDoublet :ID, :Communication1, :Communication2, :Communication3, :Communication4, :NumOfDigits, :isDoublet OUTPUT';
        Connector.DBEngine.ExecuteCustomSQL(SQLText, Parameters);
        var isDoublet = Parameters.ItemsByName('isDoublet').ValAsInt;  
        if (isDoublet == 1) {
                var Message = 'Дублируются средства связи!';
                ShowWarningDialog(Message);
                DoPost.Value = false; // не сохранять в базу
        }    
}

Что неправильно?
______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

Я вот подумала, что не очень-то хорошо прописывать строки, среди которых есть вывод сообщения пользователю в скрипте датасета. Лучше сделать это в скрипте карточки (scr_ContactEdit). Открываете окно wnd_ContactEdit, переходите на закладку не визуальные(в левой верхней стороне), становитесь на dlData, ниже среди событий находите OnDatasetBeforePost, нажимаете 2 раза и пишете

if (Dataset.State == dstInsert) {
var Parameters = CreateSPParameters();
        CreateSPParameter(Parameters, 'ID', pdtGUID, Dataset('ID'));
        CreateSPParameter(Parameters, 'Communication1', pdtString, Dataset('Communication1'));
        CreateSPParameter(Parameters, 'Communication2', pdtString, Dataset('Communication2'));
        CreateSPParameter(Parameters, 'Communication3', pdtString, Dataset('Communication3'));
        CreateSPParameter(Parameters, 'Communication4', pdtString, Dataset('Communication4'));
        CreateSPParameter(Parameters, 'NumOfDigits', pdtInteger, 7); //количество символов
        CreateSPParameter(Parameters, 'isDoublet', pdtInteger, 0);
        Parameters.ItemsByName('isDoublet').ParamType = 1;
        var SQLText = 'exec dbo.tsp_CheckForDoublet :ID, :Communication1, :Communication2, :Communication3, :Communication4, :NumOfDigits, :isDoublet OUTPUT';
        Connector.DBEngine.ExecuteCustomSQL(SQLText, Parameters);
        var isDoublet = Parameters.ItemsByName('isDoublet').ValAsInt;  
        IF (isDoublet == 1) {
                var Message = 'Дублируются средства связи!';
                ShowWarningDialog(Message);
                DoPost.Value = false; // не сохранять в базу
        }    
}
}

Ольга, спасибо.
Заработало. Результатом является появление диалогового сообщения, причем повторного и карточка не сохраняется. И при этом система не различает телефон 123456, 123-456, 12-34-56 и 123 456. По идее должно же?

______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

"Биккинин Т.Р." написал:Результатом является появление диалогового сообщения, причем повторного и карточка не сохраняется.

Что значит повторного? Вы, наверное, не убрали из скрипта датасета то, что внесли до того, как я посоветовала редактировать scr_ContactEdit.
"Биккинин Т.Р." написал:И при этом система не различает телефон 123456, 123-456, 12-34-56 и 123 456. По идее должно же?

Судя по тому, что написал Виталий, должно считать их одним и тем же.
"Виталий Ковалишин aka samael" написал:Процедура вылавливает дубли даже с тире и пробелами :lol:
8-032-229-99-99 и 2299999 - в данном случае считаются дублями. Если Вас это не устраивает, просто в параметр NumOfDigits большое количество символов для обработки

Еще обратите внимание, что проверка выполняется только при попытке сохранить новую запись.

Ольга,

"Раловец Ольга" написал:Что значит повторного? Вы, наверное, не убрали из скрипта датасета то, что внесли до того, как я посоветовала редактировать scr_ContactEdit.
Да, действительно не удалил.
[br]
"Раловец Ольга" написал:Судя по тому, что написал Виталий, должно считать их одним и тем же.
Походу не считает, даже если дубль записывается в то же поле "средство связи".
[br]
"Раловец Ольга" написал:Еще обратите внимание, что проверка выполняется только при попытке сохранить новую запись.
Так оно и есть, тем не менее, что-то здесь с тире и пробелами не так.

______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

В качестве примера:
Есть карточка, с телефонов 379007 в поле "Средство связи 1".
Если я создаю другую карточку с телефоном 379-007 или 379 007 в этом же поле, то система не воспринимает это как дубль и карточку сохраняет.
______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

Добрый день!

Проверил - считает дублями записи 2233445 и 22-33-44-5!
У Вас 6-ти значные номера телефонов? Попробуйте заменить

CreateSPParameter(Parameters, 'NumOfDigits', pdtInteger, 7); //количество символов

На:

CreateSPParameter(Parameters, 'NumOfDigits', pdtInteger, 6); //количество символов

--
www.it-sfera.com.ua

Как-то странно отрабатывает:
1) Не различает 123456, 1-23-456, 12 34 56. При этом абсолютно одинаковые номера отлавливает.
2) Если одно или более средств связи остаются пустыми, срабатывает как на дубль;
3) Не проверяет средства связи не отображенные в карточке.

"Виталий Ковалишин aka samael" написал:У Вас 6-ти значные номера телефонов? Попробуйте заменить

В системе хранятся номера с различным кол-вом знаков, каким тогда задавать параметр NumOfDigits?

"Виталий Ковалишин aka samael" написал:Это быстрое решение, для большего удобства пользования, оно еще нуждается в доработке...

Я написал как пример реализации. Вы можете внести свой вклад в развитие идеи и ее совершенствования (Доработки - читали? А никто так ничего и не предложил...)

"Виталий Ковалишин aka samael" написал:вместо баловства - могли бы и помочь

Welcome to OpenSource :) Развиваем!

--
www.it-sfera.com.ua

Подтверждаю слова Олега.
Все аналогично
______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

"Виталий Ковалишин aka samael" написал:Я написал как пример реализации. Вы можете внести свой вклад в развитие идеи и ее совершенствования

Сорь, упустил этот момент.:biggrin:

У меня предварительно получилось что-то такое:
1) Хранимка

CREATE PROCEDURE [dbo].[tsp_CheckForDoublet] (
        @ID AS uniqueidentifier,
        @Communication1 AS nvarchar(250),
        @Communication2 AS nvarchar(250),
        @Communication3 AS nvarchar(250),
        @Communication4 AS nvarchar(250),
        @ReturnResult AS int = 0 OUTPUT
        )
AS
 
SET @ReturnResult = 0
SET @Communication1 = REPLACE(REPLACE(@Communication1, '-', ''), ' ', '')
SET @Communication2 = REPLACE(REPLACE(@Communication2, '-', ''), ' ', '')
SET @Communication3 = REPLACE(REPLACE(@Communication3, '-', ''), ' ', '')
SET @Communication4 = REPLACE(REPLACE(@Communication4, '-', ''), ' ', '')
 
IF EXISTS (SELECT [ID] FROM [dbo].[tbl_ContactCommunication] WHERE 
[ContactID] <> @ID AND (  
REPLACE(REPLACE([Number], '-', ''), ' ', '') IN (@Communication1, @Communication2, @Communication3, @Communication4)
) ) SET @ReturnResult = 1
 
RETURN
GO

2) Функция:

function CheckContactCommunication(Dataset) {
	var Parameters = CreateSPParameters();
	CreateSPParameter(Parameters, 'ID', pdtGUID, Dataset.ValAsGUID('ID'));
	CreateSPParameter(Parameters, 'Communication1', pdtString, 
		Dataset.ValAsStr('Communication1'));
	CreateSPParameter(Parameters, 'Communication2', pdtString, 
		Dataset.ValAsStr('Communication2'));
	CreateSPParameter(Parameters, 'Communication3', pdtString,
		Dataset.ValAsStr('Communication3'));
	CreateSPParameter(Parameters, 'Communication4', pdtString,
		Dataset.ValAsStr('Communication4'));
	CreateSPParameter(Parameters, 'isDoublet', pdtInteger, 0);
    Parameters.ItemsByName('isDoublet').ParamType = 1;
    var SQLText = 'exec dbo.tsp_CheckForDoublet :ID,:Communication1,:Communication2,:Communication3,:Communication4,:isDoublet OUTPUT';
    Connector.DBEngine.ExecuteCustomSQL(SQLText, Parameters);
    var isDoublet = Parameters.ItemsByName('isDoublet').ValAsInt;   
    if (isDoublet == 1) {
        ShowWarningDialog('Дублируются средства связи!');
        return false;
    }
    return true;
}

3)Вызов функции:

function dlDataOnDatasetBeforePost(Dataset, DoPost) {
	if (!CheckContactCommunication(Dataset)) {
		DoPost.Value = false;
	}
}

Возник вопрос:
Если в процедуру добавляю еще один параметр, то выпадает ошибка:
Formal parameter 'такой-то' was defined as OUTPUT but the actual parameter not declared OUTPUT.
На сколько я смог понять, это связанно с типом параметра, но не могу понять как. Может кто-то сталкивался?

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

Parameters.ItemsByName('isDoublet').ParamType = 1;

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

По умолчанию тип входящий. Может, каким-то образом порядок повлиял?

Действительно. Поставил параметр в описании первым и все заработало.:confused:

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

Руслан, думаю, адаптировать проверку дублей в базовой версии для реализации данного функционала будет не совсем верно, так как он является универсальным для поиска по одному полю. Данный пример реализации таковым не является, так как с физической точки зрения поля Communication1 и Communication4 отличаются между собой так же, например, как Communication1 и Name.

Решить данную задачу можно, например, с помощью отдельного действия. Вначале придётся немного переработать хранимую процедуру, чтобы она возвращала все ID дубликатов для определённой записи. Например, так:

CREATE PROCEDURE [dbo].[tsp_CheckForDoublet]
			@ContactID uniqueidentifier,
			@NumOfDigits int
AS
begin
 
	declare @SecondID uniqueidentifier
	declare @ContactName nvarchar(250)
	declare @SecondName nvarchar(250)
	declare @Communication1 nvarchar(250)
        	declare @Communication2 nvarchar(250)
        	declare @Communication3 nvarchar(250)
        	declare @Communication4 nvarchar(250)
	create table #tmp (
		ID uniqueidentifier,
		ParentRecordID uniqueidentifier,
		ChildRecordID uniqueidentifier,
		ParentRecordValue nvarchar(250),
		ChildRecordValue nvarchar(250))
 
 
	SELECT @ContactName = [Name], @Communication1 = RIGHT(REPLACE(REPLACE([Communication1], '-', ''), ' ', ''), @NumOfDigits),
		@Communication2 = RIGHT(REPLACE(REPLACE([Communication2], '-', ''), ' ', ''), @NumOfDigits),
		@Communication3 = RIGHT(REPLACE(REPLACE([Communication3], '-', ''), ' ', ''), @NumOfDigits),
		@Communication4 = RIGHT(REPLACE(REPLACE([Communication1], '-', ''), ' ', ''), @NumOfDigits) FROM tbl_Contact
	WHERE [ID] = @ContactID
 
 
	declare c_Contact cursor for
		SELECT [ID], Name FROM [dbo].[tbl_Contact] WHERE
		[ID] <> @ContactID AND (  
		(RIGHT(REPLACE(REPLACE([Communication1], '-', ''), ' ', ''), @NumOfDigits) IN (@Communication1, @Communication2, @Communication3, @Communication4) and RIGHT(REPLACE(REPLACE([Communication1], '-', ''), ' ', ''), @NumOfDigits) <> '')
		OR
		(RIGHT(REPLACE(REPLACE([Communication2], '-', ''), ' ', ''), @NumOfDigits) IN (@Communication1, @Communication2, @Communication3, @Communication4) and RIGHT(REPLACE(REPLACE([Communication2], '-', ''), ' ', ''), @NumOfDigits) <> '')
		OR
		(RIGHT(REPLACE(REPLACE([Communication3], '-', ''), ' ', ''), @NumOfDigits) IN (@Communication1, @Communication2, @Communication3, @Communication4) and RIGHT(REPLACE(REPLACE([Communication3], '-', ''), ' ', ''), @NumOfDigits) <> '')
		OR
		(RIGHT(REPLACE(REPLACE([Communication4], '-', ''), ' ', ''), @NumOfDigits) IN (@Communication1, @Communication2, @Communication3, @Communication4) and RIGHT(REPLACE(REPLACE([Communication4], '-', ''), ' ', ''), @NumOfDigits) <> '')
		)
 
	open c_Contact
	while 1 = 1
	begin
		fetch next from c_Contact into @SecondID, @SecondName
		if @@fetch_status = -1 break
		if @@fetch_status = -2 continue
 
		insert into #tmp (ID, ParentRecordID, ChildRecordID, ParentRecordValue, ChildRecordValue)
		values (NewID(), @ContactID, @SecondID, @ContactName, @SecondName)
	end
 
	close c_Contact
	deallocate c_Contact
 
	select distinct ParentRecordID, ChildRecordID, ChildRecordValue from #tmp
	--where ParentRecordID = @ContactID
 
	drop table #tmp
 
end
GO

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

Олег Лабьяк,
разработчик,
3-я линия Службы поддержки Terrasoft.

Доброго времени суток!
Возникла необходимость реализовать поиск дублей в уже введенных контактах.
Подскажите пожалуйста, т.к. я новичок еще в доработках CRM, какие изменения возможно внести в уже готовый сервис поиска дублей для решения поставленной задачи или есть какое-то альтернативное решение?

Здравствуйте,
Подскажите какую версию Terrasoft вы используете ?
Ознакомьтесь, пожалуйста, с вложением "Настройка поиска дублей", такова реализация в 3.4.0

Здравствуйте.
Используется Terrasoft Press версии 3.3.0.45.
С вложением ознакомился, но видимо данный функционал в имеющейся версии не представлен.

Хатемкин В.А.
ОАО "Пилот-Медиа"

Функционал поиска дублей в существующих записях полноценно реализован начиная с версии 3.3.2

Для 3.3.0 его можно только дорабатывать вручную, а это довольно серьезный объем работы.

Алгоритм таков:

1. Создать зранимую процедуру поиска дублей в БД;
2. Создать интерфейсную часть в Terrasoft, которая позволила бы пользователям задавать настройки поиска и слияния дублей;
3. Интегрировать поиск дублей в систему.

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

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

Добрый день! В базовой версии имеется проверка на дубли Контактов и Контрагентов. Появилась необходимость в такой функциональности для проверки дублей в разделе "Продукты" - по имени продукта. Вопрос: возможно ли дописать своими силами еще такую проверку и насколько ресурскоёмко это будет? Заранее спасибо!

Нравится

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

Здравствуйте!
Мы проанализировали Ваш запрос и можем Вам сообщить следующее.
На самом деле Вы можете реализовать проверку дублирующихся значений в разделе продуктов. Проверку Вы можете осуществлять например, на нажатию на кнопку "ОК" карточки продукта. А именно, Вам необходимо добавить в запрос на выборку новый фильтр по названию продукта. Затем в обработчике события нажатия на кнопку "ОК" карточки продукта, необходимо "включить фильтр" (вызов функции ApplyDatasetFilter), а затем реализовать проверку наличия аналогичной записи и появление сообщения о наличии дублирующейся записи в датасете.
Как Вы наверное успели заметить, в приложении Terrasoft CRM настройка поиска дублирующихся значений по контактам и контрагентам осуществляется путем вызова окна. В том случае если Вам необходимо реализовать поиск дублирующихся значений аналогичным образом по продуктам, то это является значительной доработкой конфигурации приложения, реализовать которую у Вас есть возможность путем проектного решения специалистами отдела разработки Terrasoft.

Желаем удачи!

Спасибо за ответ! Пошёл вторым путём, доработал поиск дублирующихся записей

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

А нельзя ли поподробней объяснить реализацию первого метода? Необходимо фильтровать сразу по двум параметрам.
Не совсем понятно, как будет происходить фильтрация записей, если датасет уже отфильтрован и в нем находится только одна запись(которая только что была добавлена). Или я что-то путаю?

Спасибо!!!

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

Для реализации необходимой Вам функциональности требуется выполнить следующее:
1. В запросе на выборку SelectQuery раздела "Продукты" создать два фильтра сравнения CompareFilter по двум полям и с использованием необходимых параметров.
2. Затем в обработчике нажатия кнопки OK карточки Вам необходимо открыть новый датасет без фильтров (используя GetNewItemByUSI ('USI датасета продуктов')).
3. После открытия датасета необходимо применить созданные фильтры (ApplyDatasetFilter для каждого фильтра).
4. Затем открыть датасет Dataset.Open и проверить наличие в нем записей. По полученным результатам выполнить уже их обработку (либо запретить ввод значения, либо разрешить).

Terrasoft Support Team

Таким образом не удалось сделать, тк фильтры не применялись (запросы в базу не отправлялись).
Пошли другим путем. Использовали вот такую функцию:

function GetDatasetFilteredByParams(Dataset, Param1Name, Param1Val, Param2Name, Param2Val) {
var SelectQuery = Dataset.SelectQuery;
var PrimarySelect = GetSelectQueryPrimarySelect(SelectQuery);
EnableAllFilters(PrimarySelect.Filters, false);
EnableFilter(PrimarySelect.Filters, Param1Name, true);
EnableFilter(PrimarySelect.Filters, Param2Name, true);
SetParameterValue(SelectQuery.Parameters, Param1Name, Param1Val);
SetParameterValue(SelectQuery.Parameters, Param2Name, Param2Val);
var TempDataset = SelectQuery.Open();
EnableAllFilters(PrimarySelect.Filters, false);
EnableFilter(PrimarySelect.Filters, 'ID', true);
return TempDataset;
}

получилось громоздко, но результатом довольны. Функция вызывается из события BeforePost. Это показалось удобным, поскольку в случае дублирования записи свойству DoPost присваиваем false и запись в базу не идет.
Единственный вопрос, необходимо ли закрывать TempDataset? если да, то когда?

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

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

Terrasoft Support Team

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