在插入之前删除 SQL 服务器 table 中的记录

Deleting Records in SQL server table prior to insert

我有一个 excel 工作簿,它是一个项目计划模板,PM 填写信息并将其加载到 sql 数据库中。目前,如果通过批处理加载两个 tables(1 有 1 行数据,另一个有多条记录),则该过程。我正在将其更改为通过 vba 从 excel 直接插入到 sql 服务器。我有插入工作,但每个 table 都有一个项目 ID 列,它是 PK。 pm 可能会多次更新和保存此文件。 tables 更新为最新的保存信息。我通过在我的代码中添加删除语句然后插入更新的记录来解决这个问题。这对于具有 1 条记录的 table 非常有效,但我无法使具有多条记录的 table 起作用。它删除记录并通过插入的第一个循环,然后返回到删除并删除记录。

我附上了多次 table 删除和插入的代码。有人可以告诉我我做错了什么吗?

Public Sub exportprojdetaildata()

Dim stSQL As String
Dim conn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim strConn As String
Dim iRowNo As Integer
Dim targetedFieldNames As Variant
Dim rowData As Variant
Dim lastrow As Long
Dim sql As String
Dim i As Integer
Dim cvt As Double
Dim aField As String
Dim compare As Variant
Dim value As Variant
Dim dvalue As Long


With Sheets("Data")

    lastrow = .Range("A:A").Find(what:="*", SearchDirection:=xlPrevious, SearchOrder:=xlByRows).Row
    'Open a connection to SQL Server
  conn.Open _
    "Provider=SQLOLEDB;Data Source=PWIRTPAUDD1HV8;Initial Catalog=STAR;User Id=STAR_USER;Password=dcistarrtp"

    'Skip the header row
    iRowNo = 2

     targetedFieldNames = Join(WorksheetFunction.Transpose(wks_TargetFieldNames.Range("targetedFieldNames").value), "," & vbNewLine)

     Do While iRowNo <= lastrow
        rowData = wks_BackgroundData.Range("A" & iRowNo & ":AV" & iRowNo).value

                compare = wks_BackgroundData.Range("AV2").value


        'Generate and execute sql statement to import the excel rows to SQL Server table
            With rs
                .ActiveConnection = conn
                .Open "Select proj_id from dbo.STAR_DC_INITIAL_ProjectDetails_ExcelDevCopy where proj_id = " & compare

                wks_BackgroundData.Range("BA2").CopyFromRecordset rs


                .Close
            End With

                       value = wks_BackgroundData.Range("BA2").value

                If compare = value Then
                        sql = "delete from dbo.STAR_DC_INITIAL_ProjectDetails_ExcelDevCopy where proj_id = " & value


                conn.Execute sql
                Else

                sql = "insert into dbo.STAR_DC_INITIAL_ProjectDetails_ExcelDevCopy ("
                sql = sql & targetedFieldNames
    '            Debug.Print sql
                sql = sql & ") values (" & vbNewLine
    '            Debug.Print sql

        'couldn't do transpose since rowData represents a row, not a column
        For i = 1 To UBound(rowData, 2)
          aField = Replace(rowData(1, i), "'", "''")
      'escape single quotes
            Select Case i
                Case 1, 6, 16, 17, 23 To 47
                 '   cvt = CDbl(aField)
                    If aField = vbNullString Then
                        sql = sql & "Null," & vbNewLine
                    Else
                        sql = sql & aField & "," & vbNewLine
                    End If
                Case 2 To 5, 7 To 15, 18 To 22
                    sql = sql & "'" & aField & "', " & vbNewLine
                Case 48
                    If aField = vbNullString Then
                        sql = sql & "Null"
                    Else
                        sql = sql & aField
                    End If


                End Select
        Next i
       sql = sql & ");"
        'sql = sql & "');"

      ' End If

      conn.Execute sql

        iRowNo = iRowNo + 1

    Loop

  End If      


    conn.Close
    Set conn = Nothing


End With

结束子

避免使用 VBA 进行新的开发工作。如果您需要不断获取此 Excel 文档并将其插入 SQL 服务器数据库,则 use SSIS and some C# to easily make it a scheduled task via the SQL Agent, or simply do as the screen shot below suggests, which is a no-code and easily configurable import of flat files / database tables into SQL Server. Lastly, from a usability standpoint, There are many better methods to track Excel sheets or forms data (SharePoint, Excel 2013, Access, cloud/on premise drives) or using an internal WordPress distribution with some plugins like WP-document revisions

没有看到你试图保存的数据很难确定,但我怀疑你有逻辑错误。

rowData 的值是在循环中动态建立的。这是正确的。

rowData = wks_BackgroundData.Range("A" & iRowNo & ":AV" & iRowNo).value

但是 compare 和 value 的值总是从循环内的相同位置读取。所以delete语句会被反复执行

compare = wks_BackgroundData.Range("AV2").value
value = wks_BackgroundData.Range("BA2").value

不应该动态读取比较和值吗?

compare = wks_BackgroundData.Range("AV" & iRowNo).value
value = wks_BackgroundData.Range("BA" & iRowNo).value

您应该将 delete 语句移到循环之外,以确保它只执行一次

或者

你应该保留一个标志,表明删除已经被执行,并且不再执行它。

hasExecuted = false <- OUTSIDE THE LOOP
...
...
If compare = value and hasExecuted = false Then
    sql = "delete from dbo.STAR_DC_INITIAL_ProjectDetails_ExcelDevCopy where proj_id = " & value
    conn.Execute sql
    hasExecuted = true
...
...

此外,我认为您不应该使用 IF x=y THEN 删除 ELSE INSERT。不应该是 IF x=y THEN 删除,总是 INSERT。如果是else,则只有记录不存在才会插入,如果删除了记录,则永远不会插入新记录。

希望有点帮助

如上所述,我使用 Spock 添加动态查找比较和值变量的值。一旦我这样做了,我就添加了 hasExecuted 标志。

Public Sub exportprojinfodata()

    Dim stSQL As String
    Dim conn As New ADODB.Connection
    Dim rs As New ADODB.Recordset
    Dim strConn As String
Dim iRowNo As Integer
Dim targetFieldNames As Variant
Dim rowData As Variant
Dim lastrow As Long
Dim sql As String
Dim i As Integer
Dim aField As String
Dim compare As Variant
Dim value As Variant
Dim hasExecuted As String


hasExecuted = False



With Sheets("Data2")

    lastrow = .Range("A:A").Find(what:="*", SearchDirection:=xlPrevious, SearchOrder:=xlByRows).Row
    'Open a connection to SQL Server
   conn.Open _
        "Provider=SQLOLEDB;Data Source=PWIRTPAUDD1HV8;Initial Catalog=STAR;User Id=STAR_USER;Password=dcistarrtp"

    'Skip the header row
    iRowNo = 2

     targetFieldNames = Join(WorksheetFunction.Transpose(wks_TargetFieldNames.Range("TargetFieldNames").value), "," & vbNewLine)



     Do While iRowNo <= lastrow
        rowData = wks_ProjDescription.Range("A" & iRowNo & ":AO" & iRowNo).value


        compare = wks_ProjDescription.Range("B"& iRowNo).value

        'Generate and execute sql statement to import the excel rows to SQL Server table

            With rs
                .ActiveConnection = conn
                .Open "Select proj_id from dbo.STAR_DC_INITIAL_ProjectInfo_ExcelDevCopy where proj_id= " & compare
                wks_ProjDescription.Range("AX2").CopyFromRecordset rs
                .Close
            End With

            value = wks_ProjDescription.Range("AX"& iRowNo).value

            If compare = value And hasExecuted = False Then
                stSQL = "delete from dbo.STAR_DC_INITIAL_ProjectInfo_ExcelDevCopy where proj_id = " & value
                conn.Execute stSQL
                hasExecuted = True
            End If

        sql = "insert into dbo.STAR_DC_INITIAL_ProjectInfo_ExcelDevCopy ("
        sql = sql & targetFieldNames
        sql = sql & ") values (" & vbNewLine

'

        'couldn't do transpose since rowData represents a row, not a column
        For i = 1 To UBound(rowData, 2)
          aField = Replace(rowData(1, i), "'", "''")
                Select Case i
                    Case 1 To 40
                        sql = sql & "'" & aField & "', " & vbNewLine
                    Case 41
                        If aField Like "*,*" Then
                            sql = sql & "'" & """" & aField & """" & vbNewLine
                        Else
                            sql = sql & "'" & aField & "' " & vbNewLine
                        End If
                End Select


        Next i

       sql = sql & ");"
     '   sql = sql & "');"  

      conn.Execute sql

        iRowNo = iRowNo + 1

    Loop

    conn.Close
    Set conn = Nothing

    End With
End Sub