2015-11-03 2 views
3

Вопрос:SQL Server - проверить, существует ли какая-либо запись, и вставить, если не

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

Проблема:

Проблема я столкнулся, что у меня есть запланированное задание (вызов к API), который возвращает около 400 записей каждый раз, когда он вызывается. Это задание вызывается каждую минуту, а самое медленное - это то, что для каждого результата я проверяю, есть ли в базе данных запись, а если нет, то я делаю INSERT.

Пример: API возвращает 400 человек. Я хочу иметь возможность отправлять идентификатор каждого человека, а также имя и т. Д. В одном вызове в БД. Затем БД следует проверить и посмотреть, существует ли идентификатор (для каждого человека), а если нет, выполните INSERT.

Обратная связь:

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

+0

ли возможно, что многие из этих вызовов будет ударять дб одновременно? Если нет, вы должны загрузить их в промежуточную таблицу и запустить какой-то «MERGE». Если у вас _will_ есть несколько вызовов (что означает, что вы не можете использовать одну таблицу, поскольку они будут перезаписывать друг друга), посмотрите на «передачу массивов на хранимые процедуры» - http://stackoverflow.com/questions/11102358/how-to -pass-a-array-in-sql-server-stored-procedure –

ответ

3

Согласно моему пониманию, работа вернуть результат в прикладную (C#), то это приложение, призывающее к БД для каждого запись.

Ответ да, вы можете отправить несколько записей (datatable) на сервер sql в одном патче, после чего сервер sql обработает все эти данные.

Сначала в SQL Server вы должны определить тип данных таблицы в формате, который будет отправлен из приложения в БД.

CREATE TYPE YourDataType AS TABLE(
    [Col1] [int] NULL,    [Col2] [int] NULL,     [Col3] [int] NULL,    [Col4] [nvarchar](255) NULL, 
    [Col5] [nvarchar](255) NULL, [Col6] [nvarchar](255) NULL,  [Col7] [nvarchar](255) NULL, [Col8] [nvarchar](255) NULL, 
    [Col9] [nvarchar](255) NULL, [Col10] [nvarchar](255) NULL,  [Col11] [int] NULL,    [Col12] [nvarchar](255) NULL, 
) 
GO 

Затем создать процедуру, которая будет использовать этот тип данных

CREATE PROCEDURE YourProcedureName (@TableVariable YourDataType READONLY, @ScalarParameter nvarchar(255)) 
AS 

BEGIN 
INSERT INTO YourTable WITH (ROWLOCK) (Col1,Col2,Col3,Col4,Col5,Col6,Col7,Col8,Col9,Col10,Col11,Col12) 

    SELECT Col1,Col2,Col3,Col4,Col5,Col6,Col7,Col8,Col9,Col10,Col11,Col12 

    FROM @TableVariable t 
     /*Left Join then where ID is null to make sure the record doesn't exists*/ 
     LEFT JOIN YourTable PR WITH (NOLOCK) 
           ON PR.ID = @ScalarParameter 
           AND PR.Col1 = t.Col1  
           AND PR.Col2 = t.Col2 
           ...... 
     WHERE PR.ID IS NULL 
END 

Наконец вызвать эту процедуру из приложения, используя данные. Здесь я написал его с помощью VB.Net, но вы можете записать его в C#:

Dim connectionString As StringBuilder = New StringBuilder() 
    connectionString.AppendFormat("Server={0};", ????) 
    connectionString.AppendFormat("Database={0};", ???) 
    connectionString.AppendFormat("User ID={0};", ????) 
    connectionString.AppendFormat("Password={0}", ????) 

    Dim InputTable As DataTable = New DataTable("YourDataType") 
    InputTable = ds.Tables(0).Copy() 
    InputTable.TableName = "YourDataType" 

    Try 
     Using conn As New SqlClient.SqlConnection(connectionString.ToString()) 
      Using comm As New SqlClient.SqlCommand() 
       Dim insertedRecords As Int32 

       comm.Connection = conn 
       comm.CommandText = "YourProcedureName" 
       comm.CommandType = CommandType.StoredProcedure 
       Dim TableVariable As SqlClient.SqlParameter = comm.Parameters.Add("@TableVariable", SqlDbType.Structured) 
       TableVariable.Direction = ParameterDirection.Input 
       TableVariable.Value = InputTable 
       Dim ScalarVariable As SqlClient.SqlParameter = comm.Parameters.Add(@ScalarParameter, SqlDbType.VarChar) 
       ScalarVariable.Direction = ParameterDirection.Input 
       ScalarVariable.Value = ??? 

       conn.Open() 
       insertedRecords = comm.ExecuteNonQuery() 
       If (insertedRecords > 0) Then 
        _Changed = True 
       End If 
       conn.Close() 

       comm.Dispose() 
       conn.Dispose() 
      End Using 
     End Using 
    Catch ex As Exception 
     Return False 
    End Try 
    Return True 
+0

Вы превзошли себя, сэр. Спасибо! – blgrnboy

+0

При создании процедуры SQL Management Studio имеет ошибку в первой строке, в которой говорится: «CREATE PROCEDURE должно быть единственным оператором в пакете». Есть ли определенный порядок, в котором это нужно сделать? – blgrnboy

+0

@blgrnboy: Напишите Перейти до и после него –

2

Вам нужен способ определить, уже ли запись находится в таблице. Для этого требуется какое-то сравнение.

После того, как вы есть, что вы можете построить запрос следующим образом:

insert into t(. . .) 
    select v.* 
    from values ((v1), (v2), . . .) as v(vcol) 
    where not exists (select 1 from v where v.vcol = t.<whatever>); 
+0

Может быть слияние будет более выразительным и будет использоваться, если существует 'MERGE INTO test AS trg ИСПОЛЬЗОВАНИЕ (VALUES (@ v1), (@ v2), (@ v3)) AS src (Newt) ON trg.t = src.Newt КОГДА НЕ СООТВЕТСТВУЕТ ТОЛЬКО ВСТАВКИ (t) ЗНАЧЕНИЯ (NewT); ' – vitalygolub

+0

@vitalygolub. , ,Это, наверное, я, но я почти никогда не считаю, что «слияние» легче читать. –