Square brackets inside the name of column in VBA query? - sql

I have an issue with square brackets inside the name of column I am trying to access.
name of column: [KPI] Standard Delivery Capability SO [<0/0]
this is my code:
Dim rs As New ADODB.Recordset
Dim query As String
Dim WhatToSelect as String
query = "Select " & WhatToSelect & " From" & sourceSheet & ".[Sheet1$]"
rs.Open query, connection
rs.MoveFirst
i = rs.Fields(rs.Fields(0).name).Value
basicly I am trying to find variable, which would be in "WhatToSelect" variable
I have tried:
WhatToSelect = "avg([[KPI] Standard Delivery Capability SO [<0/0]])"
WhatToSelect = "avg(`[KPI] Standard Delivery Capability SO [<0/0]`)"
nothing has worked so far. (it works with every other column, with no [ ] in)

Coudn't find any documentation about that, so I did some experiments. I created a small table containing one column with exact your column name, executed a Select * from [Sheet1$] and had a look to the column name within the returned recordset. Turned out that the brackets where replaced by parenthesis:
Dim conn As ADODB.Connection, rs As ADODB.Recordset
Set conn = New ADODB.Connection
Dim connString As String
connString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.Name & ";" & "Extended Properties=""Excel 12.0 Xml;HDR=YES;"""
conn.Open connString
Set rs = conn.Execute("Select * from [Sheet1$]")
Dim i As Integer
For i = 0 To rs.Fields.Count
Debug.Print rs.Fields(i).Name
Next
>> (KPI) Standard Delivery Capability SO (<0/0)
To query this field, you need to (a) enclose the field name with brackets and (b) replace the brackets within the field name with parenthesis:
dim fieldname as String, sql as String
fieldName = "[(KPI) Standard Delivery Capability SO (<0/0)]"
' Use field in result set:
sql = "Select " & fieldname & " from [Sheet1$]"
Set rs = conn.Execute(sql)
' Use field in Where-Clause:
sql = "Select * from [Sheet1$] where " & fieldname & " > 100"
Set rs = conn.Execute(sql)
In your case, where you want to execute a aggregate function on that field, you need to specify
WhatToSelect = "avg([(KPI) Standard Delivery Capability SO (<0/0)])"

Related

Check if table in Oracle database is empty using VBA and SQL COUNT(*)

I need how to find if a given table is empty in an Oracle database (Oracle 11g) to be specific using VBA inside of PowerAdmin Server Monitor's "run script" feature.
SELECT COUNT(*) FROM table; correctly returns "COUNT(*)" as 0. img of result
I need to find a way to check that result if it is 0 or not.
This is a redacted version of the script colleague uses to access the database for slightly different purposes, I prefer if we could continue from this
Dim strConnect
Dim strSQL
Dim adoConnection
Dim adoRecordset
strConnect = "Driver={Oracle in OraClient11g_home1_32bit};" & _
"Dbq=database;" & _
"Uid=user;" & _
"Pwd=password"
strSQL = "SELECT COUNT(*) FROM table;;"
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Open strConnect
Set adoRecordset = CreateObject("ADODB.Recordset")
adoRecordset.ActiveConnection = adoConnection
adoRecordset.Source = strSQL
adoRecordset.Open
[check if query result is the number 0 here]
adoRecordset.Close
adoConnection.Close
I need something that would look like
If queryresult = 0 then
SendNotification = True
Details = "table is empty"
End If
Any help would be appreciated. The more ELI5 the better.
After you execute a query in ADO, the recordset points to the first record, and you can access the fields of that first record per index (0-based).
The result of your count(*)-query is always one row with one column, holding the number of records. So you can access the number of rows with adoRecordset(0) (=first field of first record)
You could create a function to fetch the number of records:
Const strConnect = "..."
Function CountValues(tableName As String) As Long
Dim strSQL As String
strSQL = "SELECT COUNT(*) FROM " & tableName
Dim adoConnection
Dim adoRecordset
On Error GoTo CountValues_ERROR
Set adoConnection = CreateObject("ADODB.Connection")
Set adoRecordset = CreateObject("ADODB.Recordset")
adoConnection.Open strConnect
adoRecordset.ActiveConnection = adoConnection
adoRecordset.Source = strSQL
adoRecordset.Open
Dim res
res = adoRecordset(0)
CountValues = CLng(res)
GoTo CountValues_EXIT
CountValues_ERROR:
MsgBox "An error occurred fetching data: " & Err.Number & " " & Err.Description
CountValues_EXIT:
If adoRecordset.State <> 0 Then adoRecordset.Close
If adoConnection.State <> 0 Then adoConnection.Close
End Function
N.B.: If I where you, I would switch to early binding. Add a reference to the ADODB library and use
Dim adoConnection As ADODB.Connection
Dim adoRecordset As ADODB.RecordSet
Set adoConnection = new ADODB.Connection
Set adoRecordset = new ADODB.RecordSet

