简体   繁体   English

SQL Server存储过程 - 检查是否存在任何记录,如果不存在则插入

[英]SQL Server stored procedure - check if ANY records exist, and insert if not

Question: 题:

Is it possible to send a single call to SQL Server 2012, with an array of specified of some time, so that the database server can check if any of those elements exist, and if not, insert them into the table? 是否可以使用指定的一段时间向SQL Server 2012发送单个调用,以便数据库服务器可以检查是否存在任何这些元素,如果不存在,则将它们插入表中?

Problem: 问题:

The problem I am facing, is that I have a scheduled job (calling an API), that returns about 400 records each time it is called. 我面临的问题是,我有一个预定的作业(调用API),每次调用它都会返回大约400条记录。 This job is called every minute, and the slowest thing, is that for each result, I am checking to see if the Database already has the record, and if it doesn't then I am doing an INSERT. 这个工作每分钟调用一次,最慢的是,对于每个结果,我正在检查数据库是否已经有记录,如果没有,那么我正在进行INSERT。

Example: API returns 400 people. 示例:API返回400人。 I want to be able to send the ID of each person, as well as Name, etc. in a single call to the DB. 我希望能够在一次调用数据库时发送每个人的ID以及姓名等。 The DB should then check and see if the ID exists (for each Person), and if not, do an INSERT. 然后,DB应该检查并查看ID是否存在(对于每个Person),如果不存在,则执行INSERT。

Feedback: 反馈:

I would also like advice on whether or not this is actually good practice, or if there is a better way of handling this. 我还想了解这是否是一个好的做法,或者是否有更好的方法来处理这个问题。

As per my understanding, the job return the result to an application (C#), then this application is calling the DB for each record. 根据我的理解,作业将结果返回给应用程序(C#),然后此应用程序为每个记录调用DB。

The Answer is yes, you can send multiple records (datatable) to the sql server in one patch then the sql server will process all these data. 答案是肯定的,你可以在一个补丁中向sql server发送多个记录(datatable),然后sql server将处理所有这些数据。

First in SQL Server, you have to define a table datatype of the format which will be sent from the application to the DB. 首先在SQL Server中,您必须定义将从应用程序发送到DB的格式的表数据类型。

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

Then create your procedure which will use this datatype 然后创建将使用此数据类型的过程

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

Finally call this procedure from your application using your data. 最后使用您的数据从您的应用程序调用此过程。 Here i wrote it using VB.Net but you can rewrite it in C#: 在这里我使用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

You need a way to determine whether or not the record is already in the table. 您需要一种方法来确定记录是否已经在表中。 This requires some sort of comparison. 这需要某种比较。

Once you have that, you can construct a query like this: 完成后,您可以构建如下查询:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM