Connecting to Excel ODBC - sql-server

I have the below query and I was wondering how to setup an ODBC connection to get this to an excel spreadsheet.
declare #StartDate DATE
declare #EndDate DATE
SELECT Sum(case when status = 6 then 1 else 0 end) as Failed,
Sum(case when status = 9 then 1 else 0 end) as Successful,
UniqueID
Into #tempsheet1
FROM Documents
WHERE ownerID = 467
and status in (6,9)
and CreationTime between #StartDate and #EndDate
Group By UniqueID
Select D.UniqueID, FromName, ToName, CreationTime,
cast(CreationTime as date) as CreationDate, cast(CreationTime as date) as CreationTime,
ErrorCode, ElapsedSendTime, RemoteID
From #tempsheet1 ts1
Inner Join Documents D On
D.UniqueID = ts1.UniqueID
and [Status] = 9
ORDER BY D.CreationTime desc
I'm still researching stuff online, but if anyone can point me in the right direction or give me some tips that would be awesome.

In excel go to Data tab > Get external data > From other sources > From Microsoft Query. From there depends on what type of database you are connecting to but the wizard should guide you through.
Once you have your connection set you can right click in the resulting data set and select table > edit query, choose command type = SQL and then edit your query as required.
Depending on what you are doing an ADO db connection may be better and will allow you to set dynamic date filters and the like... but that is another topic
Edit: ADO approach below
Add a reference to Microsoft ActiveX Data objects library
Figure out your connection string: https://www.connectionstrings.com/
Implement something like the below
.
Sub adoConExample()
Dim startDate As String
Dim endDate As String
Dim con As ADODB.Connection
Dim rs As ADODB.Recordset
Dim sql As String
Set con = New ADODB.Connection
Set rs = New ADODB.Recordset
startDate = format("Your date range reference".value, "yyyy-mm-dd")
endDate = format("Your date range reference".value, "yyyy-mm-dd")
With con
.ConnectionString = "Your connection string"
.CursorLocation = adUseClient
.Open
End With
sql = "Your sql string"
sql = Replace(sql, "DATE1", startDate)
sql = Replace(sql, "DATE2", endDate)
rs.CursorLocation = adUseClient
rs.Open sql, con, adOpenStatic, adLockReadOnly, adCmdText
"Your paste target range".CopyFromRecordset rs
con.Close
rs = Nothing
con = Nothing
End Sub

Related

Update case when sql query to vba