VBA to query field contents in CSV

I'm struggling with ADO connections/recordsets.
My problem statement is: a function that will return the first value of a chosen field, in a chosen .csv file.
I am doing this to identify variably-named .csv files before adding the data to the relevant tables in a database. I am making the assumption that this field is always present and that either it is consistent throughout the file, or only relevant ones are grouped (this is controlled higher up the chain and is certain enough).
My code is being run as part of a module in an MS Access database:
Public Function GetFirstItem(File As Scripting.File, Field As String)
Dim Conn As ADODB.Connection, Recordset As ADODB.Recordset, SQL As String
Set Conn = New ADODB.Connection
Set Recordset = New ADODB.Recordset
'Microsoft.ACE.OLEDB.16.0 / Microsoft.Jet.OLEDB.4.0
Conn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.16.0;Data Source=""" & File.ParentFolder & _
"""; Extended Properties=""text;HDR=Yes;FMT=Delimited;"";"
SQL = "SELECT " & Field & " FROM """ & File.Name & """ LIMIT 1"
Debug.Print Conn.ConnectionString
Debug.Print SQL
Conn.Open
Recordset.Source = SQL
Recordset.ActiveConnection = Conn.ConnectionString
Recordset.Open
Recordset.MoveFirst
'GetFirstItem = Recordset!Questionnaire
Recordset.Close
Conn.Close
Set Recordset = Nothing
Set Conn = Nothing
End Function
ConnectionString = Provider=Microsoft.ACE.OLEDB.16.0;Data Source="D:\Documents\Jobs\TestPath"; Extended Properties="text;HDR=Yes;FMT=Delimited;";
Field = Questionnaire
SQL = SELECT Questionnaire FROM "test.csv" LIMIT 1
I get an error on Recordset.Open of:
This may be (is probably) down to a complete lack of understanding of how ADO connections/recordsets work. I have tried sans-quotes and it complains about a malformed FROM expression. Additionally, once this hurdle is overcome I am unsure of the syntax of how to return the result of my query. If there is a better way of doing this I am all ears!
Thanks.
In Access you don't need ADO library to query a CSV file:
Public Function GetFirstItem(File As Scripting.File, Field As String) As String
Dim RS As DAO.Recordset, SQL As String
SQL = "SELECT TOP 1 [" & Field & "]" _
& " FROM [" & File.Name & "]" _
& " IN '" & File.ParentFolder & "'[Text;FMT=CSVDelimited;HDR=Yes];"
Debug.Print SQL
Set RS = CurrentDb.OpenRecordset(SQL)
GetFirstItem = RS(0)
RS.Close
Set RS = Nothing
End Function
Usage:
?GetFirstItem(CreateObject("Scripting.FileSystemObject").getfile("c:\path\to\your\file.csv"), "your field")

String truncated at 255 chars when got from a MS Access SQL query

I'm having problems with a String var in which I put a SQL query I've saved in MS Access. It works like this:
I generate a list through a SELECT query
Using a menu at a Userform with Excel VBA, I choose columns to order the list
As I will have to order many lists in many ways, I decided to create a Sub ordenar(ByVal sqlLista As String, ByVal sqlOrd As String).
sqlLista contains the name of the SELECT query that generates the list I want to order; sqlOrd contains the ORDER BY <col1>... piece of query:
sqlLista = "ListaAbonos"
ListaAbonos (Access query) =
SELECT Left('0000',4-Len(c.nro_cliente)) & c.nro_cliente & ' - ' & IIF(IsNull(razon_social),apellido & ' ' & nombre, razon_social), a.cod_localidad & '/' & cod_cobrador, cod_abono, descripcion, tel_verificacion, fecha_alta, a.direccion, s.nombre_servicio, ts.valor, a.estado
FROM ((abonos AS a
INNER JOIN servicios AS s ON a.cod_servicio = s.cod_servicio)
INNER JOIN tarifas_servicio AS ts ON a.cod_servicio = ts.cod_servicio)
INNER JOIN clientes AS c ON a.nro_cliente = c.nro_cliente;
sqlOrd = "ORDER BY..."
[NOTE: I ran the entire query (SELECT...ORDER BY...) and IT WORKS PROPERLY]
DECLARATIONS
Public Sub ordenar(ByVal sqlLista As Variant, ByVal sqlOrd As Variant)
Dim cs As String
Dim sPath As String
Dim sql As String
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim qd As DAO.QueryDef
CONNECTION TO DB:
sPath = "C:\Users\Ezequiel\Documents\ZEN.accdb"
cs = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & sPath & ";Persist Security Info=False;"
Set cn = New ADODB.Connection
cn.Open cs
Set rs = New ADODB.Recordset
With rs
.CursorLocation = adUseClient
.CursorType = adOpenStatic
.LockType = adLockOptimistic
End With
THIS IS THE IMPORTANT PART OF THE CODE:
Set qd = CurrentDb.QueryDefs(sqlLista)
sql = Left(qd.sql, Len(qd.sql) - 1) & " " & sqlOrd
Set rs = cn.Execute(sql)
When I execute the Sub, I get an error
Characters found after end of sql statement
Inspecting "sql" and "qd.sql" I found that the query had been truncated:
sql = qd.sql = "SELECT Left('0000',4-Len(c.nro_cliente)) & c.nro_cliente & ' - ' & IIF(IsNull(razon_social),apellido & ' ' & nombre, razon_social), a.cod_localidad & '/' & cod_cobrador, cod_abono, descripcion, tel_verificacion, fecha_alta, a.direccion, s.nombre_serv
Note that the ORDER BY doesn't even appear as it's beyond the first 255 chars.
What's the problem? Thanks!

Data on disk is not directly updated with the 'Update' functionality on my recordset

I am working on some VBA macros. I also use ADODB.Recordset to access data in my Access database.
Now, I need to loop through records in my table and in this loop, also need to update the same table in another function.
Here is the code (cleaned for easy reading).
Dim strSql As String
Dim rstCycles As adodb.Recordset
strSql = "SELECT * FROM tblCycles WHERE DatePlanning = #" & dteCurrentDate & "#"
Set rstCycles = SelectQuery(strSql)
While Not rstCycles.EOF
if ... then
rstCycles("NoCycle1") = ...
rstCycles.Update
end if
RefreshPlanning (*)
rstCycles.MoveNext
Wend
(*) In this function I perform a select on the tblCycles table.
The problem is after the rstCycles.Update, the data is not immediately record on disk thus the call to RefreshPlanning does not read updated data. If I set a '1 second pause' after the update everything is ok. I don't want to use a kind of pause in my loop. Is there another solution?
UPDATE ---------------
RefreshPlanning is a simple function to refresh my excel sheet based on my tblCycles table.
Sub RefreshPlanning(DatePlanning As Date, CodeEquipement As String)
Dim strSql As String
Dim rstCycles As adodb.Recordset
strSql = "SELECT * FROM tblCycles WHERE DatePlanning = #" & DatePlanning & "# AND CodeEquipement = '" & CodeEquipement & "'"
Set rstCycles = SelectQuery(strSql)
While Not rstCycles.EOF
' Some code here to update my excel sheet
' ...
rstCycles.MoveNext
Wend
End Sub
DAO is many times faster than ADO with MS Access:
Dim strSql As String
Dim rstCycles As DAO.Recordset
Dim db As Database
Set db = OpenDatabase("z:\docs\test.accdb")
strSql = "SELECT * FROM tblCycles WHERE DatePlanning = #" & dteCurrentDate & "#"
Set rstCycles = db.OpenRecordset(strSql)
While Not rstCycles.EOF
if ... then
rstCycles.Edit
rstCycles("NoCycle1") = ...
rstCycles.Update
end if
''Need more information here
RefreshPlanning (*)
rstCycles.MoveNext
Wend
If dteCurrentDate is the same as today, you can say:
"SELECT * FROM tblCycles WHERE DatePlanning = Date()"

MS Access 2007, checking current user against a table

We have a simple access database, and would like a button on a form to only be available to select members of staff. (The button has an event tied to it). I'd like to store the usernames of the staff allowed to click the button in a separate table.
What I'd like to do, is perform a simple query to see if the username exists in the table, and set the enabled state of the button depending upon the outcome.
My background is C# and SQL Server, but VBA and access are new to me, and I think I'm struggling with the quirks of this environment.
I've got the username of the logged on user in a string fOSUserName via a call to GetUserNameA in advapi32.dll, but I'm struggling with the simplest of queries to determine if the username exists in the table.
Dim strSQL As String
Dim intResult As Integer
Dim db As DAO.Database
Dim rs As Recordset
Set db = CurrentDb
strSQL = "SELECT COUNT(*) FROM [USERS] WHERE [USERS].[NAME] = '" & _
fOSUsername & "'"
Set rs = db.OpenRecordset(strSQL, dbOpenDynaset)
If Not rs.EOF Then
intResult = rs.Fields(0)
Else
intResult = 0
End If
rs.Close
db.Close
This fails on db.OpenRecordset giving me the error
Run-time error '3061':
Too few parameters. Expected 1.
Can anyone offer some pointers?
When you continue a line in VBA, you need a space between before the line continuation character ("_"). So instead of this:
strSQL = "SELECT COUNT(*) FROM [USERS] WHERE [USERS].[NAME] = '" &_
fOSUsername & "'"
Use this:
strSQL = "SELECT COUNT(*) FROM [USERS] WHERE [USERS].[NAME] = '" & _
fOSUsername & "'"
However, as #Igor Turman pointed out, the lack of a space before the underline character should trigger a compile error. So I'm unsure what's going on but suggest you fix it anyway to avoid confusion.
I'll suggest that rather than opening a recordset, and then reading a value from that recordset, this could be handled simply with the DCount() function.
Dim strCriteria As String
strCriteria = "[USERS].[NAME] = '" & fOSUsername & "'"
Debug.Print "strCriteria: '" & strCriteria & "'"
If DCount("*", "USERS", strCriteria) = 0 Then
Debug.Print "not found"
Else
Debug.Print "found"
End IF
If your missing parameter error is because USERS is a query rather than a table, you can ask DCount() to use a table instead. Or fix the query.
Sounds like your [USERS] object is not a table but Query (with parameter). Also, if you had a syntax error like '&_'(invalid) as opposed to '& _'(valid), your database would not compile. So, if table vs query is your case, please use the following:
...
Dim rs As Recordset
Dim qdf As QueryDef
Set qdf = CurrentDb.QueryDefs("Users")
qdf.Parameters("UserNameParameter") = fOSUsername
Set rs = qdf.OpenRecordset
...
I'm not totally familiar with the way you are using it, but I've always done it this way:
Dim sSQL As String
Dim rs As ADODB.Recordset
Dim cn As ADODB.Connection
Set cn = New ADODB.Connection
cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=[your access db file path and name];Persist Security Info=False"
sSQL = "SELECT COUNT(*) FROM [USERS] WHERE [USERS].[NAME] = '" &_
fOSUsername & "'"
Set rs = New ADODB.Recordset
rs.Open sSQL, cn
If Not rs.EOF Then
intResult = rs.Fields(0)
Else
intResult = 0
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing