Лучший способ объединить 3 столбца вместе, чтобы создать уникальный столбец базы данных? Спусковой крючок? - PullRequest
0 голосов
/ 23 января 2019

У меня есть таблица предметов, как это выглядит.

ItemsTbl
id -PK
BrandId- int (FK)
LocationId- int (FK)
Field3 - nvarchar(Max) Json string containing a jsonKey called itemNumber

Сейчас я создаю импортер (берет файл Excel), который будет массово импортировать 1000 элементов за раз. Но прежде чем я смогу вставить их, я должен проверить, существуют ли они в базе данных.

Если это так, обновите, если не новую запись.

В идеальном мире, я бы хотел, чтобы клиент имел в своем файле excel поле с уникальным номером (через свой pk в БД или что-то еще) и сохранил его в моем БД. Если он совпадает с тем, что есть в нашей базе данных, обновите его, иначе он новый.

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

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

Таким образом, новая идея состоит в том, чтобы в базе данных появился новый столбец, который будет объединять BrandId + LocationId + itemNumber, а затем каждый раз, когда файл проходит, объединять эти 3 поля из файла Excel и выполнять проверку.

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

Полагаю, триггер был бы лучшим, чтобы остановить это, но я не уверен, возможно ли иметь триггер в поле, содержащем json.

Я использую EF Core, Sql Server 2017.

Причина, по которой я не пытаюсь сделать что-то подобное

select * from ItemsTbl where BrandId = 1 AND LocationId = 1 And JSON_VALUE('Field3',$.itemNumber) = 12345

потому что, как я уже сказал, я получаю 1000 предметов одновременно, я не хочу делать 1000 отдельных запросов. Я скорее делаю 1 запрос с предложением in, затем перебираю результаты и обновляю.

1 Ответ

0 голосов
/ 23 января 2019

Я предлагаю вам использовать стандартные библиотеки ADO.NET для этого.

Создайте процедуру, которая получает параметр табличного значения в качестве входных данных, и передает ваши объемные данные внутри этого параметра.После этого вы можете использовать функцию MERGE для выполнения операций обновления и вставки (UPSERT) одним вызовом.

/* Create a table type. */  
CREATE TYPE SourceTableType AS TABLE   
( BrandId INT  
, LocationId INT
, ItemNumber INT
, ...
);  
GO 


CREATE PROCEDURE dbo.usp_InsertTvp  
@Source SourceTableType READONLY  
    AS        
    MERGE INTO Table1 AS Target  
    USING @Source As Source 
      ON Target.BrandId = Source.BrandId and
         Target.LocationId = Source.LocationId and
         Target.ItemNumber = Source.ItemNumber  
    WHEN MATCHED THEN  
    UPDATE SET OtherParam = Source.OtherParam  
    WHEN NOT MATCHED BY TARGET THEN  
    INSERT (BrandId, LocationId, ItemNumber, OtherParam) VALUES (BrandId, LocationId, ItemNumber, OtherParam) ; 

На стороне .Net Side необходимо использовать

using (connection)  
{  
  // Create a DataTable with the modified rows.  
  DataTable myTable = ...;  

  // Define the INSERT-SELECT statement.  
  string sqlInsert = "dbo.usp_InsertTvp"  

  // Configure the command and parameter.  
  SqlCommand mergeCommand = new SqlCommand(sqlInsert, connection);  
  mergeCommand.CommandType = CommandType.StoredProcedure;
  SqlParameter tvpParam = mergeCommand.Parameters.AddWithValue("@Source", myTable);  
  tvpParam.SqlDbType = SqlDbType.Structured;  
  tvpParam.TypeName = "dbo.SourceTableType";  

  // Execute the command.  
  insertCommand.ExecuteNonQuery();  
}  

PS: код не проверен, могут возникнуть синтаксические проблемы.


Синтаксис объединения

MERGE  [ INTO ] <target_table> [ AS ] table_alias
USING <table_source>   
  ON <merge_search_condition>  
WHEN MATCHED [ AND <clause_search_condition> ]  
    THEN <merge_matched> ] [ ...n ]  
[ WHEN NOT MATCHED [ BY TARGET ] [ AND <clause_search_condition> ]  
    THEN <merge_not_matched> ]  

, где

merge_matched>::=  
{ UPDATE SET <set_clause> | DELETE }  

<merge_not_matched>::=  
{  
    INSERT [ ( column_list ) ]   
        { VALUES ( values_list )  
        | DEFAULT VALUES }  
}  

Ссылка

...