I am trying to fit a CASE function into some SQL code and can't get it to run. Everything has worked perfectly up until the CASE function, and whenever that is inserted, I get a debug error. I was assisted in making this program so I'm hoping it's just a simple error that I'm ignorant of. This is pulling select content from 2 large excel tables based on meeting the criteria. The CASE function is determining whether a value is > or < 12000 and pumping out content based on which content matches that criteria. THANKS!!
See code below:
Dim fPath As String
Dim oConn As New ADODB.Connection
Dim oRS As New ADODB.Recordset
Dim sPath As String, rng1 As Range, rng2 As Range, SQL As String
fPath = ThisWorkbook.FullName 'workbook must be saved somewhere...
'connect to the workbook on disk
oConn.Open "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" & _
"DBQ=" & fPath & ";"
'select some records which match between lists (zipccode and subdivision)
' and with the entered criteria (price, SQFT)
SQL = " select n.*, o.* from [OldList$] o, [NewList$] n " & _
" where n.zipcode = o.zipcode and left(n.Subdivision, 6) = left(o.Subdivision, 6)" & _
" and (n.listprice - o.listprice) between " & shtCriteria.Range("C4").Value & " and " & shtCriteria.Range("D4").Value & _
" and (n.sqft - o.sqft) between " & shtCriteria.Range("C6").Value & " and " & shtCriteria.Range("D6").Value & _
" and CASE " & _
" WHEN n.lot > 12000 " & _
" THEN o.lot between n.lot + n.lot* " & shtCriteria.Range("C8").Value & " and n.lot + n.lot* " & shtCriteria.Range("D8").Value & " " & _
" ELSE (n.lot - o.lot) between " & shtCriteria.Range("C9").Value & " and " & shtCriteria.Range("D9").Value & _
" END "
Set oRS = oConn.Execute(SQL) 'run the query
CASE returns different results of the same type depending on conditions. It’s not for executing alternate code blocks as you have attempted.
Remove CASE and use OR and AND.
You have used it like this:
WHERE …
AND CASE
WHEN n.lot > 12000
THEN <condition 1>
ELSE <condition 2>
END
Change it to:
WHERE …
AND (
(n.lot > 12000 AND <condition 1>)
OR
(n.lot <= 12000 AND <condition 2>)
)
Related
In the process of building a Database for my employer.
This has been going mostly smoothly, but I have had an issue where a table "updates" but no record is inserted.
... well sort of not inserted.
I can't actually tell if it is or not. I mean it's not on the table, and my SQL query returns a 0 BUT my VBA SQL query returns a 1 on a record I told it to insert.
Code below
Dim rst As Recordset
Dim wrk As DAO.Workspace
Dim db As DAO.Database
Dim rsp As Integer
Dim uTable As String
Dim inSQL As String
Debug.Print pCurrentCmd
If pCurrentCmd = "NewIT" Then
Set rst = CurrentDb.OpenRecordset("SELECT COUNT(*) FROM tbl_IT_Staff " & _
"WHERE GivenName LIKE " & Chr(34) & Chr(42) & _
Me.txt_GivenName & Chr(42) & Chr(34) & _
" AND Surname LIKE " & Chr(34) & Chr(42) & _
Me.txt_Surname & Chr(42) & Chr(34) & ";")
If rst.Fields(0) > 0 Then
rsp = MsgBox("This person is already in the database!" & _
vbCrLf & "Do you wish to proceed anyway? ", vbYesNo)
Else
Set rst = Nothing
GoTo Finalize
End If
If rsp = 6 Then GoTo Finalize
If rsp = 7 Then GoTo exitSub
Set rst = Nothing
End If
Finalize:
Set wrk = DBEngine.Workspaces(0)
Set db = wrk.OpenDatabase(CurrentDb.Name)
DoEvents
With wrk
On Error GoTo ErrRollback
If pCurrentCmd = "NewIT" Then
uTable = "tbl_IT_Staff"
End If
.BeginTrans
If IsNull(Me.txt_AOR) Then
inSQL = "INSERT INTO " & uTable & " (GivenName, Surname) VALUES (" & _
Chr(34) & Me.txt_GivenName & Chr(34) & Chr(44) & Chr(34) & _
Me.txt_Surname & Chr(34) & ");"
Else
inSQL = "INSERT INTO " & Chr(34) & uTable & Chr(34) & _
" (GivenName, Surname) VALUES (" & Chr(34) & Me.txt_GivenName & _
Chr(34) & Chr(44) & Chr(34) & Me.txt_Surname & Chr(34) & _
Chr(44) & Chr(34) & Me.txt_AOR & Chr(34) & ");"
End If
Debug.Print inSQL
CurrentDb.Execute inSQL, dbFailOnError
Call AuditLogR(DMax("ID", "tbl_IT_Staff"), "NewP", uTable)
.CommitTrans
End With
exitSub:
Exit Sub
Now I created a new test record : Test Tests and ran the code, it went through, and committed the transaction, BUT, no record exists in the table.
Ok, nbd, I made a change (had commented out the auditlog call, so put it back in) then decided to rerun the code, and see if the audit log updates or not (this has been a constant issue in every new instance of running the audit log, it "updates" but adds no record to the table.) This is the first case where a different table is claiming to have updated, but clearly has not. Often with the Auditlog it has been easily solved.
But what's throwing me off is the fact that this record both exists, and doesn't exist. and that using the same exact SQL query, I get different results depending on if it is done via VBA (where it is 'failing?') and SQL which matches the visible records on the table.
Anyone have any suggestions? Or a direction they can point me in?
I have a VBA Code that involves, among other things, looping of an SQL query written as a Function. When I run the code for the first time, it takes nearly 155 seconds(which is understandable given the complexity of the calculation), when I run it for the second time it takes about 19 seconds. I would like to know why? Also how can I make it run faster? The SQL server version is 2008.
FunctionX() below, is used subsequently in For and Do while Loops, so I understand that a new Connection is created every time it runs.
Option Explicit
Public
Public conn As Object 'connection
________________________________________
Sub CreateConnection ()
Set conn = CreateObject("ADODB.connection")
Dim connstring As String
connstring = "Driver={SQL Server};Server=172.20.1.172;Database=WindAccess_dat_MRK;Uid=MRK_user;Pwd=MRK010usr;"
conn.Open connstring
conn.CommandTimeout = 120
End Sub
____________________________________
FunctionX(ActiveConnection as Object, arg1,arg2,....)
Dim SQLqryfunc1 As String
Dim SQLqryfunc2 As String
Dim SQLqryfunc3 As String
Dim fValue As Variant
Set wb = ThisWorkbook
Dim recset As Object
Set recset = CreateObject("ADODB.Recordset")
Dim ItemString1 As String
Dim ItemString2 As String
Dim ItemString3 As String
Dim ItemString4 As String
Dim ItemString5 As String
Dim StartZeit As String
Dim EndZeit As String
Select Case ChooseZeit
Case 1
StartZeit = Format(InputDateErsterTag, "yyyy-mm-dd hh:mm:ss.000")
EndZeit = Format(InputDateLetzterTag, "yyyy-mm-dd 23:50:ss.000")
ItemString3 = " AND HAL150.WTUR_AVG.MaxPwrSetpoint >=" & MaxPwrSetpoint_AvgVal
ItemString4 = " AND HAL150.WTUR_MIN.MaxPwrSetpoint >=" & MaxPwrSetpoint_MinVal
ItemString5 = " AND HAL150.WTUR_AVG.W >=" & WAvg_Min
Case 2
StartZeit = Format(InputDateErsterTag, "yyyy-mm-dd hh:mm:ss.000")
EndZeit = Format(InputDateLetzterTag, "yyyy-mm-dd hh:mm:ss.000")
ItemString3 = ""
ItemString4 = ""
ItemString5 = ""
End Select
Select Case Item
Case 1 ' 1= m
ItemString1 = " count(case when WindSpeed_Avg"
ItemString2 = " then 1 end)"
Case 2 ' 2= p
ItemString1 = " sum(case when WindSpeed_Avg"
ItemString2 = " then Leistung_Avg end)"
End Select
SQLqryfunc1 = "SELECT" _
& ItemString1 _
& " >=" _
& myWindSpeedFrom _
& " and" _
& " WindSpeed_Avg" _
& " <" _
& myWindSpeedTo _
& ItemString2 _
& " as '13.48 bis 14'" _
SQLqryfunc2 = " from" _
& " (" _
& " SELECT Time_Stamp, LDName as MONr,HAL150.WTUR_AVG.W as Leistung_Avg," _
& " WdSpd as WindSpeed_Avg, HAL150.WTUR_AVG.MaxPwrSetpoint as MaxPwrSetpoint_Avg,HAL150.WTUR_MIN.MaxPwrSetpoint as MaxPwrSetpoint_Min" _
& " FROM WSKD.RegCtrPeriodBlock" _
& " INNER JOIN HAL150.WNAC_AVG " _
& " ON WSKD.RegCtrPeriodBlock.idPBlock = HAL150.WNAC_AVG.idPBlock" _
& " INNER JOIN HAL150.WTUR_AVG" _
& " ON WSKD.RegCtrPeriodBlock.idPBlock = HAL150.WTUR_AVG.idPBlock" _
& " INNER JOIN WSKD.Components" _
& " ON WSKD.RegCtrPeriodBlock.IdLD = WSKD.Components.IdLD" _
& " INNER JOIN HAL150.WTUR_MIN" _
& " ON WSKD.RegCtrPeriodBlock.idPBlock = HAL150.WTUR_MIN.idPBlock" _
& " WHERE Time_Stamp BETWEEN" _
& " '" & StartZeit & "'" _
& " AND" _
& " '" & EndZeit & "'" _
& " AND" _
& " LDName in" _
& " (" & "'" & MONr & "'" & ")" _
& ItemString3 _
& ItemString4 _
& ItemString5 _
& " )" _
& " tbl"
SQLqryfunc3 = SQLqryfunc1 & SQLqryfunc2
'Debug.Print SQLqryfunc3
recset.Open SQLqryfunc3, myActiveConnection
fValue = recset.Getrows
Functionx = fValue(0, 0)
'Debug.Print Functionx
End Function
The second time your queries are executed they are likely cached by SQL server.
Lowest hanging fruit to making your query faster would be to take a sample output from this function and run it through SQL Server Management Studio with execution plan enabled: https://learn.microsoft.com/en-us/sql/relational-databases/performance/display-an-actual-execution-plan?view=sql-server-ver15 . It'll give you some tips on what indexes could be added to certain columns to make your query faster. If you have create privileges on database you can create some indexes to speed things up a bit. You'll also be able to see which parts of your query are the most expensive.
Also, dynamic SQL is hard on SQL server precisely because it has to come up with a new optimized execution plan each time and isn't able to keep it for very long. The reason it slows down again is because the optimized execution plan it creates the first time is ejected from the cache. SQL concatenation like this & " WHERE Time_Stamp BETWEEN" _ & " '" & StartZeit & "'" _ also opens you up to SQL injection attacks if the input is from the user. So if you can use parameters in your query instead using ADODB much like in this example answer here: https://stackoverflow.com/a/10353908/4641232 it would make your code more secure.
Another idea to optimize your code might be to move the processing of conditionals onto SQL server. For example, this case here:
Select Case ChooseZeit
Case 1
StartZeit = Format(InputDateErsterTag, "yyyy-mm-dd hh:mm:ss.000")
EndZeit = Format(InputDateLetzterTag, "yyyy-mm-dd 23:50:ss.000")
ItemString3 = " AND HAL150.WTUR_AVG.MaxPwrSetpoint >=" & MaxPwrSetpoint_AvgVal
ItemString4 = " AND HAL150.WTUR_MIN.MaxPwrSetpoint >=" & MaxPwrSetpoint_MinVal
ItemString5 = " AND HAL150.WTUR_AVG.W >=" & WAvg_Min
Case 2
StartZeit = Format(InputDateErsterTag, "yyyy-mm-dd hh:mm:ss.000")
EndZeit = Format(InputDateLetzterTag, "yyyy-mm-dd hh:mm:ss.000")
ItemString3 = ""
ItemString4 = ""
ItemString5 = ""
End Select
Instead of having two possible WHERE clauses, have your VBA create a SQL script that includes both and have SQL server make the distinction. For example, the WHERE clause in your output might look like this:
...
WHERE
...
AND
(
(
2 = 1 -- ChooseZeit == 2 in VB so that's where the 2 comes from.
AND HAL150.WTUR_AVG.MaxPwrSetpoint >= 4 -- I just picked a random number here.
AND HAL150.WTUR_MIN.MaxPwrSetpoint >= 2 -- I just picked a random number here.
AND HAL150.WTUR_AVG.W >= 3 -- I just picked a random number here.
)
OR
(
2 = 2 -- ChooseZeit == 2 in VB so that's where the 2 comes from.
)
)
...
With your WHERE clause constructed this way you give SQL Server a constant query structure to build an optimized path. If you use parameters, you can also now more easily move the scripted query created by VB into a stored procedure that you can compile on SQL server to possibly give even more gains.
Good day. I'm a little stumped about what is happening in my code. I have a userform which collects txtQntyRecd and cboSupplySource. I calculate the lookupValue. And it works just fine. It successfully places the txtQntyRecd in the correct tblWarehouseLocations.WQuantity location. The code is:
updateQnty = "UPDATE tblSupplySources INNER JOIN ((tblWarehouseLocations " & _
"INNER JOIN tblSupplySource_WarehouseLocation ON tblWarehouseLocations.WLocation_ID = tblSupplySource_WarehouseLocation.SWLocation_ID)) " & _
"ON tblSupplySources.SupplySourceID = tblSupplySource_WarehouseLocation.Supply_Source_ID " & _
"SET tblWarehouseLocations.WQuantity = '" & Me.txtQntyRecd & "'" & _
"WHERE (((tblSupplySource_WarehouseLocation.Supply_Source_ID)= " & Me.cboSupplySource & ") " & _
" AND ((tblWarehouseLocations.WLocation_ID)=" & lookupValue & "))"
CurrentDb.Execute updateQnty, dbFailOnError
What I want to do is add the next quantity to the same location. I get weird results if I change the SET statement to the following:
SET tblWarehouseLocations.WQuantity = tblWarehouseLocations.WQuantity + '" & Me.txtQntyRecd & "'"
If I put 200 in the first statement, I get 200 in my WQuantity field. When I change to the second statement and I try to add 1 to the 200 I get a result of 211. If I add 1 again, the result is 223. Add 1 again, the result is 236.
Could someone explain what is happening and why the results aren't 201, 202 and 203? In the future I will need to subtract quantities from WQuantity as well.
Thanks
You're adding quotes around an integer and appending it as a string. Change it to:
".....
SET tblWarehouseLocations.WQuantity = tblWarehouseLocations.WQuantity + " & val(Me!txtQntyRecd) & "....
...."
I've changed the . to a ! as I think it's still a nice distinction between objects properties and controls, and used the val function as it converts the string number value to the integer value.
This is your query in full:
' When I use values from controls, I like to store them in vars
Dim quantityReceived As integer
quantityReceived = val(Me!txtQntyRecd)
updateQnty = "UPDATE tblSupplySources INNER JOIN ((tblWarehouseLocations " & _
"INNER JOIN tblSupplySource_WarehouseLocation ON tblWarehouseLocations.WLocation_ID = tblSupplySource_WarehouseLocation.SWLocation_ID)) " & _
"ON tblSupplySources.SupplySourceID = tblSupplySource_WarehouseLocation.Supply_Source_ID " & _
"SET tblWarehouseLocations.WQuantity = tblWarehouseLocations.WQuantity + " & quantityReceived & _
" WHERE (((tblSupplySource_WarehouseLocation.Supply_Source_ID)= " & Me.cboSupplySource & ") " & _
" AND ((tblWarehouseLocations.WLocation_ID)=" & lookupValue & "))"
I solved the problem. I created a SELECT query to get the present amount in WQuantity. Now quantityReceived = Me!txtQntyRecd + the present amount. With SET tblWarehouseLocations.WQuantity = " & quantityReceived it works fine. However, if just seems so cumbersome.
' lookupValue gives the index into the tblWarehouseLocations where WQuantity resides
Dim lookupValue As Integer
lookupValue = DLookup("[WLocation_ID]", "[tblWarehouseLocations]", "[Location_Name] = '" & Me.cboWLocation & "'")
'Define SQL Query
strSQL = "select tblWarehouseLocations.WQuantity FROM tblWarehouseLocations WHERE (((tblWarehouseLocations.WLocation_ID)= " & lookupValue & "))"
Set rs = db.OpenRecordset(strSQL)
If IsNull(rs!WQuantity) Then
dbvalue = 0
Else
dbvalue = rs!WQuantity
End If
Dim quantityReceived As Integer
quantityReceived = Val(Me!txtQntyRecd) + dbvalue
updateQnty = "UPDATE tblSupplySources INNER JOIN ((tblWarehouseLocations " & _
"INNER JOIN tblSupplySource_WarehouseLocation ON tblWarehouseLocations.WLocation_ID = tblSupplySource_WarehouseLocation.SWLocation_ID)) " & _
"ON tblSupplySources.SupplySourceID = tblSupplySource_WarehouseLocation.Supply_Source_ID " & _
"SET tblWarehouseLocations.WQuantity = " & quantityReceived & _
" WHERE (((tblSupplySource_WarehouseLocation.Supply_Source_ID)= " & Me.cboSupplySource & ") " & _
" AND ((tblWarehouseLocations.WLocation_ID)=" & lookupValue & "))"
CurrentDb.Execute updateQnty, dbFailOnError
I'm trying to write a query in MS Access 2010 in order to use it to print a report, but it gives me "missing parameter" error in "set qd" line, hereunder is the code i wrote, can you please help me and tell me what is wrong with my code:
`Private Sub Command5_Click()
Dim qd As DAO.QueryDef
Dim rs As DAO.Recordset
Dim strSql As String
Dim strFrom, strTo As String
strFrom = [Forms]![FrmPrintSelection]![txtFrom]
strTo = [Forms]![FrmPrintSelection]![txtTo]
strSql = "SELECT tblInvoiceHead.CustomerNumber,
tblCustomers.AccountName,tblCustomers.Address,
tblCustomers.Phone1, tblCustomers.Phone2," _
& "tblCustomers.Mobile1, tblCustomers.Mobile2, tblInvoiceHead.InvoiceNumber,
tblInvoiceHead.InvoiceDate, tblInvoiceHead.TotalInvoice," _
& "tblInvoiceHead.CashDiscount, TblInvoiceDetails.Item, TblInvoiceDetails.Unit,
TblInvoiceDetails.Qtn, TblInvoiceDetails.Price," _
& "TblInvoiceDetails.[Discount%], TblInvoiceDetails.CashDiscount,
TblInvoiceDetails.NetUnitPrice, TblInvoiceDetails.TotalPrice, tblInvoiceHead.InvoiceType" _
& "FROM (tblCustomers INNER JOIN tblInvoiceHead ON tblCustomers.AccountNumber =
tblInvoiceHead.CustomerNumber) INNER JOIN TblInvoiceDetails" _
& "ON tblInvoiceHead.InvoiceNumber = TblInvoiceDetails.InvoiceNumber" _
& "WHERE (((tblInvoiceHead.InvoiceNumber) Between " & strFrom & " And " & strTo & "))"
Set qd = CurrentDb.CreateQueryDef("RepInv", strSql)
Set rs = qd.OpenRecordset
'DoCmd.OpenQuery "repinv", strSql
Reports!repinvoicetest.RecordSource = "repinv"
DoCmd.OpenReport "repinvoicetest", acViewPreview
End Sub
`
Usually the error "missing parameter" means that you spelled one of your columns wrong. If you take your sql and paste it into a new query (temp, don't save) and run it, the misspelled column will pop up a window asking you to provide a value for that "parameter" (because MSAccess is assuming that you never would misspell a column name).
In your query above, you might have copy/pasted it wrong, but if not, then you don't have enough spaces between your words as you continue them on the next line. For instance, your SQL string would end up having some stuff in it like "InvoiceTypeFROM", because you didn't have an extra (necessary) space in there.
Try this query instead:
strSql = "SELECT tblInvoiceHead.CustomerNumber, " _
& " tblCustomers.AccountName,tblCustomers.Address, " _
& " tblCustomers.Phone1, tblCustomers.Phone2, " _
& " tblCustomers.Mobile1, tblCustomers.Mobile2, tblInvoiceHead.InvoiceNumber, " _
& " tblInvoiceHead.InvoiceDate, tblInvoiceHead.TotalInvoice, " _
& " tblInvoiceHead.CashDiscount, TblInvoiceDetails.Item, TblInvoiceDetails.Unit, " _
& " TblInvoiceDetails.Qtn, TblInvoiceDetails.Price, " _
& " TblInvoiceDetails.[Discount%], TblInvoiceDetails.CashDiscount, " _
& " TblInvoiceDetails.NetUnitPrice, TblInvoiceDetails.TotalPrice, " _
& " tblInvoiceHead.InvoiceType " _
& " FROM (tblCustomers INNER JOIN tblInvoiceHead " _
& " ON tblCustomers.AccountNumber = tblInvoiceHead.CustomerNumber) " _
& " INNER JOIN TblInvoiceDetails " _
& " ON tblInvoiceHead.InvoiceNumber = TblInvoiceDetails.InvoiceNumber " _
& " WHERE (((tblInvoiceHead.InvoiceNumber) Between " & strFrom & " And " & strTo & "))"
Notice how I added a lot of unncessary spaces at the begining and end of each line. All of those extra spaces will be ignored. However, if there are too few, then you will get errors. It is a simple trick that I stick-with.
I am trying to connect to a database using VBA in excel but don't know what is wrong. Any suggestions?
Here is the code. I want to get the query results and put then into an excel sheet at the same time
Private Sub CommandButton1_Click()
Dim dd As String
Dim nn As String
OMCS_Connection.Show
If OMCS_Connection.CommandButton1 = False Then
dd = OMCS_Connection.TextBoxa.Value
nn = OMCS_Connection.TextBoxb.Value
End If
Dim order_number As String
order_number = TextBox1.Text
Dim sql_query As String
Set ad = CreateObject("ADODB.Connection") 'create and open ODBC connection
ad.ConnectionString = "ODBC;DRIVER=IBM DB2 ODBC DRIVER - DB2COPY1; DSN=ODRPTDB;UID = " & dd & " ; PWD = " & nn & ";"
'UID=me"
ad.Open
sql_query = "SELECT" & _
"CMOT.MFGNO AS MANUFACTURING_NUMBER," & _
"'BOX' AS ORDER_TYPE," & _
"CMOT.IDCUS AS CUSTOMER_ID," & _
"CMOT.WTCTN AS WT_CUSTOMER_ID," & _
"CMOT.PLORN AS ORDER_NUMBER," & _
"CMOT.IDMAC AS MACHINE_TYPE," & _
"CMOT.IDSMN AS MODEL_NUMBER," & _
"' ' AS NEW_MACHINE_TYPE," & _
"' ' AS NEW_MODEL_NUMBER," & _
"CMOT.BOXSH AS PSSD," & _
"CMOT.ALDPF AS RSSD," & _
"COGUS.ITPDC AS REGION" & _
"FROM DB2COATG.COS1S0T0 CMOT" & _
"INNER JOIN COGUS.WTCTN_CONVERSION COGUS" & _
"ON(COGUS.WTCTN = CMOT.WTCTN AND COGUS.REGIO = CMOT.REGIO)" & _
"WHERE CMOT.PLORN IN (" & order_number & ");"
Set RS = ad.Execute(sql_query) 'execute query
Before ad.open try inserting the following line
ad.CommandTimeout=0
This should prevent the query from timing out if it runs long.
If that does not work, it would help to know what line of code is throwing the error. Do you know how to step thought the code?