I've been trying to convert the below code from SQL Server to run directly from Excel VBA. But unable to do so.
Update Legal
Set Category = Case
when datediff(month, GETDATE(), [End date]) > 9
then 'Blue'
when datediff(month, GETDATE(), [End date]) < 9
and datediff(month, GETDATE(), [end date]) > 1
then 'Orange'
when datediff(month, GETDATE(), [End date]) < 2
then 'Red'
End
where classification = 'A'
Select
classification,
datediff(month, GETDATE(), [End date]),
Category
from
Legal
Into VBA like below
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 SQLSelect As String
Dim rs As ADODB.Recordset
Dim sqlcmd as string
cbb = Environ("computername")
With Sheet3.Range("A4:Z" & Rows.Count)
.ClearContents
'.ClearFormats
End With
sqlcmd = "Update Legal Set Category = Case" & _
" when datediff(month,GETDATE(),[End date])>9 then 'Blue'" & _
" when datediff(month,GETDATE(),[End date])<9 and datediff(month,GETDATE(),[end date])>1 then 'Orange'" & _
" when datediff(month,GETDATE(),[End date])<2 then 'Red'" & _
" End " & _
" where classification = 'A'"
Debug.Print sqlcmd
With Sheet3.ListObjects.Add(SourceType:=0, Source:=Array( _
"OLEDB;Provider=SQLOLEDB.1;Persist Security Info=True;User ID=Login_ID;Password=Password;Data Source=Server_Name;Use Procedure f" _
, _
"or Prepare=1;Auto Translate=True;Packet Size=4096;Workstation ID=" & cbb & ";Use Encryption for Data=False;Tag with column collatio" _
, "n when possible=False;Initial Catalog=DB_Name"), Destination:=Sheet3.Range( _
"$A$4")).QueryTable
.CommandType = xlCmdSql
.CommandText = sqlcmd
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.BackgroundQuery = True
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.PreserveColumnInfo = True
.SourceConnectionFile = _
"C:\Users\xxxxx\Documents\My Data Sources\xxxxx.odc"
.ListObject.DisplayName = _
"AP_123"
.Refresh BackgroundQuery:=False
End With
This query works absolutely in SQL Server. But I get the following error in VBA:
The query did not run, or the database table could not be opened.
Check the database server or contact your database administrator. Make sure the external database is available and hasn't been moved or reorganized, then try the operation again.
Kindly help me guys!! Been trying this for weeks!
P.S. Do not require a Power Query as it will ask for credentials to the other users whom do not have access to the server
As mentioned, simply separate the two queries by first actually running the action UPDATE statement and then connect your QueryTable to SELECT statement. You can even shorten connection string in Source argument:
Dim Cn As ADODB.Connection, rs As ADODB.Recordset
Dim Server_Name As String, Database_Name As String
Dim User_ID As String, Password As String
Dim conn_str As String, SQLSelect As String, sqlcmd as string
cbb = Environ("computername")
With Sheet3.Range("A4:Z" & Rows.Count)
.ClearContents
'.ClearFormats
End With
conn_str = "Provider=SQLOLEDB.1;Persist Security Info=True;User ID=Login_ID;Password=Password;" & _
"Data Source=Server_Name;Use Procedure for Prepare=1;Auto Translate=True;" & _
"Packet Size=4096;Workstation ID=" & cbb & ";Use Encryption for Data=False;" & _
"Tag with column collation when possible=False;Initial Catalog=DB_Name"
Cn.Open conn_str
' EXECUTE ACTION QUERY
sqlcmd = "UPDATE Legal SET Category = Case" & _
" when datediff(month,GETDATE(),[End date])>9 then 'Blue'" & _
" when datediff(month,GETDATE(),[End date])<9 and " & _
" datediff(month,GETDATE(),[end date])>1 then 'Orange'" & _
" when datediff(month,GETDATE(),[End date])<2 then 'Red'" & _
" End " & _
" where classification = 'A'"
Cn.Execute sqlcmd
' CONNECT TO SELECT QUERY
sqlcmd = "SELECT classification, datediff(month, GETDATE(), [End date]), Category " & _
" FROM Legal;"
With Sheet3.ListObjects.Add(SourceType:=0, Source:=Array( _
"OLEDB;" & conn_str), Destination:=Sheet3.Range( _
"$A$4")).QueryTable
.CommandType = xlCmdSql
.CommandText = sqlcmd
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.BackgroundQuery = True
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.PreserveColumnInfo = True
.SourceConnectionFile = _
"C:\Users\xxxxx\Documents\My Data Sources\xxxxx.odc"
.ListObject.DisplayName = _
"AP_123"
.Refresh BackgroundQuery:=False
End With
Cn.Close
Set Cn = Nothing
Here's the stored procedure method. In SSMS, run this one time
CREATE PROCEDURE dbo.UpdateAndGetLegal
AS
UPDATE Legal
SET Category = CASE WHEN DATEDIFF(MONTH, GETDATE(), [End date]) > 9 THEN 'Blue'
WHEN DATEDIFF(MONTH, GETDATE(), [End date]) < 9
AND DATEDIFF(MONTH, GETDATE(), [end date]) > 1 THEN 'Orange'
WHEN DATEDIFF(MONTH, GETDATE(), [End date]) < 2 THEN 'Red'
END
WHERE classification = 'A'
SELECT classification
, DATEDIFF(MONTH, GETDATE(), [End date])
, Category
FROM Legal
That will create a stored procedure that runs the update and returns the SELECT results.
In Excel, I almost never have to .Add a ListObject. Sometimes I have to change the SQL statement of an existing ListObject, but once a table is created, you don't really need to create it again. So I'm not entirely sure what you're doing, but here's how it would look in one of my projects.
I create an Excel file (or template if it's something I'm generating on the fly). In that file, I create an external data ListObject with a commandtext of
EXEC UpdateAndGetLegal
Then if the user simply refreshes the table, I'm done. If I need my code to refresh the table, it's
Sheet3.ListObjects(1).QueryTable.Refresh
If you're passing Windows credentials through to SQL Server, all of the users will need EXECUTE rights for the stored procedures.
I'm taking a bit of a guess here, but it's based on something that feels off.
Every time you run your SELECT to get some data
Select
classification,
datediff(month, GETDATE(), [End date]),
Category
from
Legal
You first run an UPDATE...
Update Legal
Set Category = Case
when datediff(month, GETDATE(), [End date]) > 9
then 'Blue'
when datediff(month, GETDATE(), [End date]) < 9
and datediff(month, GETDATE(), [end date]) > 1
then 'Orange'
when datediff(month, GETDATE(), [End date]) < 2
then 'Red'
End
where classification = 'A'
That's strange and I can't think of a usecase where this would be appropriate in any database. Instead you could just have a SELECT all by itself:
Select
classification,
datediff(month, GETDATE(), [End date]),
Case WHEN classification = 'A'
THEN
CASE
when datediff(month, GETDATE(), [End date]) > 9
then 'Blue'
when datediff(month, GETDATE(), [End date]) < 9
and datediff(month, GETDATE(), [end date]) > 1
then 'Orange'
when datediff(month, GETDATE(), [End date]) < 2
then 'Red'
End
ELSE Category
END
from
Legal
That does the same thing, but without touching the underlying data in Legal. This SELECT is the one that you want to shoehorn in to your VBA/QueryTable.

