How to update SQL Server table from Excel data - sql-server

I've a vendor table in SQL Server with vendor code, vendor ID and vendor name. Another table called disc_mast with columns vendor ID and disc_per. Vendors will revise disc% frequently and we will get the details in Excel with vendor code and disc%. How can I update the discount percent in the disc_mast from the data in excel without importing the data in Excel to SQL Server tables.

You can do something like this.
Sub Update()
'Declare some variables
Dim cnn As adodb.Connection
Dim cmd As adodb.Command
Dim strSQL As String
'Create a new Connection object
Set cnn = New adodb.Connection
'Set the connection string
cnn.ConnectionString = "Your_Server_Name;Database=Northwind;Trusted_Connection=True;"
'Create a new Command object
Set cmd = New adodb.Command
'Open the connection
cnn.Open
'Associate the command with the connection
cmd.ActiveConnection = cnn
'Tell the Command we are giving it a bit of SQL to run, not a stored procedure
cmd.CommandType = adCmdText
'Create the SQL
strSQL = "UPDATE TBL SET JOIN_DT = 2013-01-13 WHERE EMPID = 2"
'Pass the SQL to the Command object
cmd.CommandText = strSQL
'Open the Connection to the database
cnn.Open
'Execute the bit of SQL to update the database
cmd.Execute
'Close the connection again
cnn.Close
'Remove the objects
Set cmd = Nothing
Set cnn = Nothing
End Sub
This is VBA code that runs in Excel. Also, create a reference to 'Microsoft ActiveX Data Objects x.x Library'.
Tools -. References:

Related

How do I insert Excel date format (mm/dd/yyyy) into SQL Server format (yyyy-mm-dd)?

There is already pre-inputed data in the Excel table in dd/mm/yyyy date format. How can I bulk insert the Excel values in a .csv file into the SQL Server table with yyyy-mm-dd date format?
Well, CSV files don't have formatting, and 'bulk insert the Excel values in a .csv file' doesn't make a whole lot of sense. If you want to push data from Excel to SQL Server, you have many options to do so. If the data set is samll, you can use an Excel Macro to do the work.
Sub InsertInto()
'Declare some variables
Dim cnn As adodb.Connection
Dim cmd As adodb.Command
Dim strSQL As String
'Create a new Connection object
Set cnn = New adodb.Connection
'Set the connection string
cnn.ConnectionString = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=True;Initial Catalog=Northwind;Data Source=Server_Name"
'Create a new Command object
Set cmd = New adodb.Command
'Open the Connection to the database
cnn.Open
'Associate the command with the connection
cmd.ActiveConnection = cnn
'Tell the Command we are giving it a bit of SQL to run, not a stored procedure
cmd.CommandType = adCmdText
'Create the SQL
strSQL = "UPDATE TBL SET JOIN_DT = '2013-01-22' WHERE EMPID = 2"
'Pass the SQL to the Command object
cmd.CommandText = strSQL
'Execute the bit of SQL to update the database
cmd.Execute
'Close the connection again
cnn.Close
'Remove the objects
Set cmd = Nothing
Set cnn = Nothing
End Sub
If you data really is in a CSV file, you can bulk insert the CSV data into SQL Server.
BEGIN TRANSACTION
BEGIN TRY
BULK INSERT OurTable
FROM 'c:\OurTable.txt'
WITH (CODEPAGE = 'RAW', DATAFILETYPE = 'char', FIELDTERMINATOR = '\t',
ROWS_PER_BATCH = 10000, TABLOCK)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
END CATCH
Of course you can also go to SQL Server and import the CSV file from there.
https://www.sqlshack.com/importing-and-working-with-csv-files-in-sql-server/

Call SQL Stored Procedure using Procedure clause

