I'm having a problem running a SQL statement on vba excel, the last 3 Columns are for storing numbers separated by commas, but when executed on excel vba it doesn't display these values, while on other Database programs it does
the code is the following
Sub obtainColMachs()
Dim cnn1 As New ADODB.Connection
Dim mrs As New ADODB.Recordset, sqry As String
Set cnn1 = New ADODB.Connection
cnn1.ConnectionString = "driver=SQL Server Native Client 11.0;" & _
"server=server;uid=user;pwd=password;database=DB;"
cnn1.ConnectionTimeout = 3
cnn1.Open
sqry = "select top 1 m.* from recipe r left join RecipeGroup rg on r.RecipeGroupID = rg.RecipeGroupID " & _
"left join Matricula m on tonalidad_ID = ParentGroupID *100 + rg.RecipeGroupID where Substring(ColorNo,3,3) = 'ZG5'"
mrs.Open sqry, cnn1
Range("A26").CopyFromRecordset mrs
mrs.Close
cnn1.Close
End Sub
It should return:
But it only returns:
You only seem to be returning fields from your Matricula table; perhaps the SQL should be:
select top 1 m.*, r.*, rg.* from
Or better yet, a list of the fields that are actually required and with reference to the table from which they originate, e.g.:
select top 1 m.Tonalidad, m.Field2, r.Field3, rg.Field4 etc... from
Related
I want to create a sql query. The column name that I want, it's in another table. I wrote this query.
SELECT (SELECT FieldName From TableGENQuest WHERE ID = 1)
FROM TableGEN
WHERE strSO = 'RV12648-01';
I want to get the data from the strGEN1 columns using the FieldName column of the TableGENQuest table.That is data I want No significant transportation damage observed.
tl;dr: Your request is not possible using MS Access SQL alone.
You will need to use VBA to open a recordset containing the content of the table TableGENQuest and construct an appropriate SQL statement whilst iterating over the records held by such recordset.
For example:
Sub GenerateQuery()
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
Dim sql As String
Set dbs = CurrentDb
Set rst = dbs.OpenRecordset("SELECT FieldName FROM TableGENQuest WHERE ID = 1")
With rst
If Not .EOF Then
.MoveFirst
Do Until .EOF
sql = sql & "[" & !FieldName & "], "
.MoveNext
Loop
sql = "select " & Left(sql, Len(sql) - 2) & " from TableGEN WHERE strSO = 'RV12648-01';"
End If
.Close
End With
If sql <> vbNullString Then dbs.CreateQueryDef "OutputQuery", sql
Set rst = Nothing
Set dbs = Nothing
End Sub
The above will generate a query defined in the current database with a SQL statement selecting the fields whose fieldnames are sourced using the SQL:
SELECT FieldName FROM TableGENQuest WHERE ID = 1
The difficulty and convoluted nature of this method indicates that your database is poorly designed: the field names themselves should instead appear as rows within another table.
SELECT b.FieldName FROM TableGEN a
LEFT OUTER JOIN TableGENQuest b
ON a.ID=b.ID
WHERE a.strSO = 'RV12648-01'
AND b.ID=1
OR
SELECT a.strSO,b.FieldName,b.ID
FROM TableGEN a
LEFT OUTER JOIN
(
SELECT FieldName,ID From TableGENQuest WHERE ID = 1
)
b
ON a.ID = b.ID
WHERE strSO = 'RV12648-01'
Try This Query...or can change Join Type...
Try this:
SELECT TableGENQuest.FieldName
FROM TableGEN, TableGENQuest
WHERE TableGENQuest.ID=1 AND WHERE strSO = 'RV12648-01';
I've been tasked to get data from a SQL DB based off the values in Column A Row 3 onwards.
Example of Excel Sheet:
ITEM | QTY TO PICK | QTY ON ORDER | Column 2 | Column 3 etc
PART 1 | 5 | <Data will be populated here>
PART 2 | 12 | <Data will be populated here>
This code runs through a Command Button.
The data pulled from SQL will be populated starting in C3 onwards.
However, my below code only returns one row at a time.
I know where I need to make changes, I just don't know what. After at least 2 hours googling, I'm thoroughly stumped.
ItemNumber = Range("A3").Value
I've tried amending to ("A3:A100").Value but I just get errors.
Full code below;
Private Sub CommandButton2_Click()
' Create a connection object.
Dim cn As ADODB.Connection
Set cn = New ADODB.Connection
' Provide the connection string.
Dim strConn As String
'Use the SQL Server OLE DB Provider.
strConn = "Provider=SQLOLEDB;"
'Connect to the Pubs database on the local server.
strConn = strConn & "server=<server name>;INITIAL CATALOG=<DB Name>;"
'Use an integrated login.
strConn = strConn & " INTEGRATED SECURITY=sspi;"
'Now open the connection.
cn.Open strConn
'
'
ActiveSheet.Range("C3:G10000").Clear ' clear out existing data
Dim ItemNumber As String
ItemNumber = Range("A3").Value
' Create a recordset object.
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
SQLStr = "Select * from vw_WorksOrder WHERE ITEMNO = " & ItemNumber & ""
rs.Open SQLStr, cn
' Copy the records into cell A1 on Sheet1.
Sheet4.Range("C3").CopyFromRecordset rs
' Tidy up
rs.Close
cn.Close
Set rs = Nothing
Set cn = Nothing
You could try building the SQL like so
"Select * from vw_WorksOrder WHERE ITEMNO in (" & _
join(application.transpose(range("a1:a5").Value),",") & ")"
or, for strings.
"Select * from vw_WorksOrder WHERE ITEMNO in ('" & _
join(application.transpose(range("a1:a5").Value),"','") & "')"
My advise is:
1.)
Create a table on SQL Server which contains parameters for your sql statement (itemnumber = 1)
2.)
Write a cycle which loops tru the ranges and adds values one by one to the table like:
i = 1
while cells(i,3).value <> ""
... Insert into temptable values (parameter1,parameter2, etc)
i = i+1
wend
3.)
Modify your sql statement for the recordset joining the table with the parameters and the data you would like to pull and paste that data.
I'm quite new to VBA/SQL and I'm trying to execute a conditional inner join.
I have two tables with a column in common ("CRM" and "CodeCRM") and I would like to obtain an email adress from table2 ("Desks") when something is triggered (CodeBlocage = 101) in table1 ("Flux") in order to add it to an automatic email.
Dim StrDestinataire As String
Select Case Strtable
Case "Flux", "GAFIJOUR"
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim Y As String
Dim sSql As String
Set cn = CurrentProject.Connection
sSql = "Select AddMailCRM from Desks Inner Join Flux on Desks.CODECRM = Flux.CRM WHERE Flux.CODEBLOCAGE = '101'"
Set rs = cn.Execute(sSql)
If Not rs.BOF And Not rs.EOF Then
Y = rs.Fields("AddMailCRM").Value
End If
StrDestinataire = Y
cn.Close
Everything works great except that it should be returning more than one value for the email adress. Any leads?
Thank you
There are three keywords that may cause confusion:
SELECT in sql
SELECT determines the columns in the resulting recordset. If your sql statement is SELECT Name, Number FROM Employees, the SELECT part tells you that the resulting recordset will have two columns named Name and Number.
Select Case in VBA
Select Case is a programming construct for conditionals. You'd use it when you don't want to use a bunch of If..ElseIf..Else statements, but anything you can do with If you can do with Select Case.
Select Case A
Case "Flux"
Execute these VBA statements when the variable A = Flux
Case "Capacitor"
Execute these statements when A = Capacitor
Case Else
Execute these statements when A is neither Flux nor Capacitor
End Select
CASE in sql
The CASE keyword in sql is like Select Case in VBA, but it's used in the field list of a SELECT sql statement (for one).
SELECT Name, CASE WHEN Number = 1 THEN 'One' ELSE 'Two' END MyNum FROM Employees
If you execute this recordset, you get two columns (Name, MyNum). The MyNum field will contains the text One when Number is 1 for that record and the text Two if Number is anything but 1.
Recordsets
You have both Excel and Access tags, so I'm going to assume you're using ADO in either one of those. Your statement
Y = Select email from table2 Inner Join table1 on table2.Crm = table1.Crm WHERE table1.Code = 1
Doesn't do anything - it wouldn't compile. Let's assume you want a variable, Y, to contain the email that would be returned if you executed that sql statement.
Sub GetEmail()
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim Y As String
Dim sSql As String
Set cn = New ADODB.Connection
cn.Open "MyConnectionStringGoesHere"
sSql = "Select email from table2 Inner Join table1 on table2.Crm = table1.Crm WHERE table1.Code = 1"
Set rs = cn.Execute(sSql)
If Not rs.BOF And Not rs.EOF Then
Y = rs.Fields("email").Value
End If
End Sub
In this case I have to create a recordset and execute that recordset for a certain connection. Presumably the join and the WHERE clause ensures that it will only return one record. But if it returns more, this example will only use the email from the first record.
Before I grab the Value of the email field, I make sure that the recordset returned at least one record. If it's at the beginning of the file (BOF) and at the end of the file (EOF) at the same time, that means there are no records in the recordset.
Solved.
Dim StrDestinataire As String
Select Case Strtable
Case "Flux", "GAFIJOUR"
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim Y As String
Dim sSql As String
Set cn = CurrentProject.Connection
sSql = "Select AddMailCRM from Desks Inner Join Flux on Desks.CODECRM = Flux.CRM WHERE Flux.CODEBLOCAGE = '101'"
Set rs = cn.Execute(sSql)
If Not rs.BOF And Not rs.EOF Then
Y = rs.Fields("AddMailCRM").Value
End If
StrDestinataire = Y
cn.Close
This is my first question on Stack Overflow. I have learned a lot from from this site but I have not been able to find the answer for a problem I am having.
I have a SQL query that works in SQL Server 2008 R2 management studio but it does not work when I query it using vba in EXCEL 2013. The query contains a common table expression and it is not returning any records to my recordset.
The SQL query is:
WITH cte AS
( SELECT *, ROW_NUMBER() OVER (PARTITION BY [partNumber]
ORDER BY [date] DESC) AS i FROM [myDB].[dbo].[PartOrders]
WHERE [partDescription] like '%motor%' )
SELECT * FROM cte WHERE i = 1
I have a reference for Microsoft ActiveX Data Objects 6.1 Library
The VBA code I am using is:
Dim conn as ADODB.Connection
Dim sql as String
Dim rst as ADODB.Recordset
Set conn = New ADODB.Connection
conn.ConnectionString = myConnectionString
conn.Open
sql = ";WITH cte AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY " & _
"[partNumber] ORDER BY [date] DESC) AS i " & _
"FROM [myDB].[dbo].[PartOrders]" & _
"WHERE [partDescription] like '%motor%' ) " & _
"SELECT * FROM cte WHERE i = 1 "
Set rst = New ADODB.Recordset
rst.Open sql, conn, adOpenStatic, adLockReadOnly, adCmdText
debug.print rst.recordcount
conn.Close
Set rst = Nothing
Set conn = Nothing
My code prints a "-1" in the Immediate window
I have added the preceding ";" to my query based on a recommendation of another questions response. It does not make a difference.
I have verified the following query string returns a recordset:
sql = "SELECT *, ROW_NUMBER() OVER (PARTITION BY " & _
"[partNumber] ORDER BY [date] DESC) AS i " & _
"FROM [myDB].[dbo].[partNumbers]" & _
"WHERE [partDescription] like '%motor%'"
I am using a CTE due to needing to collect entire records of a table but only of distinct part descriptions. I do not want to see that a motor was ordered 20 times. I would like to see that the motor was was ordered at least once along with the other fields associated with it. I am searching a table with 730,000 records where there are records for 10,000 motors but only 500 distinct types.
I am open to using a different query if it will net the same results but I am really curious as to why my current query is not yielding any records. I hope it is not due to an ADODB and VBA incompability.
Thank you for all of the help I have received from others questions and I appreciate any help you can provide me.
Parfait provided a solution for me in the comments to my original question. Changing my connection string provider to a driver did not work. It caused a Run-time error '-2147467259 (80004005)'
Instead of a CTE, I utilized a derived table in my query.
The SQL query that returns a recordcount for me in VBA is:
SELECT main.*
FROM (SELECT *, ROW_NUMBER() OVER (PARTITION BY [partNumber]
ORDER BY [date] DESC) AS i FROM [myDB].[dbo].[PartOrders]
WHERE [partDescription] like '%motor%')
AS main WHERE main.i = 1
Thank You!
I had the same issue except I was using Driver as recommended by user7638417. When the recordset returned, the recordcount was -1, but, when I inserted the rows into the spreadsheet, they were all there (24). Used simplified query in example, actual query was more complex which lead me to the CTE method.
Dim sql As String
Dim dbConn As New ADODB.Connection
Dim dbRS As New ADODB.Recordset
Dim rows As Integer
sql = "WITH S1 AS ( SELECT Lot, CollectDt, Mark, Slot, Thick1, Thick2 From Table1 )"
sql = sql + " WHERE Lot = 'lotnumber' "
sql = sql + " SELECT * FROM S1 WHERE Thick2 <> "UNKNOWN" ORDER BY Slot "
dbConn.ConnectionString = "Driver={SQL Server};server=myserver;database=production;uid=guest;pwd=guest"
dbConn.Open
dbConn.CommandTimeout = 600
dbRS.Open sql, dbConn, adOpenStatic, adLockReadOnly
Dim totRow As Integer
totRow = dbRS.RecordCount + 2
' If (dbRS.RecordCount > 0) Then
Sheet1.Cells(2, 1).CopyFromRecordset dbRS
' End If
I had to comment out the check for data in order to get the data from the record set. The value in totRow came back as 1 instead of 26, the expected value which causes other things to fail later in the code.
SQL Server Version: 13.0.4001.0
Excel Version: 2016
How do I run a query with VB that will return the TOP 10 results based on column appClickCount and update column appFAIList to 1 and anything below the TOP 10 will give the column appFAIList a value of 0?
Using sqlCon = New SqlConnection("Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\ITCSDatabase.mdf;Integrated Security=True")
sqlCon.Open()
Dim sqlText = "SELECT top 10 appClickCount " & _
"FROM appTable" & _
"UPDATE appTable SET appFAIList = 1"
Dim cmd = New SqlCommand(sqlText, sqlCon)
cmd.ExecuteScalar()
End Using
Run this SQL statement instead
with t as (
select *, rn=row_number() over (order by 1/0)
from appTable)
update t set
appFAIList = case when rn<=10 then 1 else 0 end
Your vb.net code is quite buggy though. You're using ExecuteScalar which is intended to return a single-row, single-column result. As written, it will give you the first appClickCount value.
The other issue is that using TOP 10 in SQL Server without a corresponding ORDER BY means that it will quite arbitrarily (aka "randomly") return any 10 records from the table.
UPDATE a
SET a.appFAIList = 1
FROM appTable AS a
INNER JOIN
(SELECT top 10 appClickCount FROM appTable) AS b ON a.SomeField = b.SomeField
SomeField - may be primary key of your table