VBA ACCESS Comparing String as they are integer - sql

I am trying to prompt the user to input a range and display all the instruments that are within that range in a subform.
Problem: The upper and lower range is a text field (because some of the range cannot be expressed in integer). As seen in the screenshot, the comparison only compare the first character of the field.
User's input: 5 - 3
On the subform: 36 - 4
It compares 5 and 3 instead of 36
I know vba is doing what it has been told but how can I achieve the result I want?
Here is my code for requering the subform:
Dim Up As Integer
Dim Low As Integer
If Me.Text_L = "" Or IsNull(Me.Text_L) Or Me.Text_U = "" Or IsNull(Me.Text_U) Then
MsgBox ("Please choose a valid range!")
Else
Up = Me.Text_U
Low = Me.Text_L
SQL = SQL_Origin & " WHERE [qry_View_Search].[Upper_Range] <= '" & Up & "' " _
& "AND [qry_View_Search].[Lower_Range] >= '" & Low & "';"
subform_View_Search.Form.RecordSource = SQL
subform_View_Search.Form.Requery
End If

so what i did is made a new column in the query for
IIf(IsNumeric([Upper]), Val([Upper]), Null)
to get all the numeric result.
Then in the vba, I re query the subform as below
SQL = SQL_Origin & " WHERE [qry_View_Search].[Upper] <= cint(Forms![frm_View_Search]![Text_U]) " _
& "AND [qry_View_Search].[Lower] >= cint(Forms![frm_View_Search]![Text_L]);"
Thanks #HansUp !

I have successfully for those cases used Val only:
Value: Val([FieldName])
or:
Value: Val(Nz([FieldName]))

Related

Access VBA DCount data type mismatch in criteria expression when data types are obviously the same (both Text)