In VB.NET, who can Iet all databases that contain a specific table

In VB.NET am trying to return all databases that have a specific table. The code I have been using polls just the databases and that works fine. When I add the CASE statement below to get just the ones with the table I need then it returns nothing.
strQuery = "SELECT [name] FROM sys.databases where create_date > '2016-07-01' and [name] not like '_Config_Options' order by create_date desc"
sqlCon = New SqlConnection(strConn)
Using (sqlCon)
Dim sqlComm As SqlCommand = New SqlCommand(strQuery, sqlCon)
sqlCon.Open()
Dim sqlReader As SqlDataReader = sqlComm.ExecuteReader
If sqlReader.HasRows Then
While (sqlReader.Read())
cmbDatabase.Items.Add(sqlReader.GetString(0))
End While
End If
sqlReader.Close()
End Using
The above code returns the full list of databases.
When I change the strQuery to
strQuery = "SELECT [name] FROM sys.databases WHERE CASE WHEN state_desc = ''ONLINE'' THEN OBJECT_ID(QUOTENAME([name]) + ''.[dbo].[MyTable]'', ''U'') END IS NOT NULL order by create_date desc"
I get nothing back. After executing Dim sqlReader As SqlDataReader = sqlComm.ExecuteReader, the code jumps to the End Using. I don't see an error code.
Joel Coehoom gets the credit for answering. I removed the double single quotes and it works.
strQuery = "SELECT [name] FROM sys.databases WHERE CASE WHEN state_desc = 'ONLINE' THEN OBJECT_ID(QUOTENAME([name]) + '.[dbo].[MyTable]', 'U') END IS NOT NULL order by create_date desc"

I am gettin a null error in the code below for one user

The function below is trying to get the earliest date from a table with 3 dates, one for each type of user, care, sales and manager. This is to build up the diary system by first finding the first date in the diary dates. It's working for some users, but in one case the values do not return at and it gives null.
Private Function GetEarliestDate() As Date
Dim strSQL As String
Dim cmd As New SqlCommand
Dim dDate As Date
Try
strSQL = "Select dT.RecordID, MIN(dT.inDate) As [EarliestDate]
FROM (
Select RecordID, SentDate As [inDate]
From tblOrderDetails Where Flagged = 0 AND SalesID = '" & gUserID & "'
UNION ALL
Select RecordID, DiaryDate AS [inDate]
From tblOrderDetails
Where Flagged=0 And ManID ='" & gUserID & "'
UNION ALL
Select RecordID, CareDate As [inDate]
From tblOrderDetails
Where Flagged = 0 And CareID ='" & gUserID & "'
) As dT Group By RecordID"
cmd.CommandText = strSQL
cmd.Connection = CnMaster
cmd.CommandType = CommandType.Text
Dim RecordCount As Integer
RecordCount = 0
dDate = DateTime.MaxValue
Using reader As SqlDataReader = cmd.ExecuteReader()
While (reader.Read())
RecordCount += 1
Dim dt As DateTime = reader.GetDateTime(1)
If dt < dDate Then
dDate = dt
End If
End While
If dDate = DateTime.MaxValue Then
dDate = DateTime.MinValue
End If
End Using
cmd.Dispose()
Return dDate
Catch ex As Exception
Error_Handler(ex, "GetEarliestDate", "Unable to Get The Earliest Date!")
End Try
Put in all 3 queries additional where:
where SentDate is not null ...
where DiaryDate is not null ...
where CareDate is not null ...