I am trying to build a database for IT device inventory. It uses an MS Access Office 365 front-end with a SQL 2017 backend.
In the database, we don't want to delete records, simply archive them to another table. To do this, I created a stored procedure in SSMS and verified that it does the job properly.
I want VBA to call this stored procedure. For this procedure, I need to pass it identifying information. In VBA, I am trying to assign the server name value from a form to a variable that I can pass into a call of the stored procedure. I found examples using the EXEC command but Access tells me I must use the Procedure clause.
Private Sub Command148_Click()
Dim SrvNameVar As String
Dim strSQL As String
Dim strParm As String
SrvNameVar = Me.SrvName
strParm = "PARAMETERS [Server Name] As CHAR;"
Dim dbs As DAO.Database
Dim qdf As DAO.QueryDef
Set dbs = CurrentDb
strSQL = strParm & "PROCEDURE dbo.sp_ArchiveServer [Server Name];"
Set qdf = dbs.CreateQueryDef("SrvArchive", strSQL)
dbs.Execute ("SrvArchive")
End Sub
The stored procedure that functions properly in SSMS:
CREATE PROCEDURE sp_ArchiveServer #Server nvarchar(30) AS
BEGIN TRANSACTION;
INSERT INTO FSC.dbo.Archive_Servers ([SrvID],[SID],[SrvName],[Make],
[Model],[SN],[SrvIP],[RemoteMgmt],[OSID],[IsDP],[IsIEMRelay],
[IsGUP],[DatePurch],[WarrantyExp],[RAIDConfig],[PrintSrv],
[ConnectedToUPS],[VirtHost],[VirtMachine])
SELECT FSC.dbo.Servers.*
FROM FSC.dbo.Servers
WHERE FSC.dbo.Servers.SrvName = #Server;
DELETE FROM FSC.dbo.Servers
WHERE FSC.dbo.Servers.SrvName = #Server;
COMMIT;
Currently, you are conflating MS Access SQL dialect with SQL Server dialect. Only MS Access SQL queries supports PARAMETERS. However, you are attempting to run an SQL Server query, specifically to execute a stored procedure.
MS Access does allow pass-through queries to backend databases so you can adjust your QueryDef (defaults to Access backend) to connect to MSSQL database and then run EXEC command. All pass-through queries should conform to SQL dialect of backend.
Private Sub Command148_Click()
Dim dbs As DAO.Database
Dim qdf As DAO.QueryDef
Dim SrvNameVar, strSQL As String
SrvNameVar = Me.SrvName
strSQL = "EXEC dbo.sp_ArchiveServer #Server='" & SrvNameVar &"'"
Set dbs = CurrentDb
Set qdf = dbs.CreateQueryDef("SrvArchive")
' ASSIGN ODBC DSN CONNECTION
qdf.Connect = "ODBC; DATABASE=database; UID=user; PWD=password; DSN=datasourcename;"
qdf.SQL = strSQL
qdf.Execute
End Sub
To effectively use parameterization, consider a different API, namely ADO (extendable to any backend database) instead of DAO (more tailored for Access databases).
Private Sub Command148_Click()
' SET REFERENCE TO Microsoft ActiveX Data Object #.# Library
Dim conn As ADODB.Connection, cmd As ADODB.Command
Dim SrvNameVar As String
SrvNameVar = Me.SrvName
' OPEN DRIVER OR DSN CONNECTION
Set conn = New ADODB.Connection
conn.Open "DRIVER={SQL Server};server=servername;database=databasename;UID=username;PWD=password;"
' conn.Open "DSN=datasourcename"
' OPEN AND DEFINE COMMAND OBJECT
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = conn
.CommandText = "sp_ArchiveServer"
.CommandType = adCmdStoredProc
' BIND PARAMETERS BY POSITION AND NOT NAME
.Parameters.Append .CreateParameter("param1", adVarchar, adParamInput, 255, SrvNameVar)
.Execute
End With
conn.close()
Set cmd = Nothing: Set conn = Nothing
End Sub
Create a pass-though query in the Access designer.
You can type in that command in the query (sql view). So, you have a pass-though query,and it will look like this:
EXEC dbo.sp_ArchiveServer #Server='test'
Save the above query. (make sure it is pass through query).
Ok, now your VBA code will look like this:
With CurrentDb.QueryDefs("qryPass")
.SQL = "EXEC dbo.sp_ArchiveServer #Server='" & Me.SrvName & "'"
.ReturnsRecords = False
.Execute
End With
Thank you everyone for your help! With all of the info that you provided, it is now working. To do it, I followed Albert's example creating the Pass Through query first and then appended his code with the information from Parfait and ErikA regarding the connection string. I then added a simple MsgBox command and a Close Form command to make it a little more "pretty". Here is the final code that worked:
Private Sub Command148_Click()
With CurrentDb.QueryDefs("SrvQryPass")
.Connect = "ODBC;DSN=ODBC_17;Description=FSC;Trusted_Connection=Yes;APP=Microsoft Office;DATABASE=FSC;Network=DBMSSOCN;"
.SQL = "EXEC dbo.sp_ArchiveServer #Server='" & Me.SrvName & "'"
.ReturnsRecords = False
.Execute
End With
MsgBox "Archived!"
DoCmd.Close
End Sub

Import data from Excel into SQL Server using queries

