check if SQL field has UNIQUE constraint via ADODB VBA - sql-server

I am writing vba code to update SQLSERVER tables.
I want to check all values for a new record are ok, before actually trying to update them.
How can I check if a field has UNIQUE constrain?
I have tried listing all properties and attributes, but the propertie ISUNIQUE does not show anything, although it is set as such and it produces error when tring to create a new record with duplicate enty in this field
Properties
BASECATALOGNAME = TEBUS_Templates
BASECOLUMNNAME = Nombre del Armario
BASESCHEMANAME =
BASETABLENAME = TBL_FAKOM_ARMARIOS
CLSID =
COLLATINGSEQUENCE =
COMPUTEMODE =
DATETIMEPRECISION =
DEFAULTVALUE =
DOMAINCATALOG =
DOMAINSCHEMA =
DOMAINNAME =
HASDEFAULT =
ISAUTOINCREMENT = Falso
ISCASESENSITIVE = Falso
ISSEARCHABLE = 4
ISUNIQUE =
OCTETLENGTH = 200
KEYCOLUMN = Falso
OPTIMIZE = Falso
Attributes
adFldUnknownUpdatable
FWIW this is the procedure I put together to get the list above:
'2017-05-22 / B.Agullo /
Public Sub showFieldAtributesAndProperties(ByVal f As Field)
'description of sub
Dim p As Variant
Debug.Print f.Name
Debug.Print "Properties"
For Each p In f.Properties
Debug.Print p.Name & " = " & p.Value
Next
Debug.Print Chr(10) & "Attributes"
If ((adFldCacheDeferred And f.Attributes) = adFldCacheDeferred) Then Debug.Print "adFldCacheDeferred"
If ((adFldFixed And f.Attributes) = adFldFixed) Then Debug.Print "adFldFixed"
If ((adFldIsChapter And f.Attributes) = adFldIsChapter) Then Debug.Print "adFldIsChapter"
If ((adFldIsCollection And f.Attributes) = adFldIsCollection) Then Debug.Print "adFldIsCollection"
If ((adFldIsDefaultStream And f.Attributes) = adFldIsDefaultStream) Then Debug.Print "adFldIsDefaultStream"
If ((adFldIsNullable And f.Attributes) = adFldIsNullable) Then Debug.Print "adFldIsNullable"
If ((adFldIsRowURL And f.Attributes) = adFldIsRowURL) Then Debug.Print "adFldIsRowURL"
If ((adFldLong And f.Attributes) = adFldLong) Then Debug.Print "adFldLong"
If ((adFldMayBeNull And f.Attributes) = adFldMayBeNull) Then Debug.Print "adFldMayBeNull"
If ((adFldMayDefer And f.Attributes) = adFldMayDefer) Then Debug.Print "adFldMayDefer"
If ((adFldNegativeScale And f.Attributes) = adFldNegativeScale) Then Debug.Print "adFldNegativeScale"
If ((adFldRowID And f.Attributes) = adFldRowID) Then Debug.Print "adFldRowID"
If ((adFldRowVersion And f.Attributes) = adFldRowVersion) Then Debug.Print "adFldRowVersion"
If ((adFldUnknownUpdatable And f.Attributes) = adFldUnknownUpdatable) Then Debug.Print "adFldUnknownUpdatable"
If ((adFldUnspecified And f.Attributes) = adFldUnspecified) Then Debug.Print "adFldUnspecified"
If ((adFldUpdatable And f.Attributes) = adFldUpdatable) Then Debug.Print "adFldUpdatable"
release:
End Sub
also, for your reference, this is the SQL command to create the table
CREATE TABLE TBL_FAKOM_ARMARIOS(
"ArmarioID" int IDENTITY(1,1) PRIMARY KEY NOT NULL
, "Nombre del Armario" nvarchar(100) UNIQUE NOT NULL
, "Fecha de Alta" dateTime NOT NULL
, "Fecha de Baja" dateTime
, "Usuario de Alta" nvarchar(50) NOT NULL
, "Usuario de Baja" nvarchar(50)
)

You can use the database schema, something like so
Function IX_UNIQUE(strTableName As String, strFieldName As String) as Boolean
Dim c As ADODB.Connection
Dim r As ADODB.Recordset
Set c = New ADODB.Connection
c.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & "C:\TESTsb.accdb" & ";" & _
"Persist Security Info=False;"
c.Open
Set r = New ADODB.Recordset
Set r = c.OpenSchema(adSchemaIndexes, Array(Empty, Empty, strFieldName , Empty, strTableName))
If Not r.EOF Then
IX_UNIQUE = r.Fields("UNIQUE").value
Else
IX_UNIQUE = False
End If
End Function