How to query with dates from SQL Server after today's date

I'm trying to query my database with ADO.NET
string con = "Data Source=xx.xx.xx.xx\\SqlExpress;Network Library=DBMSSOCN; Initial Catalog=DB;User ID=ID;Password=xxxxx;";
SqlConnection connection = new SqlConnection(con);
using (connection)
{
string query = "SELECT * FROM Gigs where Date >= GetDate()";
SqlCommand command = new SqlCommand(query, connection);
var da = new SqlDataAdapter();
connection.Open();
SqlDataReader reader = command.ExecuteReader();
da.SelectCommand = command;
connection.Close();
var ds = new DataSet();
da.Fill(ds);
gigs.DataSource = ds;
gigs.DataBind();
}
The code executes fine, but it shows incorrect values. I was expecting to see only dates after today. Yet, I see values from the past and future. It's as if the query is simply SELECT * from Gigs
In SQL Server, the column Date is of type date.
What have I done wrong?
A correct way to get rows from tomorrow and forward :
SELECT * FROM Gigs
WHERE [Date] >= CAST(getdate() + 1 as date)
This would also work
[Date] >= DATEADD(d, datediff(d, 0,getdate()),1)
Using DATEDIFF will make the expression non-sargable, resulting in bad performance.
string query = "SELECT * FROM Gigs WHERE CONVERT(VARCHAR(10), #date, 111) > CONVERT(VARCHAR(10), GETDATE(),111)"
Use DATEDIFF.
Change your string query as follows.
string query = "SELECT * FROM Gigs where DATEDIFF(day, GETDATE(), [Date]) > 0";
This will select the rows which the Date column is newer than today's date.

SQL Server stored procedure does not return data to the class but works fine in SQL Server Management Studio

I'm trying to retrieve data from this SQL Server stored procedure from a vb class and on the class:
Dim GetDailySalesAmateurRptOrderItems_DataArray(,) As String =
oDAL.GetDailySalesAmateurRptOrderItems("2014-04-17", "2014-04-20")
Even though there is enough data in the database it returns nothing to the array... any idea what is causing this problem?
USE [QUICKFIX_COLOR_LAB_POS]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[GetDailySalesAmateurRptOrderItems]
#FromDate Datetime, #ToDate Datetime
as
SELECT
ITEMS.ItemID, ITEMS.ItemName, ORDER_ITEMSET.Qty,
ORDER_ITEMSET.SoldPrice, ORDERS.OrderTimestamp
FROM
ORDERS
INNER JOIN
ORDER_ITEMSET ON ORDERS.OrderID = ORDER_ITEMSET.OrderID
INNER JOIN
CUSTOMER_ACCOUNTS ON ORDERS.CustomerID = CUSTOMER_ACCOUNTS.CUSTOMER_ID
CROSS JOIN
ITEMS
WHERE
(CUSTOMER_ACCOUNTS.CUSTOMER_CATEGORY = 'Amateur')
AND (ORDERS.OrderTimestamp BETWEEN CONVERT(DATETIME, #FromDate, 102) AND CONVERT(DATETIME, #ToDate, 102))
ORDER BY
ITEMS.ItemID
VB function
Function GetDailySalesAmateurRptOrderItems(DateFrom As String, ByVal DateTo As String)
Try
Dim DateFrom_Date As DateTime = DateFrom
Dim DateTo_Date As DateTime = DateTo
Dim output(,) As String
Dim counter As Integer
Dim cmd As New SqlCommand("GetDailySalesAmateurRptOrderItems", DBconn)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("#FromDate", DateFrom_Date)
cmd.Parameters.AddWithValue("#ToDate", DateTo_Date)
Dim reader As SqlDataReader
DBconn.Open()
reader = cmd.ExecuteReader
While reader.Read()
counter = counter + 1
End While
ReDim output(counter - 1, 0 To 4)
counter = 0
reader.Close()
reader = cmd.ExecuteReader
While reader.Read()
output(counter, 0) = reader(0)
output(counter, 1) = reader(1)
output(counter, 2) = reader(2)
output(counter, 3) = reader(3)
output(counter, 4) = reader(4)
counter = counter + 1
End While
DBconn.Close()
Return output
Catch ex As Exception
Return ex.Message
End Try
End Function

Resources