If I am not allowed to use the import function of SQL Server to bring data from Excel into SQL Server, would you be able to use queries to import the data?
There are several ways to export data from Excel to SQL Server. Here is one concept.
Sub InsertInto()
'Declare some variables
Dim cnn As adodb.Connection
Dim cmd As adodb.Command
Dim strSQL As String
'Create a new Connection object
Set cnn = New adodb.Connection
'Set the connection string
cnn.ConnectionString = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=True;Initial Catalog=Northwind;Data Source=server_name"
'cnn.ConnectionString = "DRIVER=SQL Server;SERVER=server_name;DATABASE=Northwind;Trusted_Connection=Yes"
'Create a new Command object
Set cmd = New adodb.Command
'Open the Connection to the database
cnn.Open
'Associate the command with the connection
cmd.ActiveConnection = cnn
'Tell the Command we are giving it a bit of SQL to run, not a stored procedure
cmd.CommandType = adCmdText
'Create the SQL
strSQL = "UPDATE TBL SET JOIN_DT = '2013-01-22' WHERE EMPID = 2"
'Pass the SQL to the Command object
cmd.CommandText = strSQL
'Execute the bit of SQL to update the database
cmd.Execute
'Close the connection again
cnn.Close
'Remove the objects
Set cmd = Nothing
Set cnn = Nothing
End Sub

VBA to open and run .sql file and copy the result in excel