Related

Import from txt (MS Access 2013) to SQL Server 2016 slow

I have a txt file on my local PC, this has to be check and then line by line uploaded into SQL Server 2016 using a Stored Procedure from MS Access using ADODB. It looks like Access is running always 2 rows fast and then making a short stop.
In MS Access I'm using this function:
Public Function ImportData(FileString As String)
Dim WholeLine As String
Dim cc As Variant
Dim sapPurchaseDocument As String
Dim sapPartNumber As String
Dim sapPartName As String
Dim sapDocumentDate As String
Dim sapSupplier As String
Dim sapPlant As String
Dim sapSLoc As String
Dim sapQuantity As Double
Dim sapUOM As String
Dim sapTargetQuantity As Double
Dim sapDeliveryDate As String
Dim sapPrevQuantity As Double
Dim sapReceivedQuantity As Double
Dim sapIssuedQuantity As Double
Dim sapDeliveredQuantity As Double
Dim sapPurchaseRequisition As String
Dim sapPurchaseRequisitionItem As String
Dim sapCreationIndicatior As String
Dim sapNoOfPositions As Double
Dim totalCount As Integer
Dim sapPurchaseDocumentItem As String
Dim rs As New ADODB.Recordset
Call GetConnection
Set rs.ActiveConnection = myCN
If Right(FileString, 3) = "txt" Then
totalCount = GetRowCount(FileString)
Open FileString For Input As #1
i = 0
Do While Not EOF(1)
Line Input #1, WholeLine
If Left(WholeLine, 3) = "| 4" Then
'Debug.Print WholeLine
cc = Split(WholeLine, "|")
sapPurchaseDocument = Trim(cc(1))
sapPartNumber = Trim(Replace(cc(2), ".", ""))
sapPartName = Trim(Replace(cc(3), "'", ""))
sapDocumentDate = Right(cc(4), 4) & "-" & Mid(cc(4), 4, 2) & "-" & Left(cc(4), 2)
sapSupplier = cc(5)
sapPlant = cc(6)
sapSLoc = cc(7)
sapQuantity = Replace(cc(8), ",", "")
sapUOM = Trim(cc(9))
sapTargetQuantity = Replace(cc(10), ",", "")
sapDeliveryDate = Right(cc(11), 4) & "-" & Mid(cc(11), 4, 2) & "-" & Left(cc(11), 2)
sapPrevQuantity = cc(12)
sapReceivedQuantity = Replace(cc(13), ",", "")
sapIssuedQuantity = Replace(cc(14), ",", "")
sapDeliveredQuantity = Replace(cc(15), ",", "")
sapPurchaseRequisition = Trim(cc(16))
sapPurchaseRequisitionItem = Trim(cc(17))
sapCreationIndicatior = cc(18)
sapNoOfPositions = cc(19)
sapPurchaseDocumentItem = Trim(cc(20))
strSQL = "spInsertUpdateSAPME2M '" & sapPurchaseDocument & "', '" & sapPartNumber & "', '" & sapPartName & "', '" & _
sapDocumentDate & "', '" & sapSupplier & "', '" & sapPlant & "', '" & sapSLoc & "', " & _
sapQuantity & ", '" & sapUOM & "', " & sapTargetQuantity & ", '" & sapDeliveryDate & "', " & _
sapPrevQuantity & ", " & sapReceivedQuantity & ", " & sapIssuedQuantity & ", " & _
sapDeliveredQuantity & ", '" & sapPurchaseRequisition & "', '" & sapPurchaseRequisitionItem & "', '" & _
sapCreationIndicatior & "', '" & sapNoOfPositions & "', '" & sapPurchaseDocumentItem & "'"
rs.Open (strSQL)
DoEvents
End If
i = i + 1
Debug.Print i
Forms!frm_Overview.lblStatus.Caption = "Record " & i & " of " & totalCount & " loaded. Please wait!"
DoEvents
'Refresh
Loop
MsgBox "Import done"
End If
Close #1
End Function
And on SQL Server I have a stored procedure which looks like this:
USE [MOBILEPRINT]
GO
/****** Object: StoredProcedure [dbo].[spInsertUpdateSAPME2M] Script Date: 5/25/2020 11:39:31 AM ******/
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER ON
GO
CHANGE NO ACTION
ALTER PROCEDURE [dbo].[spInsertUpdateSAPME2M]
-- Add the parameters for the stored procedure here
#sapPurchaseDocument varchar(50),
#sapPartNumber varchar(50),
#sapPartName varchar(300),
#sapDocumentDate date,
#sapSupplier varchar(50),
#sapPlant varchar(100),
#sapSLoc varchar(50),
#sapQuantity float,
#sapUOM varchar(50),
#sapTargetQuantity float,
#sapDeliveryDate date,
#sapPrevQuantity float,
#sapReceivedQuantity float,
#sapIssuedQuantity float,
#sapDeliveredQuantity float,
#sapPurchaseRequisition varchar(50),
#sapPurchaseRequisitionItem varchar(50),
#sapCreationIndicatior varchar(50),
#sapNoOfPositions varchar(50),
#sapPurchaseDocumentItem varchar(50)
AS
BEGIN TRANSACTION
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #RESULT int
DECLARE #UPDATE_CHECK int
DECLARE #UpdateDate datetime = GetDate()
BEGIN
SELECT #RESULT = COUNT(sapPurchaseDocument) FROM SAP_ME2M WHERE sapPurchaseDocument = #sapPurchaseDocument AND sapPartNumber = #sapPartNumber
IF ISNULL(#RESULT,0) = 0
BEGIN
INSERT INTO SAP_ME2M (
sapPurchaseDocument,
sapPartNumber,
sapPartName,
sapDocumentDate,
sapSupplier,
sapPlant,
sapSLoc,
sapQuantity,
sapUOM,
sapTargetQuantity,
sapDeliveryDate,
sapPrevQuantity,
sapReceivedQuantity,
sapIssuedQuantity,
sapDeliveredQuantity,
sapPurchaseRequisition,
sapPurchaseRequisitionItem,
sapCreationIndicatior,
sapNoOfPositions,
ChangeDate,
sapPurchaseDocumentItem)
VALUES
(#sapPurchaseDocument, #sapPartNumber, #sapPartName, #sapDocumentDate, #sapSupplier, #sapPlant,
#sapSLoc, #sapQuantity, #sapUOM, #sapTargetQuantity, #sapDeliveryDate, #sapPrevQuantity,
#sapReceivedQuantity, #sapIssuedQuantity, #sapDeliveredQuantity, #sapPurchaseRequisition,
#sapPurchaseRequisitionItem, #sapCreationIndicatior, #sapNoOfPositions, #UpdateDate, #sapPurchaseDocumentItem)
END
ELSE
SELECT #UPDATE_CHECK = COUNT(*) FROM SAP_ME2M WHERE
sapPurchaseDocument = #sapPurchaseDocument AND
sapPartNumber = #sapPartNumber AND
sapPartName = #sapPartName AND
sapDocumentDate = #sapDocumentDate AND
sapSupplier = #sapSupplier AND
sapPlant = #sapPlant AND
sapSLoc = #sapSLoc AND
sapQuantity = #sapQuantity AND
sapUOM = #sapUOM AND
sapTargetQuantity = #sapTargetQuantity AND
sapDeliveryDate = #sapDeliveryDate AND
sapPrevQuantity = #sapPrevQuantity AND
sapReceivedQuantity = #sapReceivedQuantity AND
sapIssuedQuantity = #sapIssuedQuantity AND
sapDeliveredQuantity = #sapDeliveredQuantity AND
sapPurchaseRequisition = #sapPurchaseRequisition AND
sapPurchaseRequisitionItem = #sapPurchaseRequisitionItem AND
sapCreationIndicatior = #sapCreationIndicatior AND
sapNoOfPositions = #sapNoOfPositions AND
sapPurchaseDocumentItem = #sapPurchaseDocumentItem
IF #UPDATE_CHECK = 0
BEGIN
UPDATE SAP_ME2M SET
sapPartName = #sapPartName ,
sapDocumentDate = #sapDocumentDate ,
sapSupplier = #sapSupplier ,
sapPlant = #sapPlant ,
sapSLoc = #sapSLoc ,
sapQuantity = #sapQuantity ,
sapUOM = #sapUOM ,
sapTargetQuantity = #sapTargetQuantity ,
sapDeliveryDate = #sapDeliveryDate ,
sapPrevQuantity = #sapPrevQuantity ,
sapReceivedQuantity = #sapReceivedQuantity ,
sapIssuedQuantity = #sapIssuedQuantity ,
sapDeliveredQuantity = #sapDeliveredQuantity ,
ChangeDate = #UpdateDate
WHERE
sapPartNumber = #sapPartNumber AND
sapPartName = #sapPartName AND
sapDocumentDate = #sapDocumentDate AND
sapSupplier = #sapSupplier AND
sapPlant = #sapPlant AND
sapSLoc = #sapSLoc AND
sapPurchaseDocumentItem = #sapPurchaseDocumentItem
END
END
COMMIT TRANSACTION WITH (DELAYED_DURABILITY = ON);
I have to upload around 30000 Records which takes more then an hour at the moment.
If you have suggestions, please let me know.
For fast data transfer, use a disconnected recordset with batch operations enabled.
Dim conn As ADODB.Connection
Call GetConnection
Set conn = myCN
Dim rs As New ADODB.Recordset
rs.CursorLocation = adUseClient
rs.Open "Table1", conn, adOpenForwardOnly, adLockBatchOptimistic
'Disconnect
Set rs.ActiveConnection = Nothing
Dim i As Long
For i = 1 To 3000
rs.AddNew
rs.Fields(1) = i
Next
'Reconnect
Set rs.ActiveConnection = conn
'Batch insert
rs.UpdateBatch
Debug.Print Now()
For me, this executes in 2 seconds, but it highly depends on the location of SQL server.
Then, process further on the data set when uploaded. Processing on a per-record basis is usually going to be slow.

VBA to push data into a database

I have a data table that has just a few columns: GLID, Metric Category, Amount, and Metric Date. The way the data is organized on the excel file I need to use is like a matrix as so:
The date columns are the metric date and the numbers below them are the amounts. As you can see for each date there is some amount that pertains to a particular metric category and in some cases a GLID. Now what I need to do in VBA is push the data into the format as so
GLID Metric Category Amount Metric Date
5500 Property Tax-5500 -8 3/31/2020
5500 Property Tax-5500 -8 4/30/2020
So on and so forth. I am completely new to VBA so this particular task is daunting and challenging for me and thus why I made a post here. If anyone has some suggestions I would greatly appreciate it.
So far this is the setup I have in VBA:
Sub second_export()
Dim sSQL As String, sCnn As String, sServer As String
Dim db As Object, rs As Object
sServer = "CATHCART"
sCnn = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=True;Initial Catalog=Portfolio_Analytics;Data Source=" & sServer & ";" & _
"Use Procedure for Prepare=1;Auto Translate=True;Packet Size=4096;"
Set db = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
If db.State = 0 Then db.Open sCnn
End Sub
Note For Further Clarification:
The number of columns is 36 and the number of rows is 46 in the excel file. For the categories that do not have a GLID then we can push NULL if needed.
I can push data into the database when its simply and insert but I have to pivot the data such that the GLID and Metric category are repeated for their associated dates and amounts.
First create a sheet of data to upload
Option Explicit
Sub CreateDataSheet()
Dim wb As Workbook, ws As Worksheet, wsData As Worksheet, header As Variant
Dim iLastRow, iLastCol, dt As Variant, iOutRow
Set wb = ThisWorkbook
Set ws = wb.Sheets("Sheet1") ' the matrix sheet
Set wsData = wb.Sheets("Sheet2") ' sheet to hold table data
wsData.Cells.Clear
wsData.Range("A1:D1") = Array("GLID", "Metric Category", "Amount", "Metric Date")
' get header
iLastCol = ws.Cells(1, Columns.Count).End(xlToLeft).Column
iLastRow = ws.Cells(Rows.Count, 1).End(xlUp).Row
header = ws.Range(ws.Cells(1, 3), ws.Cells(1, iLastCol))
'Debug.Print iLastRow, iLastCol, UBound(header, 2)
Dim r, c
iOutRow = 2
For r = 2 To iLastRow
For c = 1 To UBound(header, 2)
'Debug.Print r, header(1, c), ws.Cells(r, c + 2)
With wsData.Cells(iOutRow, 1)
.Offset(0, 0) = ws.Cells(r, 1)
.Offset(0, 1) = ws.Cells(r, 2)
.Offset(0, 2) = ws.Cells(r, c + 2)
.Offset(0, 3) = header(1, c)
End With
iOutRow = iOutRow + 1
Next
Next
wsData.Range("A1").Select
MsgBox iOutRow - 2 & " Rows created on " & wsData.Name, vbInformation
End Sub
Then create a table in the database
Sub CreateTable()
Const TABLE_NAME = "dbo.GL_TEST"
Dim SQL As String, con As Object
SQL = "CREATE TABLE " & TABLE_NAME & "( " & vbCr & _
"RECNO int NOT NULL," & vbCr & _
"GLID nchar(10)," & vbCr & _
"METRICNAME nvarchar(255)," & vbCr & _
"AMOUNT money," & vbCr & _
"METRICDATE date," & vbCr & _
"PRIMARY KEY (RECNO))"
'Debug.Print sql
Set con = mydbConnect()
'con.Execute ("DROP TABLE " & TABLE_NAME) ' use during testing
con.Execute SQL
con.Close
Set con = Nothing
MsgBox "Table " & TABLE_NAME & " created"
End Sub
using data connection.
Function mydbConnect() As Object
Dim sConStr As String
Const sServer = "CATHCART"
sConStr = "Provider=SQLOLEDB.1;" & _
"Integrated Security=SSPI;" & _
"Persist Security Info=True;" & _
"Initial Catalog=Portfolio_Analytics;" & _
"Data Source=" & sServer & ";" & _
"Use Procedure for Prepare=1;" & _
"Auto Translate=True;Packet Size=4096;"
Set mydbConnect = CreateObject("ADODB.Connection")
mydbConnect.Open sConStr
End Function
Then load the data from the sheet one record at a time with auto-commit off.
Sub LoadData()
Const TABLE_NAME = "dbo.GL_TEST"
Dim SQL As String
SQL = " INSERT INTO " & TABLE_NAME & _
" (RECNO,GLID,METRICNAME,AMOUNT,METRICDATE) VALUES (?,?,?,?,?) "
Dim con As Object, cmd As Object, rs As Variant
Set con = mydbConnect()
Set cmd = CreateObject("ADODB.Command")
With cmd
.ActiveConnection = con
.CommandType = adCmdText
.CommandText = SQL
.Parameters.Append .CreateParameter("P1", adInteger, adParamInput)
.Parameters.Append .CreateParameter("P2", adVarWChar, adParamInput, 10)
.Parameters.Append .CreateParameter("P3", adVarWChar, adParamInput, 255)
.Parameters.Append .CreateParameter("P4", adCurrency, adParamInput)
.Parameters.Append .CreateParameter("P5", adDate, adParamInput)
End With
con.Execute "SET IMPLICIT_TRANSACTIONS ON"
Dim ws As Worksheet, iLastRow As Long, i As Long
Set ws = ThisWorkbook.Sheets("Sheet2") ' sheet were table data is
iLastRow = ws.Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To iLastRow
cmd.Parameters(0).Value = i
cmd.Parameters(1).Value = ws.Cells(i, 1)
cmd.Parameters(2).Value = ws.Cells(i, 2)
cmd.Parameters(3).Value = ws.Cells(i, 3)
cmd.Parameters(4).Value = ws.Cells(i, 4)
cmd.Execute
Next
con.Execute "COMMIT"
con.Execute "SET IMPLICIT_TRANSACTIONS OFF"
rs = con.Execute("SELECT COUNT(*) FROM " & TABLE_NAME)
MsgBox rs(0) & " Rows are in " & TABLE_NAME, vbInformation
con.Close
Set con = Nothing
End Sub
Here's how you can loop over your data:
Sub Tester()
Dim rw As Range, n As Long
Dim GLID, category, dt, amount
For Each rw In ActiveSheet.Range("H2:AS47").Rows
'fixed per-row
GLID = Trim(rw.Cells(1).Value)
category = Trim(rw.Cells(2).Value)
'loopover the date columns
For n = 3 To rw.Cells.Count
dt = rw.Cells(n).EntireColumn.Cells(1).Value 'date from Row 1
amount = rw.Cells(n).Value
Debug.Print rw.Cells(n).Address, GLID, category, amount, dt
'insert a record using your 4 values
'switch GLID to null if empty
Next n
Next rw
End Sub

VBA Update column in SQL Server table with data from excel

I have a excel workbook that pulls data into a table users can then fill in the missing dates in column 11. Column 1 is the unique identifier that matches the ID column in the SQL table. I want to create a macro that runs when the workbook is closed and will update the SQL table with the filled in dates, but I am struggling with the code. I have have tried two different things but neither seem to work.
Option 1:
Private Sub tableupdate()
Dim con As New ADODB.Connection
Dim cmd As New ADODB.Command
Dim rst As New ADODB.Recordset
Dim i As Long
Dim vDB As Variant
Dim ws As Worksheet
con.connectionstring = "Provider=SQLOLEDB;Password=*********;User ID=clx_write; Initial Catalog=DPEDataMartDBPrd01; Data Source=tcp:dscusnoramcloroxprd01.database.windows.net,1433;"
con.Open
Set cmd.ActiveConnection = con
Set ws = ActiveSheet
vDB = ws.Range("A4").CurrentRegion
For i = 2 To UBound(vDB, 1)
cmd.CommandText = "UPDATE [dbo].[all_load_control] set Driver_arr_dte = ' " & vDB(i, 2) & " ' WHERE mst_ship_num = ' " & vDB(i, 1) & " ' "
cmd.Execute
Next i
con.Close
Set con = Nothing
End Sub
option 2:
Private Sub uplodblanks()
Dim r, c, con, dstring
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim lRow
Dim ssql As String
con = "Provider=SQLOLEDB;Password=********;User ID=clx_write; Initial Catalog=DPEDataMartDBPrd01; Data Source=tcp:dscusnoramcloroxprd01.database.windows.net,1433;"
r = 1
c = 1
Worksheets("WTUpload").Calculate
lRow = Cells.Find(What:="*", After:=Range("A1"), LookAt:=xlPart, LookIn:=xlFormulas, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False).Row
cn.Open con
i = 1
For i = 1 To lRow
ssql = "update dbo.cxu_all_load_control set driver_arr_dte = " & CDate(Sheets("WTUpload").Cells(i, 11)) & " where mst_ship_num = " & CDbl(Sheets("WTUpload").Cells(i, 11)) & " ; "
cn.Execute ssql
Next i
cn.Close
End Sub
Any help as to why neither of these are working would be great
Replace the mydbConnect() function with you own method of getting a connection.
Sub tableupdate2()
Const COL_NUM As String = "A"
Const COL_DATE As String = "K"
Const TABLE As String = "dbo.all_load_control"
' define update sql
Const SQL As String = " UPDATE " & TABLE & _
" SET Driver_arr_dte = CAST(? AS DATETIME2) " & _
" WHERE mst_ship_num = ? "
' establish connection and create command object
Dim con As Object, cmd As Object, sSQL As String
Set con = mydbConnect() ' establish connection
Set cmd = CreateObject("ADODB.Command")
With cmd
.ActiveConnection = con
.CommandText = SQL
.CommandType = 1 'adCmdText
.Parameters.Append .CreateParameter("P1", adVarChar, 1, 20) '
.Parameters.Append .CreateParameter("P2", adVarChar, 1, 50) ' adParamInput = 1
End With
' prepare to get data from spreadsheet
Dim wb As Workbook, ws As Worksheet, iLast As Integer, iRow As Integer
Set wb = ThisWorkbook
Set ws = wb.Sheets("WTUpload")
iLast = ws.Range(COL_NUM & Rows.count).End(xlUp).Row
Dim p1 As String, p2 As String, count As Long
' scan sheet and update db
Debug.Print "Updates " & Now
With cmd
For iRow = 1 To iLast
p1 = Format(ws.Range(COL_DATE & iRow).Value, "yyyy-mm-dd hh:mm")
p2 = ws.Range(COL_NUM & iRow).Value
If len(p2) > 0 Then
.Parameters(0).Value = p1
.Parameters(1).Value = p2
Debug.Print "Row ", iRow, "p1=" & p1, "P2=" & p2
.Execute
count = count + 1
End If
Next
End With
' end
MsgBox "Rows processed = " & count, vbInformation, "Updates Complete"
con.Close
Set con = Nothing
End Sub
Edit - added connection and test code
Function mydbConnect() As Object
Dim sConStr As String
sConStr = "Provider=SQLOLEDB;Password=*********;User ID=clx_write;" & _
"Initial Catalog=DPEDataMartDBPrd01;" & _
"Data Source=tcp:dscusnoramcloroxprd01.database.windows.net,1433;"
Set mydbConnect = CreateObject("ADODB.Connection")
mydbConnect.Open sConStr
End Function
Sub test()
Dim con As Object, rs As Object
Set con = mydbConnect()
Set rs = con.Execute("SELECT CURRENT_TIMESTAMP")
MsgBox rs.Fields(0), vbInformation, "Current Date/Time"
End Sub

Invalid Use of Default Parameter Error While Performing an Insert

I get an error thrown when I try to execute my command to insert a new row into my database. I believe the error is being thrown by Null values. Although I cannot be sure about that.
Here is my code:
Sub AddRows()
Dim Cn As ADODB.Connection
Dim Server_Name As String
Dim Database_Name As String
Dim User_ID As String
Dim Password As String
Dim SQLStr As String
Dim comm As ADODB.Command
Set comm = New ADODB.Command
Dim param As ADODB.Parameter
Dim getType As MultipleValues
Dim nullCheck As String
SQLStr = "Insert Into [Steve_Dev_Matrix] Values("
For i = 1 To 121
'Get type
SQLStr = SQLStr & "?,"
Set param = New ADODB.Parameter
param.Name = "Param" & i
Set param = comm.CreateParameter("param" & i, CLng(CellType(i, Cells(2, i).Value).CellType), adParamInput, CellType(i, Cells(2, i).Value).CellNum)
param.Attributes = adParamNullable
'Debug.Print (param.Type)
comm.Parameters.Append param
Next i
SQLStr = Left(SQLStr, Len(SQLStr) - 1) & ");"
Set Cn = New ADODB.Connection
Cn.CommandTimeout = 0
Cn.Open "Driver={SQL Server};Server=" & Server_Name & ";Database=" & Database_Name & _
";Uid=" & User_ID & ";Pwd=" & Password & ";"
comm.ActiveConnection = Cn
comm.CommandText = SQLStr
comm.CommandType = adCmdText
Dim test As String
lastrow = Sheet1.Cells(Sheet1.Rows.Count, "A").End(xlUp).Row
'For x = 2 To lastrow
For i = 1 To 121
Debug.Print (comm.Parameters.Item("Param" & i).Type)
comm.Parameters.Item("Param" & i).Value = Cells(2, i).Value
Next
comm.Execute
' Tidy up
Cn.Close
Set Cn = Nothing
End Sub
Also here is an example of the CellType method:
Private Function CellType(Num, Rng) As MultipleValues
Application.Volatile
Select Case True
Case Num = 1
CellType.CellType = adInteger
Case Num = 2
CellType.CellType = adInteger
Case Num = 3
CellType.CellType = adVarWChar
CellType.CellNum = 255
Case Num = 4
CellType.CellType = adCurrency
Case Num = 5
CellType.CellType = adVarWChar
CellType.CellNum = 255
The error says: Invalid use of default parameter

Excel VBA error End with with out with?

Hi friends i am working on export excel rows to Sql Server 2008 Table
in that way i am checking the row already exist in table or not
my table has
sap_code
depot
size
entry_date
if table exist that record skip that row and check next row of excel with table
here goes my working code
' ===== Export Using ADO =====
Function ExportRangeToSQL(ByVal sourceRange As Range, _
ByVal conString As String, ByVal table As String) As Integer
On Error Resume Next
' Object type and CreateObject function are used instead of ADODB.Connection,
' ADODB.Command for late binding without reference to
' Microsoft ActiveX Data Objects 2.x Library
' ADO API Reference
' http://msdn.microsoft.com/en-us/library/ms678086(v=VS.85).aspx
' Dim con As ADODB.Connection
Dim con As Object
Set con = CreateObject("ADODB.Connection")
con.ConnectionString = conString
con.Open
' Dim cmd As ADODB.Command
Dim cmd As Object
Set cmd = CreateObject("ADODB.Command")
cmd.CommandType = 1 ' adCmdText
' Dim rst As ADODB.Recordset
Dim rst As Object
Set rst = CreateObject("ADODB.Recordset")
With rst
Set .ActiveConnection = con
.Source = "SELECT * FROM " & table
.CursorLocation = 3 ' adUseClient
.LockType = 4 ' adLockBatchOptimistic
.CursorType = 1 ' adOpenKeyset
.CursorType = 0 ' adOpenForwardOnly
.Open
' Do While Not .EOF
' .MoveNext
' Loop
' Column Mappings
Dim tableFields(100) As Integer
Dim rangeFields(100) As Integer
Dim exportFieldsCount As Integer
exportFieldsCount = 0
Dim col As Integer
Dim index As Integer
For col = 1 To .Fields.Count - 1
index = Application.Match(.Fields(col).Name, sourceRange.Rows(1), 0)
If index > 0 Then
exportFieldsCount = exportFieldsCount + 1
tableFields(exportFieldsCount) = col
rangeFields(exportFieldsCount) = index
End If
Next
If exportFieldsCount = 0 Then
ExportRangeToSQL = 1
Exit Function
End If
' Fast read of Excel range values to an array
' for further fast work with the array
Dim arr As Variant
arr = sourceRange.Value
' Column names should be equal
' For col = 1 To exportFieldsCount
' Debug.Print .Fields(tableFields(col)).Name & " = " & arr(1, rangeFields(col))
' Next
' The range data transfer to the Recordset
Dim row As Long
Dim rowCount As Long
rowCount = UBound(arr, 1)
Dim val As Variant
For row = 2 To rowCount
' Testing the Ledger data to insert
Dim qu As String
Dim br, de, si, da As String
br = arr(row, rangeFields(1)) ' sap_code from excel
de = arr(row, rangeFields(2)) ' depot from excel
si = arr(row, rangeFields(3)) ' size from excel
da = arr(row, rangeFields(5)) ' entry_date from excel
Set con = CreateObject("ADODB.Connection")
con.ConnectionString = conString
con.Open
Dim rstTest As ADODB.Recordset
Set rstTest = New ADODB.Recordset
With rstTest
.CursorLocation = adUseClient
.Open "select TOP 1 sap_code, depot, size, entry_date from openstock where " + "sap_code='" + br + "' and depot='" + de + "' and size='" + si + "' and entry_date='" + da + "' ORDER BY id DESC", con, adOpenStatic, adLockBatchOptimistic, adCmdText
MsgBox "SAP_CODE" & br & "Depot" & de & "Size" & si & "entry_date" & da & "Duplicate Entry Not Entered into Database"
If br = rstTest.Fields("sap_code").Value And _
de = rstTest.Fields("depot").Value And _
si = rstTest.Fields("size").Value And _
da = rstTest.Fields("entry_date").Value Then
Else
End With **NOte: Error showing here as End With with out With**
.AddNew
For col = 1 To exportFieldsCount
val = arr(row, rangeFields(col))
If IsEmpty(val) Then
Else
.Fields(tableFields(col)) = val
End If
Next
End If
Next **NOte: Problem showing here as Next with out FOR**
.UpdateBatch
End With
rst.Close
Set rst = Nothing
con.Close
Set con = Nothing
ExportRangeToSQL = 0
End Function
Suggestion: Always indent your code. So even if you look at the code say 6 months down the line, you will know what the code does. Indentation also helps you catch errors which occur as it happened in the code above
Here is an example
Sub Sample()
For i = 1 to 5
For j = 1 to 10
For k = 1 to 7
If a = 10 then
End If
Next
Next
Next
End Sub
The same code can be written as
Sub Sample()
For i = 1 to 5
For j = 1 to 10
For k = 1 to 7
If a = 10 then
End If
Next
Next
Next
End Sub
Another suggestion (it is not mandatory though) For a better understanding where does a For loop ends, it is advisable to write Next as say Next i.
So the above code can be further improved to
Sub Sample()
For i = 1 to 5
For j = 1 to 10
For k = 1 to 7
If a = 10 then
End If
Next k
Next j
Next i
End Sub
If you implement the above suggestion, you will notice that this section of your code
With rstTest
.CursorLocation = adUseClient
.Open "select TOP 1 sap_code, depot, size, entry_date from openstock where " + "sap_code='" + br + "' and depot='" + de + "' and size='" + si + "' and entry_date='" + da + "' ORDER BY id DESC", con, adOpenStatic, adLockBatchOptimistic, adCmdText
MsgBox "SAP_CODE" & br & "Depot" & de & "Size" & si & "entry_date" & da & "Duplicate Entry Not Entered into Database"
If br = rstTest.Fields("sap_code").Value And _
de = rstTest.Fields("depot").Value And _
si = rstTest.Fields("size").Value And _
da = rstTest.Fields("entry_date").Value Then
Else
End With **NOte: Error showing here as End With with out With**
.AddNew
For col = 1 To exportFieldsCount
val = arr(row, rangeFields(col))
If IsEmpty(val) Then
Else
.Fields(tableFields(col)) = val
End If
Next
End If
Next **NOte: Problem showing here as Next with out FOR**
Solution: Above code can be re-written as
For row = 2 To rowCount
'
'
'
With rstTest
.CursorLocation = adUseClient
.Open "select TOP 1 sap_code, depot, size, entry_date from openstock where " + _
"sap_code='" + br + "' and depot='" + de + "' and size='" + si + _
"' and entry_date='" + da + "' ORDER BY id DESC", con, adOpenStatic, _
adLockBatchOptimistic, adCmdText
MsgBox "SAP_CODE" & br & "Depot" & de & "Size" & si & "entry_date" & da & _
"Duplicate Entry Not Entered into Database"
If br = rstTest.Fields("sap_code").Value And _
de = rstTest.Fields("depot").Value And _
si = rstTest.Fields("size").Value And _
da = rstTest.Fields("entry_date").Value Then
Else
'~~> Removed End With from here
'End With **NOte: Error showing here as End With with out With**
.AddNew
For col = 1 To exportFieldsCount
val = arr(row, rangeFields(col))
If IsEmpty(val) Then
Else
.Fields(tableFields(col)) = val
End If
Next col
End If
End With '<~~ Pasted it here
Next row

Resources