Passing empty cells to sql-server shows "0" instead of NULL - sql-server

I'm passing values from excel to sql-server via stored procedure.
There are two columns in excel in wich the cells contain integers or are empty.
But in sql-server, the empty cells from one column are shown as NULL, and the empty cells from the other are shown as "0". Why is that? Both variables are declared as integers in vba, and in sql.
What do I have to do to get everywhere NULL if the cell is empty?
This is part of the vba-code:
Dim rst As New ADODB.Recordset
Dim cmd As ADODB.Command
Dim query As String
Global ktghnev As String
Global ktghID As Integer
Dim elsosor As Integer
Dim pt, bank As Integer
Dim fizmod As String
Dim honap As String
With ActiveSheet
elsosor = 3
Do Until .Cells(elsosor, 1) = ""
nevID = .Cells(elsosor, 1)
pt = .Cells(elsosor, 4)
bank = .Cells(elsosor, 5)
If IsEmpty(Range("D" & elsosor)) = False Or IsEmpty(Range("E" & elsosor)) = False Then
Set cmd = New ADODB.Command
cmd.ActiveConnection = cnn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "EURfeltoltes"
cmd.Parameters.Append cmd.CreateParameter("#nevID", adInteger, adParamInput, , nevID)
cmd.Parameters.Append cmd.CreateParameter("#ktghID", adInteger, adParamInput, , ktghID)
cmd.Parameters.Append cmd.CreateParameter("#honap", adVarChar, adParamInput, 10, honap)
cmd.Parameters.Append cmd.CreateParameter("#pt", adInteger, adParamInput, , pt)
cmd.Parameters.Append cmd.CreateParameter("#bank", adInteger, adParamInput, , bank)
cmd.Execute
End If
elsosor = elsosor + 1
Loop
End With
This is the stored procedure:
ALTER PROCEDURE [dbo].[EURfeltoltes]
#nevID int = null,
#ktghID int = null,
#honap nvarchar(10) = null,
#pt int = null,
#bank int = null
AS
BEGIN
SET NOCOUNT ON;
insert into bertabla (nevID, ktghelyID, honap, eurpt, eurbank) values (#nevID, #ktghID, #honap, #pt, #bank)
END

Related

VB6 - Call Stored Procedure with recordset output on SQLServer

I'm supposed to run a procedure that results in a recordset. I found some code online.
I used this code:
Dim cnAdoDB As ADODB.Connection
Dim StrConnection As String
Dim ACmd As ADODB.Command
Dim TempRS As ADODB.Recordset
Dim RecordNumber As Long
Set cnAdoDB = New ADODB.Connection
StrConnection = "Provider=SQLOLEDB.1;Persist Security Info=False;User ID=xxx;Password=xxx;Initial Catalog=DB-Name;Data Source=xxx.xxx.xxx.xxx"
cnAdoDB.ConnectionString = StrConnection
cnAdoDB.Open
cnAdoDB.CursorLocation = adUseClient
Set ACmd = New ADODB.Command
ACmd.CommandType = adCmdStoredProc
ACmd.CommandText = "[dbo].[st_log_GetDatiTracciabilitaLottoArticolo]"
ACmd.Parameters.Append ACmd.CreateParameter("#ReturnValue", adInteger, adParamReturnValue)
ACmd.Parameters.Append ACmd.CreateParameter("#vLotto", adVarChar, adParamInput, 20, "2022085001")
ACmd.Parameters.Append ACmd.CreateParameter("#vCodArticolo", adVarChar, adParamInput, 32, "A014L628")
ACmd.Parameters.Append ACmd.CreateParameter("#vDataOraPompa", adDate, adParamInput, , Null)
Set ACmd.ActiveConnection = cnAdoDB
Set TempRS = ACmd.Execute(RecordNumber)`
ADODB.Recordset RecordCount property always returns -1:
The TempRS recordset is empty but the "RecordNumber" variable has a value of 2 as the result records really are.
Make it a habit to never rely on the .RecordCount property. It's too situational. From the help:
Use the RecordCount property to find out how many records are in a
Recordset object. The property returns -1 when ADO cannot determine
the number of records or if the provider or cursor type does not
support RecordCount. Reading the RecordCount property on a closed
Recordset causes an error.
Your code also has errors:
ACmd.Parameters.Append ACmd.CreateParameter("#vLotto", adVarChar, adParamInput, 20, "2022085001")
ACmd.Parameters.Append ACmd.CreateParameter("#vCodArticolo", adVarChar, adParamInput, 32, "A014L628")
Instead of "20" and "32" (presumably the defined size), the Parameter object expects that actual length of the passed data, i.e.
ACmd.Parameters.Append ACmd.CreateParameter("#vLotto", adVarChar, adParamInput, Len("2022085001"), "2022085001")
ACmd.Parameters.Append ACmd.CreateParameter("#vCodArticolo", adVarChar, adParamInput, Len("A014L628"), "A014L628")

Null date in MS Access form causes error in SQL Server when table is updated using ADO & VBA

My form in MS Access has 10 fields on it - three are date fields updated in sequence - ('Start Date', 'Expected End Date', 'Actual End Date'.) Actual End Date is always NULL the first time the form is updated and Expected End Date may be null on the first few edits too.
When I edit the form and click the update button, a VBA routine calls the SQL Server stored procedure to update the database with changes/new values.
All works good - except if I leave any date fields as NULL (which they have to be for the business process) I get an error when the VBA executes the stored procedure. Please see the code I have used to date (and I have spent many hours on this with no luck)
Error Details: 3421
Application uses a value of the wrong type for the current operation.
Private Sub cmdUpdate_Click()
Dim Con As ADODB.Connection
Dim cmd As ADODB.Command
Dim rtn As Integer
Dim dtStartDate As Date
Dim dtProjectedEnd As Date
Dim dtActualEnd As Date
On Error GoTo HandleErr
Set Con = New ADODB.Connection
Con.ConnectionString = fnProvider
Con.Open
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = Con
.CommandType = adCmdStoredProc
Select Case frmStatus
Case "Add"
.CommandText = "dbo.spAddProjectPhaseDetail"
Case "Edit"
.CommandText = "dbo.spEditProjectPhaseDetail"
End Select
.Parameters.Append .CreateParameter("#PhaseDetailID", adinteger, adparaminput, , Me.txtPhaseDetailID)
.Parameters.Append .CreateParameter("#ProjPhaseID", adinteger, adparaminput, , Me.cboProjPhase)
.Parameters.Append .CreateParameter("#ProjectID", adVarChar, adparaminput, 10, Me.txtProjectID)
.Parameters.Append .CreateParameter("#PhaseLead", adinteger, adparaminput, , Me.cboTestLead)
If IsNull(Me.txtStartDt) Then
MsgBox "You must include a phase start date - this can be an estimate", vbExclamation, "Input Error"
GoTo ExitSub
End If
.Parameters.Append .CreateParameter("#PhaseStartDate", adDate, adparaminput, 9, Me.txtStartDt)
.Parameters.Append .CreateParameter("#PhaseProjectedEndDate", adDBDate, adparaminput, 9, Nz(Me.txtProjectedEnd, Null))
.Parameters.Append .CreateParameter("#PhaseActualEndDate", adDBDate, adparaminput, 9, Nz(Me.txtActualEnd, Null))
.Parameters.Append .CreateParameter("#SoftwareBuild", adVarChar, adparaminput, 20, Nz(Me.txtSoftwareBuild, ""))
.Parameters.Append .CreateParameter("#SysEnvironmentID", adVarChar, adparaminput, 50, Nz(Me.txtSysEnvironment, ""))
.Parameters.Append .CreateParameter("#IsCurrent", adinteger, adparaminput, , Nz(Me.chkCurrent, 0))
.Execute rtn
End With
If rtn = 0 Then
Err.Raise 10005, , "Could not add record to database."
Else
MsgBox IIf(frmStatus = "Edit", "Record Updated", "Record Added"), vbInformation, "Data Update"
End If
ExitSub:
Con.Close
Set Con = Nothing
Set cmd = Nothing
frmStatus = ""
DoCmd.Close acForm, "frmAddProjectPhases"
Exit Sub
HandleErr:
MsgBox "[" & Err.Number & "] " & Err.Description & vbCrLf & "If the error persisits, please contact support."
Call sbSysErrorLogUpdate(Err.Number, Err.Description, "Target:frmAddProjectProjectPhases/cmdUpdate_Click()")
Err.Clear
GoTo ExitSub
The Stored Procedure:
ALTER PROCEDURE [dbo].[spEditProjectPhaseDetail]
#PhaseDetailID Integer,
#ProjPhaseID Integer,
#ProjectID varchar(10),
#PhaseLead integer,
#PhaseStartDate DATE,
#PhaseProjectedEndDate date = NULL,
#PhaseActualEndDate date = NULL,
#SoftwareBuild varchar(50) = NULL,
#SysEnvironmentID varchar(50) = NULL,
#IsCurrent bit = 0
AS
BEGIN
SET NOCOUNT ON;
UPDATE dbo.tblProjPhaseDetail
Set
fPROJ_PHASE_ID = #ProjPhaseID,
fPROJECT_ID = #ProjectID,
fPHASE_LEAD = #PhaseLead,
PHASE_START_DT = #PhaseStartDate,
PHASE_PROJECTED_END_DT = #PhaseProjectedEndDate,
PHASE_ACTUAL_END_DT = #PhaseActualEndDate,
SOFTWARE_BUILD = #SoftwareBuild,
SYS_ENVIRONMENT_ID = #SysEnvironmentID
WHERE PHASE_DETAIL_ID = #PhaseDetailID
END
I'd be grateful for any getting this procedure to run with the Null dates. Thanks
Apologies - the answer is quite simple. I changed the parameter type from adDAte to adDBDate fro the parameters that need to pass null and it worked. Also there was a coding error - I had left the 'size' value in the parameters for the dates - in a previous attempt I had tried passing the dates as strings.-

Call a stored procedure from VBA

I'm pretty new to SQL and VBA and I've written the following query in SQL Server:
ALTER PROCEDURE SP_insert_search_archive
#IP_Address VARCHAR(20),
#DT VARCHAR(30),
#search_word VARCHAR(50),
#search_time TIME
AS
INSERT INTO Search_Archive
values (#IP_Address, #DT, #search_word, #search_time);
Now I would like to execute this stored procedure in VBA (Excel):
Dim StartTime As Double
Dim SecondsElapsed As Double
Dim con As ADODB.Connection
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset
Dim par As String
Dim WSP1 As Worksheet
Set con = New ADODB.Connection
Set cmd = New ADODB.Command
Set rs = New ADODB.Recordset
StartTime = Timer
Application.DisplayStatusBar = True
Application.StatusBar = "Contacting SQL Server..."
con.Open "Provider=SQLOLEDB;Data Source=localhost;Initial Catalog=master;Integrated Security=SSPI;Trusted_Connection=Yes;"
cmd.ActiveConnection = con
SecondsElapsed = Round(Timer - StartTime, 4)
Dim search_word As String
search_word = Range("D2").Text
Dim IP As String
IP = GetMyPublicIP
cmd.Parameters.Append cmd.CreateParameter("IP", adVarChar, adParamInput, 20, IP)
cmd.Parameters.Append cmd.CreateParameter("DT", adVarChar, adParamInput, 30, Now)
cmd.Parameters.Append cmd.CreateParameter("Search Word", adVarChar, adParamInput, 50, search_word)
cmd.Parameters.Append cmd.CreateParameter("Search Time", adVarChar, adParamInput, 20, SecondsElapsed)
cmd.CommandText = "SP_insert_search_archive"
Set rs = cmd.Execute(, , adCmdStoredProc)
rs.Close
Set rs = Nothing
Set cmd = Nothing
MsgBox (DT)
con.Close
Set con = Nothing
When I'm activating the macro, I get this error:
Runtime error '-2147217900 (80040e14)':
Procedure or function SP_insert_search_archive has too many arguments specified
possible that the issue is with the name of the parameters, you left spaces in them instead of separating with "_" ("Search Word" instead of "search_word")

VBA - SQL Output Parameter returning NULL

I have the below sub in VBA and I am trying to retrieve the value of the output parameter from the stored proc but it either returns null or an empty string
Option Explicit
Public Sub BrandewynTest()
' Create Command Object
Set g_objCommand = New ADODB.Command
With g_objCommand
.ActiveConnection = g_objConnection
.CommandType = adCmdStoredProc
.CommandText = "BrandewynTest"
.Parameters.Refresh
.Parameters(1) = "value"
Set g_objResultset = .Execute
Debug.Print .Parameters(2).Value
End With
End Sub
Below is the stored procedure
CREATE PROCEDURE BrandewynTest
#value VARCHAR(50)
,#ouput INT OUTPUT
AS
IF #value = 'value'
SELECt #ouput = 1
ELSE
SELECt #ouput = 0
What am I doing wrong?
You need to define all your parameters, both input and output. Generally you could define your parameters more strictly as well. See the below code:
Public Sub BrandewynTest()
Dim PRM As ADODB.Parameter
Dim iRetVal As Integer
' Create Command Object
Set g_objCommand = New ADODB.Command
With g_objCommand
.ActiveConnection = g_objConnection
.CommandType = adCmdStoredProc
.CommandText = "BrandewynTest"
Set PRM = .CreateParameter("#value", adVarChar, adParamInput, 50, "value")
.Parameters.Append PRM
Set PRM = .CreateParameter("#ouput", adInteger, adParamOutput, , iRetVal)
.Parameters.Append PRM
.Execute
iRetVal = CMD.Parameters("#ouput")
Debug.Print iRetVal
End With
End Sub
You could argue that having iretval as a variable is superfluous but you can pin it to the watch t

SQL Server return table to MS Access via stored procedure

I'm trying to return a table back to MS Access that has 50+ columns and the rows can vary from 0 to 5000. For each case there can be multiple records and vehicle type.
I can execute the stored procedure and it works fine. I'm having trouble getting the data to return back to MS Access.
Stored procedure code:
ALTER PROCEDURE [dbo].[pJDB_Export]
(#dteFrom int,
#dteTo int,
#Veh nvarchar(80))
AS
BEGIN
SET NOCOUNT ON;
DECLARE #stWhere VARCHAR(200)
SELECT DISTINCT [Case]
INTO #tmp
FROM data
WHERE [VEHICLE TYPE] = #Veh
AND (CY BETWEEN #dteFrom AND #dteTo)
SELECT DISTINCT *
FROM dbo.vdata_Export_V3_3_2 v
INNER JOIN #tmp t ON v.[CASE] = t.[CASE]
MS Access code:
Function Exec_pJDB_export(sqlConn as string)
Dim conn As ADODB.Connection
Dim cmd As ADODB.Command
Dim iFrom, iTo As Integer
Dim stv As String
iFrom = 1999
iTo = 2002
stv = "1 TO 2 TON TRUCKS (COMMERCIAL)"
Set conn = New ADODB.Connection
conn.Open "DSN=Cars"
conn.ConnectionString = sqlConn
Set cmd = New ADODB.Command
cmd.ActiveConnection = conn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "pJDB_export"
cmd.Parameters.Append cmd.CreateParameter("#dteFrom", adInteger, adParamInput, , iFrom)
cmd.Parameters.Append cmd.CreateParameter("#dteTo", adInteger, adParamInput, , iTo)
cmd.Parameters.Append cmd.CreateParameter("#vehicle", adVarChar, adParamInput, 80, stv)
cmd.Execute
conn.Close
End Function
The execute method returns a recordset object. It is this object that contains your records. Here is example:
Function Exec_pJDB_export(sqlConn As String)
Dim conn As ADODB.Connection
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset ' ADO recordset object, for accessing records.
Dim iFrom, iTo As Integer
Dim stv As String
iFrom = 1999
iTo = 2002
stv = "1 TO 2 TON TRUCKS (COMMERCIAL)"
Set conn = New ADODB.Connection
conn.Open "DSN=Cars"
conn.ConnectionString = sqlConn
Set cmd = New ADODB.Command
cmd.ActiveConnection = conn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "pJDB_export"
cmd.Parameters.Append cmd.CreateParameter("#dteFrom", adInteger, adParamInput, , iFrom)
cmd.Parameters.Append cmd.CreateParameter("#dteTo", adInteger, adParamInput, , iTo)
cmd.Parameters.Append cmd.CreateParameter("#vehicle", adVarChar, adParamInput, 80, stv)
' This line has changed.
Set rs = cmd.Execute()
' Loops over the records.
Do Until rs.EOF
' Display the contents of column one to the user.
MsgBox rs.Fields(0).Value
rs.MoveNext
Loop
rs.Close
conn.Close
End Function
Quick overview:
EOF stands for End of File. It is true when you have viewed all records.
Don't forget to call MoveNext, or the do loop will continue forever!
The line rs.Fields(0).Value can be changed to rs.Fields("YourFieldName").Value, if you prefer. I find it easier to refer to fields by name, rather than position.

Resources