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
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'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
I am using an MS Access append query to append inventory transactions to my ERP database (MYSQL).
Please advise how I would go about to modify my query to automatically insert the next sequential transaction ID (primary key) into the Inventory_transaction table, with ability to append multiple records at once.
My existing query works fine, but only when I append just one record.
I usually need to append multiple records simultaneously. Each record needs to have a unique sequential transaction ID (primary key). There would be multiple users using this app simultaneously, so I need minimal chance of duplicate a key violation, to prevent roll backs. I tried appending without using a primary key to see if my database would automatically assign a transaction ID, but unfortunately this this ERP field is not an auto-number and I cant modify the table structure...
Below are 2 queries.
This one currently works for generating a transaction ID for just one record.
SELECT Max([SYSADM_INVENTORY_TRANS].[TRANSACTION_ID])+1 AS new_inventory_transaction_ID
FROM SYSADM_INVENTORY_TRANS;
The 2nd query is the append query that contains the first query and I would much appreciate it if someone can modify the query so the user has ability to append multiple records at once with a unique transaction ID.
INSERT INTO SYSADM_INVENTORY_TRANS ( TRANSACTION_ID, WORKORDER_TYPE,
WORKORDER_BASE_ID, WORKORDER_LOT_ID, WORKORDER_SPLIT_ID, WORKORDER_SUB_ID,
OPERATION_SEQ_NO, REQ_PIECE_NO, PART_ID, TYPE, CLASS, QTY, COSTED_QTY,
TRANSACTION_DATE, WAREHOUSE_ID, LOCATION_ID, USER_ID, POSTING_CANDIDATE,
ACT_MATERIAL_COST, ACT_LABOR_COST, ACT_BURDEN_COST, ACT_SERVICE_COST,
CREATE_DATE, ADD_BURDEN, COUNT_SEQUENCE, DESCRIPTION )
SELECT T.new_inventory_transaction_ID, S.WORKORDER_TYPE, D.WORKORDER_BASE_ID,
D.WORKORDER_LOT_ID, D.WORKORDER_SPLIT_ID, D.WORKORDER_SUB_ID, D.OPERATION_SEQ_NO,
D.PIECE_NO, D.auto_issue_part_ID, S.TYPE, S.CLASS, D.[total_auto_issue Qty],
0 AS Expr6, Date() AS Expr1, D.BACKFLUSH_WHS_ID, D.BACKFLUSH_LOC_ID,
"SYSADM" AS Expr3, S.POSTING_CANDIDATE, S.ACT_MATERIAL_COST, S.ACT_LABOR_COST,
S.ACT_BURDEN_COST, S.ACT_SERVICE_COST, Date() AS Expr2, S.ADD_BURDEN,
S.COUNT_SEQUENCE, "ENTERED WITH ACCESS APP" AS Expr5
FROM tbl_static_autoissue_data AS S,
tbl_dynamic_autoissue_data AS D,
qry_transaction_ID_generator AS T;
Here are some notes that may help you towards your goal, however life would be a lot easier and a lot safer with autonumbers. This is VBA as you mention MS Access.
Function NextTranNumber(ByRef FirstTran As Long, _
ByRef LastTran As Long, Optional BlockSize = 1)
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim strSQL As String
Dim lngResult As Long
Dim strCon As String
lngResult = 0 'assume fail
strCon = TestCon ''Connection to back-end
cn.Open strCon
rs.CursorType = adOpenKeyset
rs.LockType = adLockPessimistic
rs.CursorLocation = adUseServer
''Where BEInfo is a single line table that holds a transaction seed
strSQL = "SELECT ASeqNumber FROM BEInfo"
rs.Open strSQL, cn, , , adCmdText
'Note this is ADO, so no rs.Edit
FirstTran = rs!ASeqNumber + 1
rs!ASeqNumber = rs!ASeqNumber + BlockSize
rs.Update
LastTran = rs!ASeqNumber
rs.Close
Set rs = Nothing
End Function
Sub TransactionProcessing()
Dim FirstTran As Long
Dim LastTran As Long
Dim db As Database
Dim sSQL As String
Dim Block As Long
Dim rs As DAO.Recordset
Set db = CurrentDb
'Existing temporary table
sSQL = "DELETE FROM FETempTrans"
db.Execute sSQL, dbFailOnError
'The records to be added to the main table
sSQL = "INSERT INTO FETempTrans ( ID, AText ) SELECT 0 AS ID, AText FROM Table1"
db.Execute sSQL, dbFailOnError
Block = db.RecordsAffected
'Reserve a transaction block based on the temp table count
NextTranNumber FirstTran, LastTran, Block
Set rs = db.OpenRecordset("FETempTrans")
Do While Not rs.EOF
rs.Edit
rs!ID = FirstTran
rs.Update
FirstTran = FirstTran + 1
rs.MoveNext
Loop
If FirstTran - 1 = LastTran Then
'compare the temp set to the main table
'if it passes, update the main table
Else
'fail
End If
End Sub
I need to place 3 Parameters into a Select query from Excel VBA to SQL - One of which can just be replaced using a variable. But this query is a query of another query, and the parameters are held within those two other queries. If running this query in Access I'm just prompted by all three to manually type them in - "Start", "End", and "AdvisorName".
Running the code will prompt the "No value given for one or more required parameters" - However, only 1 Parameter is in this query, the other 2 parameters are held within the other two queries inside this query - "Q_SoloFocus_Advisor_QuestionsYes" and "Q_SoloFocus_Advisor_QuestionsNo".
The three parameters are called "Start" (Start Date range), "End" (End Date range), and "AdvisorName" (held within this query).
Dim cnn As ADODB.Connection
Dim rst As ADODB.Recordset
Dim Command As New ADODB.Command
Dim strSQL As String
Set cnn = New ADODB.Connection
cnn.Open ConnectionString:=Cnct
Set rst = New ADODB.Recordset
strSQL = "SELECT Q_SoloFocus_Advisor_QuestionsAll.Advisor,
Q_SoloFocus_Advisor_QuestionsAll.KeyID,
Q_SoloFocus_Advisor_QuestionsAll.SubQ_Text,
Q_SoloFocus_Advisor_QuestionsAll.CountOfAnswer AS [All],
Q_SoloFocus_Advisor_QuestionsNo.CountOfAnswer AS [No],
Q_SoloFocus_Advisor_QuestionsYes.CountOfAnswer
AS Yes," & _"Format(Q_SoloFocus_Advisor_QuestionsYes.CountOfAnswer/
Q_SoloFocus_Advisor_QuestionsAll.CountOfAnswer,'0.0%')
AS Result" & _"
FROM (Q_SoloFocus_Advisor_QuestionsAll
LEFT JOIN Q_SoloFocus_Advisor_QuestionsNo
ON (Q_SoloFocus_Advisor_QuestionsAll.SubQ_Text =
Q_SoloFocus_Advisor_QuestionsNo.SubQ_Text)
AND (Q_SoloFocus_Advisor_QuestionsAll.KeyID =
Q_SoloFocus_Advisor_QuestionsNo.KeyID)
AND (Q_SoloFocus_Advisor_QuestionsAll.Advisor =
Q_SoloFocus_Advisor_QuestionsNo.Advisor))
LEFT JOIN Q_SoloFocus_Advisor_QuestionsYes
ON (Q_SoloFocus_Advisor_QuestionsAll.SubQ_Text =
Q_SoloFocus_Advisor_QuestionsYes.SubQ_Text)
AND (Q_SoloFocus_Advisor_QuestionsAll.Advisor =
Q_SoloFocus_Advisor_QuestionsYes.Advisor)
AND (Q_SoloFocus_Advisor_QuestionsAll.KeyID =
Q_SoloFocus_Advisor_QuestionsYes.KeyID)" & _
" WHERE (((Q_SoloFocus_Advisor_QuestionsAll.Advisor)=[AdvisorName]));"
'----------------------------------------------------------------------------------
'----------------------------------------------------------------------------------
rst.Open strSQL, cnn, adOpenStatic
rst.MoveFirst
The SQL for the other two queries are similar, one has a where "No" and the other a where not "No" where the parameters are required are:
SELECT tbl_Surveys.Advisor, tbl_QuestionRef.KeyID, tbl_QuestionRef.CallSkill,
tbl_QuestionRef.CallReason, tbl_QuestionRef.MainQ_Text
tbl_QuestionRef.SubQ_Text,
Count(tbl_SurveyAnswers.Answer) AS CountOfAnswer
FROM tbl_QuestionRef
INNER JOIN (tbl_SurveyAnswers
INNER JOIN tbl_Surveys
ON tbl_SurveyAnswers.SurveyLink = tbl_Surveys.ID)
ON tbl_QuestionRef.KeyID = tbl_SurveyAnswers.QuestionRef
WHERE (((tbl_SurveyAnswers.Answer)<>"No"
And (tbl_SurveyAnswers.Answer)<>"N/A"
And (tbl_SurveyAnswers.Answer)<>"0")
AND ((tbl_Surveys.CallDate)>=[Start]
And (tbl_Surveys.CallDate)<=[End]))
GROUP BY tbl_Surveys.Advisor, tbl_QuestionRef.KeyID, tbl_QuestionRef.CallSkill,
tbl_QuestionRef.CallReason,
tbl_QuestionRef.MainQ_Text, tbl_QuestionRef.SubQ_Text;
As you can see, the "Start" and "End" parameters are in this second SQL query... Any ideas how I can put these two parameters into the first SQL function? I can't put the Start and End into the "All" query, as it'll knock out the "Count" part...
Assuming the other two queries are saved and named, instead of calling named queries, incorporate the SQL from the two queries into the main query as derived tables. By doing so, the query will prompt for all parameters. See the JOIN clauses for some clarification.
strSQL = "SELECT Q_SoloFocus_Advisor_QuestionsAll.Advisor, "
Q_SoloFocus_Advisor_QuestionsAll.KeyID,
Q_SoloFocus_Advisor_QuestionsAll.SubQ_Text,
Q_SoloFocus_Advisor_QuestionsAll.CountOfAnswer AS [All],
Q_SoloFocus_Advisor_QuestionsNo.CountOfAnswer AS [No],
Q_SoloFocus_Advisor_QuestionsYes.CountOfAnswer
AS Yes," & _"Format(Q_SoloFocus_Advisor_QuestionsYes.CountOfAnswer/
Q_SoloFocus_Advisor_QuestionsAll.CountOfAnswer,'0.0%')
AS Result" & _"
FROM (Q_SoloFocus_Advisor_QuestionsAll
LEFT JOIN (YOUR FIRST SAVE QUERY SQL) AS Q_SoloFocus_Advisor_QuestionsNo
ON (Q_SoloFocus_Advisor_QuestionsAll.SubQ_Text =
Q_SoloFocus_Advisor_QuestionsNo.SubQ_Text)
AND (Q_SoloFocus_Advisor_QuestionsAll.KeyID =
Q_SoloFocus_Advisor_QuestionsNo.KeyID)
AND (Q_SoloFocus_Advisor_QuestionsAll.Advisor =
Q_SoloFocus_Advisor_QuestionsNo.Advisor))
LEFT JOIN (YOUR SECOND QUWERY SQL) AS Q_SoloFocus_Advisor_QuestionsYes
ON (Q_SoloFocus_Advisor_QuestionsAll.SubQ_Text =
Q_SoloFocus_Advisor_QuestionsYes.SubQ_Text)
AND (Q_SoloFocus_Advisor_QuestionsAll.Advisor =
Q_SoloFocus_Advisor_QuestionsYes.Advisor)
AND (Q_SoloFocus_Advisor_QuestionsAll.KeyID =
Q_SoloFocus_Advisor_QuestionsYes.KeyID)" & _
" WHERE (((Q_SoloFocus_Advisor_QuestionsAll.Advisor)=[AdvisorName]));"
I fail to execute an SQL query with a with clause via ADODB and Oracle.
That is, the following snippet works:
Dim cn As ADODB.connection
Set cn = ....
Dim rs As ADODB.recordSet
Set rs = New ADODB.Recordset
rs.Open "select 'foo' x from dual", cn
Do While Not rs.eof
...
rs.MoveNext
Loop
However, the following doesn't work - it genererats a Run-Time error 3704: Operation is not allowed when the object is closed.
Dim cn As ADODB.connection
Set cn = ....
Dim rs As ADODB.recordSet
Set rs = New ADODB.Recordset
rs.Open "with w as (select 'foo' x from dual) select x from w", cn
Do While Not rs.eof
...
rs.MoveNext
Loop
Obviously, this is a trimmed-down demonstration of the real problem which consists
of a more sophisticated query.
It seems to me that ADODB sort of parses the query before it passes it to the Oracle instance and does not understand the with clause. Anyway, any help on this is highly
appreciated.
Ok, it really seems as though ADODB expects a query statement to actually start with select.
Therefore, a work around for the problem might be to enclose the statement in a select * from ( .... ) like so:
Dim sql As String
sql = "with w as (select 'foo' x from dual) select x from w"
' enclose the statement:
sql = "select * from (" & sql & ")"
rs.Open sql, cn
Above method did not work for me.
Adding ";" prior to WITH keyword resolved the issue.
Dim sql As String
sql = ";with w as (select 'foo' x from dual) select x from w"
rs.Open sql, cn