I'm doing a simple DCount, just looking for how many people have signed up for the same date and time. At the moment I'm just using a single date and a single time to prove the process, then I'll have it loop through all possible dates and times.
Private Sub Get_Singles()
Dim TestDate As String
Dim TestTime As String
AloneCnt = 0
Dinc = 0
Tinc = 0
TestDate = vStartDate
TestTime = "0700"
If (DCount("[ID]", VigilTable, "[fldTime] = " & TestTime) = 1) Then
' "[fldDate] = " & TestDate) & " And
AloneCnt = AloneCnt + 1
End If
End Sub
It works fine for the date (I've moved it to a different line and commented it out so I can focus on the time.).
In the table, fldDate and fldTime are both set for text (shows up as Field Size
= 255 in the properties list) and, as you can see, TestDate and TestTime are both dimmed as String.
And it works if I change the DCount line to:
(DCount("[ID]", VigilTable, "[fldTime] = '0700'")
So where's the error?
Thanks.
The error is, that you must handle date and time as data type Date. So change the data type of the fields to DateTime and:
Dim TestDate As Date
Dim TestTime As Date
Dim AloneCnt As Long
TestDate = vStartDate
TestTime = TimeSerial(7, 0, 0)
If DCount("*", "VigilTable", "[fldTime] = #" & Format(TestTime, "hh\:nn\:ss") & "# And [fldDate] = #" & Format(TestDate, "yyyy\/mm\/dd") & "#") = 1 Then
AloneCnt = AloneCnt + 1
End If
Because you hold all date/time bits as text/string, you should use the text syntax in the criteria as you showed: with quotes (notice the quotes around time string):
(DCount("[ID]", VigilTable, "[fldTime] = '" & TestTime & "'")
You could also keep Date/times in date types like #Gustav's answer.
Update:
You must be doing something wrong; here is my suggested version in VBA window, and it is not Red.
OK, I found the fix after searching several other sites; it was, as I suggested above, a problem of handling variables:
If (DCount("[ID]", VigilTable, "[fldDate]='" & TestDate & "'" & " AND [fldTime] = '" & TestTime & "'") = 1) Then
I always have trouble with those damned single quotes and can never get them in the right place (I'd tried placing single quotes several times but never got them where they are here.); I don't know if the rules are different in different places or I just don't understand the rules or both.
Thanks for all your suggestions; even things that don't work help.

MS-ACCESS VBA Multiple Search Criteria

In my GUI, I have several ways to filter a database. Due to my lack of knowledge, my VBA programming has exploded with nested IF statements. I am getting better at using ACCESS now, and would like to find a more succinct way to perform multiple filters. My form is continuous.
Is there a simple way to do the following task (I made a toy model example):
I have a combo box SITE where I can filter by work sites A, B, C. After filtering by SITE, I have three check boxes where the user can then filter by item number 1-10, 11-20, 21-30, depending on what the user selects.
Is there a way to append multiple filters (or filter filtered data)? For example, filter by SITE A, then filter A by item number 1-10?
Currently, for EACH check box, I then have an IF statement for each site. Which I then use Form.Filter = . . . And . . . and Form.FilterOn = True.
Can I utilize SQL on the property sheet to filter as opposed to using the VBA?
What I do for these types of filters is to construct a SQL statement whenever one of the filter controls is changed. All of them reference the same subroutine to save on code duplication.
What you do with this SQL statement depends on what you're trying to do. Access is pretty versatile with it; use it as a RecordSource, straight execute it, and use the results for something else, even just printing it to a label.
To try to modularize the process, here's an example of how I do it:
Dim str As String
str = "SELECT * FROM " & Me.cListBoxRowSource
Me.Field1.SetFocus
If Me.Field1.Text <> "" Then
str = AppendNextFilter(str)
str = str & " SQLField1 LIKE '*" & Me.Field1.Text & "*'"
End If
Me.Field2.SetFocus
If Me.Field2.Text <> "" Then
str = AppendNextFilter(str)
str = str & " SQLField2 LIKE '*" & Me.Field2.Text & "*'"
End If
Me.Field3.SetFocus
If Me.Field3.Text <> "" Then
str = AppendNextFilter(str)
str = str & " SQLField3 LIKE '*" & Me.Field3.Text & "*'"
End If
Me.cListBox.RowSource = str
Variables edited to protect the guilty.
My AppendNextFilter method just checks to see if WHERE exists in the SQL statement already. If it does, append AND. Otherwise, append WHERE.
Making quite a few assumptions (since you left out a lot of info in your question), you can do something like this:
Dim sSql as String
sSql = "Select * from MyTable"
Set W = Me.cboSite.Value
sSql = sSql & " WHERE MySite = " & W & ""
Set X = Me.Chk1
Set Y = Me.Chk2
Set Z = Me.Chk3
If X = True Then
sSql = sSql & " And MyItem between 1 and 10"
If Y = True Then
sSql = sSql & " And MyItem between 11 and 20"
If Z = True Then
sSql = sSql & " And MyItem between 21 and 30"
End If
DoCmd.ExecuteSQL sSql
Again, this is entirely "air code", unchecked and probably needing some edits as I haven't touched Access in some time and my VBA is likely rusty. But it should put you on the right track.
The way i use combobox filtering in access is first I design a Query that contains all the data to be filtered. The Query must contain fields to be used for filtering. QueryAllData => "SELECT Table.Site, Table.ItemNumber, FROM Table;" Then make a copy of the query and Name it QueryFilteredData and Design the report to display the data using QueryFilteredData.
Then create a form with a Site ComboBox, ItemNumber Combo Box, and Sub Report Object and Assign SourceObject the Report Name. Use Value List as the combo box Row Source type and type in the values for Row Source to get it working. To get the report to update I always unassign the SubReport.SourceOject update the QueryFilteredData and then Reassign the SubReport.SourceObject
Combobox_Site_AfterUpdate()
Combobox_ItemNumber_AfterUpdate
End Sub
Combobox_ItemNumber_AfterUpdate()
Select Case Combobox_ItemNumber.value
Case Is = "1-10"
Store_Filters 1,10
Case Is = "11-20"
Store_Filters 11,20
Case Is = "21-30"
Store_Filters 21,30
Case Else
Store_Filters 1,10
End Sub
Private Sub Store_Filters(Lowest as integer, Highest as integer)
Dim SRpt_Recset As Object
Dim Temp_Query As Variant
Dim Temp_SourceObject as Variant
Temp_SourceObject = SubReport.SourceObject
SubReport.SourceObject =""
Set SRpt_Recset = CurrentDb.QueryDefs("QueryFilteredData")
Filter_Combo_Box1 = " ((QueryAllData.[Sites])= " & Chr(39) & Combo_Box1 & Chr(39) & ") "
Filter_Combo_Box2 = (Filter_Combo_Box1 AND (QueryAllData.ItemNumber <= Highest)) OR (Filter_Combo_Box1 AND (QueryAllData.ItemNumber >= Lowest));"
Temp_Query = " SELECT " & Query_Name & ".* " & _
"FROM " & Query_Name & " " & _
"WHERE (" & Filter_Combo_Box2 & ") ORDER BY [Field_Name_For_Sorting];"
SRpt_Recset.SQL = Temp_Query
'Debug.print Temp_Query
SubReport.SourceObject = Temp_SourceObject
End Sub
After the Combo Boxes Work if the Data is going to Change like Site and Item Number then you might want to change the Row Source of the combo boxes to Use a Query that uses Select Distinct Site From QueryAllData. I don't know if Filter_Combo_Box2 step so it may need some correction. Hope this helps.

VB InputBox Validation Inquiry

I know InputBox isn't the best for validation, but that was one of the specifications on the program I am writing for class. My problem is that despite the if or case statements I make to validate the data entered, it still accepts the data while simultaneously displaying the MsgBox's I have in my code..
Essentially what I would like the case statement to do is to properly filter the data that is entered and not proceed onto the next floor if the data is invalid and request that new data be entered. If the data is valid, proceed onto the next floor.
Const ROOMS As Integer = 30
Const MAX_FLOOR As Integer = 16
Dim floor As Integer
Dim StrOccupancy As String
Dim occupancy As Integer
Dim occupancyRate As Double
Dim occupancySum As Integer
Dim overallRate As Double
lblOccupancyRate.Text = String.Empty
lblRoomsOccupied.Text = String.Empty
output.Items.Clear()
For floor = 1 To MAX_FLOOR
If floor = 13 Then
Continue For
End If
StrOccupancy = Integer.TryParse(InputBox("Enter the number of rooms occupied for floor:" & Space(1) & floor), occupancy)
Select Case occupancy
Case < 1
MsgBox("Please enter a number of 1 or more occupants.")
Case > 30
MsgBox("Amount of occupants must be between 1-30.")
Case >= 1 And occupancy <= 30
occupancyRate = (occupancy / ROOMS)
occupancySum += occupancy
overallRate = occupancySum / (ROOMS * 15)
End Select
output.Items.Add("Floor: " & floor & " Rooms Occupied: " & occupancy _
& " Occupancy Rate: " & occupancyRate.ToString("P2"))
lblRoomsOccupied.Text = occupancySum.ToString
lblOccupancyRate.Text = overallRate.ToString("P2")
Next
output.Items.Add("")
output.Items.Add("Total occupancy is" & Space(1) & occupancySum & Space(1) & "and" & Space(1) & overallRate.ToString("P2") & Space(1) & " of rooms are full.")
End Sub
Had a little time to check your code and actually you need a Boolean that validates if the occupancy requirements are met and loop if not. The code would be something like this:
For floor = 1 To MAX_FLOOR
'Boolean to validate the occupancy meet the requirements
Dim goodOccupancy As Boolean = False
'Do loop enters at least 1 time and runs the code inside it
Do
Integer.TryParse(InputBox("Enter the number of rooms occupied for floor:" & Space(1) & floor), occupancy)
Select Case occupancy
Case < 1
MsgBox("Please enter a number of 1 or more occupants.")
Case > 30
MsgBox("Amount of occupants must be between 1-30.")
Case >= 1 And occupancy <= 30
occupancyRate = (occupancy / ROOMS)
occupancySum += occupancy
overallRate = occupancySum / (ROOMS * 15)
'If the requirements are met we change the Boolean value to continue with the execution
goodOccupancy = True
End Select
'We loop if the requirements are not met
Loop Until goodOccupancy = True
output.Items.Add("Floor: " & floor & " Rooms Occupied: " & occupancy _
& " Occupancy Rate: " & occupancyRate.ToString("P2"))
lblRoomsOccupied.Text = occupancySum.ToString
lblOccupancyRate.Text = overallRate.ToString("P2")
Next
But please next time try to be more explicit with your code. Most of people won't check what is going on. Do not expect people to solve your problems without guidance. Please read the How to ask guide it will give you a light to use the site as it is supposed to be used

Using a form control as a field selector in SQL query

I am attempting to build a form ,called UI, that users will select a dimension parameter from a combobox "cmbFilter" and then add a +/- tolerance in a text box "txtTolerance". After selection a part number from a list this should return results for similar part numbers in the the tolorence range for that parameter. The field names in the table are the dimension parameters and are .AddItem to the combobox in the form load code.
Example. Part#1 OD is 5, so I select "OD" as the search parameter then I set a tolerance to +/- 1. The results should show Part#2 with a OD of 6 but not Part#3 with a OD of 7.
I have set a listboxs row source to the query but
no matter what I change in the syntax in this code I get operation or syntax errors. So I assume Im not referencing the form control right, or my logic isn't right?
I have tired the following code in the SQL design view in access.
SQL
SELECT Part_Matrix.Part_Number, Part_Matrix.Customer, Part_Matrix.Large_OD, Part_Matrix.Vent_Opening, & _
Part_Matrix.BPT, Part_Matrix.MFT, Part_Matrix.PD, Part_Matrix.Hat_ID, Part_Matrix.Microfinish, & _
Part_Matrix.Turn_Operations, Part_Matrix.Stud_Holes, Part_Matrix.SH_Dimensions, Part_Matrix.Manufacturer_Holes, & _
Part_Matrix.MH_Dimensions, Part_Matrix.Other_Holes, Part_Matrix.Other_Dimension
FROM Part_Matrix
WHERE [Forms]![UI]![cmbFilter]
BETWEEN (((SELECT [Forms]![UI]![cmbFilter] FROM Part_Matrix WHERE Part_Number = [Forms]![UI]![lbSelected]) - [Forms]![UI]![txtTolerance])
AND ((SELECT [Forms]![UI]![cmbFilter] FROM Part_Matrix WHERE Part_Number = [Forms]![UI]![lbSelected]) + [Forms]![UI]![txtTolerance]))
ORDER BY [Forms]![UI]![cmbFilter] DESC;
I have also tried to write the SQL code in access vba still no luck, the code below was just a simple text, I know its now the same logic as above.
Private Sub btnSearch_Click()
Dim SQL As String
If txtTolerance = "" Then
MsgBox ("No Tolerance Entered")
Exit Sub
ElseIf cmbFilter = "" Then
MsgBox ("No Filter Criteria Entered")
Exit Sub
Else
SQL = "SELECT Part_Matrix.[Part_Number], " & Me.cmbFilter & " " & _
"FROM Part_Matrix" & _
"ORDER BY " & Me.cmbFilter & " DESC;"
Debug.Print SQL
DoCmd.RunSQL SQL
lbFilterResults.RowSource = SQL
lbFilterResults.Requery
End If
End Sub
Try this, using a dlookup instead of SELECT to return the values you want in the BETWEEN statement. I believe the dlookup should return the value for whatever field you select in the combo box. Also, I've simplified to remove the forms!UI statement with a "me" assuming you are running code from the same form. Let me know if this works for ya.
intTarget = dlookup(me!CmbFilter, "PartMatrix", "Part_Number = " & me!LbSelected)
intLower = intTarget - me!txtTolerance
intUpper = intTarget + me!txtTolerance
strSQL = "SELECT * FROM Part_Matrix WHERE " & me!cmbFilter & " " & _
"BETWEEN " & intLower & " AND " & intUpper
In your BETWEEN statement, reference the table's [Large_OD] field and not the form'S.
i.e
WHERE Large_OD
BETWEEN (((SELECT Large_OD FROM Part_Matrix WHERE Part_Number = [Forms]![UI]![lbSelected]) - [Forms]![UI]![txtTolerance])
AND ((SELECT Large_OD FROM Part_Matrix WHERE Part_Number = [Forms]![UI]![lbSelected]) + [Forms]![UI]![txtTolerance]))
ORDER BY " & Me.cmbFilter & " DESC;

How to run query, automate using VBA Macro and Excel, make "loading" feature while reconciling?

I am building a reconciliation tool via VBA that automates queries from my oracle database and a worksheet. When I run the query I want the user to input what ITEM (in this case pipeline) to query (the worksheet has many items) and the end/start dates. I am having trouble figuring out the following:
1) It is querying - if the value is NULL, how may I tell it to print out "DATA NOT AVAILABLE"
2) How can I clear up the old output from pipeline A, when I am querying pipeline B?
3) My dates are saved as strings in Oracle - how can I convert that to date?
Thank you!
Here is what I have so far:
Option Explicit
Option Base 1
Dim cnnObject As ADODB.Connection
Dim rsObject As ADODB.Recordset
Dim strGPOTSConnectionString As String
Dim startDate As Date
Dim endDate As Date
Dim strPipelineName As String
Dim strQuery As String
Sub ClickButton2()
Debug.Print ("Button has been clicked")
Dim Pipeline As String
Dim DateStart As Date
Dim DateEnd As Date
Pipeline = InputBox("Enter PipeLine", "My Application", "Default Value")
DateStart = InputBox("Enter Start Date", "My Application", DateTime.Date)
DateEnd = InputBox("Enter End Date", "My Application", DateTime.Date + 1)
Pipeline = Range("B1").Value
DateStart = Range("B2").Value
DateEnd = Range("B3").Value
strQuery = "select pipelineflow.lciid lciid, ldate, volume, capacity, status, " & _
"pipeline, station, stationname, drn, state, county, owneroperator, companycode, " & _
"pointcode, pottypeind, flowdirection, pointname, facilitytype, pointlocator, " & _
"pidgridcode from pipelineflow, pipelineproperties " & _
"where pipelineflow.lciid = piplineproperties.lciid " & _
"and pipelineflow.audit_active = 1 " & _
"and pipelineproperties.audit_active =1 " & _
"and pipelineflow.ldate >= '" & Format(DateStart, "dd-MMM-yyyy") & "' and pipelineflow.ldate < '" & Format(DateEnd, "dd-MMM-yyyy") & "' " & _
"and pipelineflow.ldate >= '" & DateStart & "' and pipelineflow.ldate < '" & DateEnd & "' " & _
"and pipelineproperties.pipeline = '" & Pipeline & "' "
Call PullZaiNetData(strQuery)
Call TieOut
End Sub
Sub PullZaiNetData2(ByVal strQry As String)
Set cnnObject = New ADODB.Connection
Set rsObject = New ADODB.Recordset
strGPOTSConnectionString = "DRIVER={Microsoft ODBC for Oracle}; SERVER=hhh; PWD=hhhh; UID=hhh"
cnnObject.Open strGPOTSConnectionString
rsObject.Open strQry, cnnObject, adOpenStatic
Worksheets("ZaiNet Data").Cells(1, 1).CopyFromRecordset rsObject
rsObject.Close
cnnObject.Close
Set rsObject = Nothing
Set cnnObject = Nothing
End Sub
Sub TieOut()
End Sub
Since you changed your questions, I'll add another answer.
1) It is querying - if the value is NULL, how may I tell it to print out "DATA NOT AVAILABLE"
Which value? I suspect that you mean when the query returns no records. To check this, test for rsObject.RecordCount = 0:
Dim ws As Worksheet
Set ws = Worksheets("ZaiNet Data")
ws.UsedRange.Clear '' remove results of previous query if any
If rsObject.RecordCount = 0 Then
ws.Cells(1, 1) = "DATA NOT AVAILABLE"
Else
ws.Cells(1, 1).CopyFromRecordset rsObject
End If
You can also test for one or both of rsObject.BOF or rsObject.EOF being true ("Beginning Of File" or "End Of File" respectively).
When developing things in VBA, especially when using new features that I'm unfamiliar with, I do lots of tests that output things to the Immediate Window. To help with this, I use the following little routine:
Sub Say(s as String)
Debug.Print s
End Sub
It makes it a little easier to generate testing output that typing "Debug.Print" all the time (even slightly easier than typing "Debug.P" + Enter using Intellisense).
So when you open your recordset, show the record count after it:
rsObject.Open strQry, cnnObject, adOpenStatic
Say rsObject.RecordCount & " records"
Do something like this any time you want to verify a value.
Later on, if you want to capture your debugging statements in a text file, you just need to change the operation of the Say() routine.
2) How can I clear up the old output from pipeline A, when I am querying pipeline B?
As shown in context above:
ws.UsedRange.Clear '' remove results of previous query if any
3) My dates are saved as strings in Oracle - how can I convert that to date?
You don't technically need to convert the resulting date strings to date values, you may find that just by putting them in a cell, Excel will treat them as date values.
You just need to make sure that the user's dates get converted to the format that the database is expecting.
Your query string as it stands above still shows two lines incorporating the user's dates. The one that uses Format() to convert them to "dd-MMM-yyyy" format is the one you want to keep. Delete the other line, making sure your string concatenating syntax is still correct.
To actually convert the date string to a date value though, you would use the CDate() function:
Sub DateTest()
Dim sDate As String
Dim dDate As Date
sDate = "09-Jul-2009"
dDate = CDate(sDate)
Say "sDate = " & sDate
Say "dDate = " & dDate
dDate = dDate + 1
Say "dDate = " & dDate
End Sub
Immediate Window output:
sDate = 09-Jul-2009
dDate = 7/9/2009
dDate = 7/10/2009
We can verify that it converted the string to a date value because it shows up in the default date format for my machine, and responds to date math (adding 1 day).
Answers to previous questions (paraphrased):
1) "how to make sure end date is after start date":
Valid date values are floating point numbers, so DateEnd should be >= DateStart. The whole number part is the number of days since 1900-01-01. The fractional part is the current time of day (eg 12 noon = 0.5).
2) "use fancy calendar entry controls for dates"
Look at the controls available under the Insert> Object menu (in Excel 2003 and earlier - it's in 2007 too, but in a different place). One of them is a Calendar control. Double-clicking it in the Objects list will insert it into the current cell and put the sheet into Design Mode. Right click the control and choose Properties. Type a cell address into the LinkedCell field. Then click the "Exit Design Mode" button from the little toolbar that should have popped up. Now when you select a date on the control, it will show the value in the cell you linked it to.
Similarly there is a drop down list control that you can use to select your pipeline types.
3) "why am I getting an error on DateEnd = Range("B3").Value?"
The DateEnd error is probably due to a missing or invalid value in the cell you specified, as I asked in my comment.
What version of Excel are you doing this in? Excel 2003