I am a bit new to this so my apologies in advance for any mistakes. I am trying to open and execute a sql query which is saved in C drive. The sql works fine. I did not write that sql and it is a very big file so would not like to add the code in VBA. I have been searching on this site and other places but struggling to make this work. I have had some or the other problem each time. I am pasting the code below for you to have a look and help me please. I have created this function which I am using in my VBA code.
Public Function ss()
'Open Connection
Dim oCon As ADODB.Connection
Set oCon = New ADODB.Connection
'Set Connection String
Dim sCon As String
sCon = "Provider=SQLOLEDB;Persist Security Info=True;User
ID='*****';Password='*****';Initial Catalog=****;Data Source=*******;Use
Procedure for Prepare=1;Auto Translate=True;Packet Size=4096;Use Encryption
for Data=False;Tag with column collation when possible=False"
oCon.Open sCon 'Connect established
'Create recordset
Dim ps As ADODB.Recordset
Set ps = New ADODB.Recordset
'Set & execute SQL Command
Dim pCMD As ADODB.Command
Set pCMD = New ADODB.Command
Set pCMD.ActiveConnection = oCon
Dim filename As String
filename = "C:\Users\???????????\******.sql"
'select data
pCMD.CommandText =
CreateObject("scripting.filesystemobject").opentextfile(filename).ReadAll()
Set ps = pCMD.Execute(, , adCmdText)
Debug.Print ps.GetRows
If ps.EOF = False Then Sheets("Sheet2").Range("A1").CopyFromRecordset ps
'Close connection
Set ps = Nothing
Set pCMD = Nothing
oCon.Close
Set oCon = Nothing
End Function
Debug.Print has only been used to see the result but it is showing the same error "Run-time error '3704' Operations is not allowed when the object is closed. After trying so many different things I am not sure what is it that I am doing wrong.
Can someone please help?
Any help will be really appreciated.
For me the easiest solution for you is to modify the end of the stored procedure so when executed, it insert all the results in a table. The next time you execute the SP you just have to TRUCATE the table and INSERT new results.
Execute the SP
You can call the SP from Excel with VBA using some code you can find here on StackOverflow, for example the following (which I've taken from this answer):
Dim cnn As Object
Set cnn = CreateObject("ADODB.Connection")
Dim cmd As Object
Set cmd = CreateObject("ADODB.Command")
cmd.CommandType = 1 ' adCmdText
cmd.CommandTimeout = 120 ' number of seconds to time out
Dim ConnectionString As String
cnn.ConnectionString = "driver={SQL Server};server=MYSERVERNAME;Database=MYDATABASE;Trusted_Connection=yes;"
cnn.Open
Dim SQL As String
SQL = "EXEC [dbo].[Procedure_make_report] 'param1'"
cnn.Open
cmd.CommandText = SQL
cmd.ActiveConnection = cnn
cmd.Execute
If Not cnn Is Nothing Then
cnn.Close
Set cnn = Nothing
End If
Retrive results into Excel
Now that the results of the SP are stored into a table of you DB you can import them into Excel with ODBC connection as shown here or with this procedure.

How do I send data from Excel to SQL temp tables for processing using VBA?

My group uses an Excel macro-based tool to do some serious number crunching. I would like to move the number-crunching bit to SQL because using VBA has become intolerable due to the runtime. Users need to be able to use Excel as the interface and also need to be able to run their macros simultaneously as the Excel workbook is self-contained. I've been testing my plan to call an SQL stored procedure from VBA to pull the data from Excel into SQL temp tables, crunch it, and send it back to Excel. I'm able to pull the data from Excel if I run my SP in SQL Management Studio. Here is the SP:
ALTER PROCEDURE sp_test_import
-- Add the parameters for the stored procedure here
#path varchar(1000)
AS
BEGIN
SET NOCOUNT ON;
declare #SQL varchar(2500);
set #SQL = '
select *
from openrowset(''Microsoft.ACE.OLEDB.12.0'',
''Excel 12.0 Macro;
Database='+#path+''',
[Sheet1$]); '
create table [#test](
col1 varchar(15),
col2 varchar(15),
col3 varchar(15),
col4 varchar(15)
)
insert into #test
exec(#SQL)
select * from #mb_test
END
So that works fine. I then try to call this SP from the Excel file containing the data.
Option Explicit
Sub ado_test()
Dim adoConnection As ADODB.Connection
Dim adoRecordset As ADODB.Recordset
Dim connectString As String
Dim strSQL As String
Dim sPath As String
Worksheets("Sheet1").Select
sPath = ThisWorkbook.FullName
'-Create a new ADO connection --
Set adoConnection = New ADODB.Connection
'-Create a new ADO recordset --
Set adoRecordset = New ADODB.Recordset
'-Build our connection string to use when we open the connection --
connectString = "DRIVER=SQL Server;SERVER=MyServer;Trusted_Connection=yes;DATABASE=testDB"
adoConnection.ConnectionTimeout = 20
adoConnection.CommandTimeout = 20
adoConnection.Open connectString
strSQL = "EXEC testDB.dbo.sp_test_import " & vbCr _
& "#path = " & "'" & sPath & "'"
adoRecordset.Open strSQL, adoConnection
End Sub
The code hangs on the 'adoRecordset.Open' call. If I instead pass a path to a separate Excel file in the variable #path, then everything works swimmingly. Is there a simple way that I can make this SP call from the same workbook? I'm not worried about security since the SQL db will be a dedicated structure for pulling in and processing temporary data. I just need users to be able to run their Excel tools whenever they want to, so I don't want to use permanent tables in the DB in case their respective inputs get mixed up together.
Everything I've found online deals with ASP or ISS and I know nothing about ASP and ISS doesn't seem like the right solution to my particular problem. I could have VBA pass the data to external text files and then pass the paths to those text files to the SQL SP, but if there is a cleaner solution then I would like to know about it. Thanks in advance!
I think it is because you are passing in strSQL, a String data type, as the first parameter of the .Open method, but the Open method requires a Command object (according to MSDN).
What you'll want to do is declare an ADODB.Command object and pass that through. I've modified your code to do this:
Option Explicit
Sub ado_test()
Dim adoConnection As ADODB.Connection
Dim adoRecordset As ADODB.Recordset
Dim adoCommand As ADODB.Command
Dim connectString As String
Dim strSQL As String
Dim sPath As String
Worksheets("Sheet1").Select
sPath = ThisWorkbook.FullName
'-Create a new ADO connection --'
Set adoConnection = New ADODB.Connection
'-Create a new ADO recordset --'
Set adoRecordset = New ADODB.Recordset
'-Create a new ADO command --'
Set adoCommand = New ADODB.Command
'-Build our connection string to use when we open the connection --'
connectString = "DRIVER=SQL Server;SERVER=MyServer;Trusted_Connection=yes;DATABASE=testDB"
adoConnection.ConnectionTimeout = 20
adoConnection.CommandTimeout = 20
adoConnection.Open connectString
strSQL = "sp_test_import"
With adoCommand
.ActiveConnection = adoConnection
.CommandText = strSQL
.CommandType = adCmdStoredProc
.Parameters.Refresh
.Parameters(1).Value = sPath
End With
Set adoRecordset = adoCommand.Execute
If adoRecordset.EOF = False Then ThisWorkbook.Worksheets("YourSheetName").Cells(1, 1).CopyFromRecordset adoRecordset
'--adoRecordset.Open adoCommand, adoConnection'
'--Close the database connection'
adoConnection.Close
End Sub
More information on the Command object.
I also added how I get values from SQL Server into the Excel workbook using the CopyFromRecordset method.

Resources