How to get info from a listbox populated by an SQL query? - sql

The title says the vague question, but, I will be more specific. I'm more of a hardware oriented person with some experience in VB, Java, and C++. I've been asked to modify a form in Access which uses SQL queries to take information from a database. The edit I am trying to make is to a form that has selections to narrow down the data it queries from to appear in a listbox in the center of the form (so, like radio buttons to specify a certain height or weight of an object in the database). The selections, as they are selected, concatenate additional specifications to an string that is then run as an SQL query. What I am trying to accomplish is to take a column of the narrowed-down data and find the maximum number in the column and the average of the numbers in the column. It seems really simple and know how to do that with regular lists and arrays, but I'm at a loss with my limited knowledge. I've considered making another SQL string, but in another part of the form, it was done with two strings (so, one to put the data in the listbox from the database and one to pull the specific column of the narrowed down data). That being said, it doesn't seem logical to me to pull the same sets of data each time, so I'm wondering if I can just pull the info from the already pulled info. At the bottom of the code set is this:
ItemList.RowSource = vSQLStock
ItemList = Null
ItemList.Requery
QuoteList.RowSource = vSQLNonStock
QuoteList = Null
QuoteList.Requery
Both vSQLStock and vSQLNonStock have their own sets of SQL strings that are run by this function, or as far as I can tell (I'm still studying up on SQL) put the narrowed down items in the QuoteList listbox. What I'm asking is if there is a way with any function that can be used to go through this information? Specifically, take a column and do some calculations on the data. I don't want to run another SQL query and bog down the server, but rather manipulate the data on the user's computer.
An example of what happens is the user selects whether the item is stock/nonstock, searches by the name/code/ID, and then puts all the matches on the listbox on the form. The listbox shows lines of data with columns like Name, Cost, Size, Weight, etc. of which I am looking to do calculations on the Cost column. Hopefully this is enough information; I appreciate any advice.

It looks from your question like you are attempting to get the Maximum and the Average from a SQL query.
the syntax:
SELECT MAX(myColumn) as MyMax, AVG(myColumn) as MyAverage
FROM myTable
WHERE . . .
Will return the Maximum and Average Values within SQL Server or within MS Access

If you're really bound and determined to do this locally with the data you've already retrieved from the server, then you probably need to look into working with adodb.recordsets. You can kind of treat it like an array. Kind of.
I really recommend querying the server for the data you need though. It's a world simpler.
dim rs as ADODB.Recordset
Set rs = QuoteList.Recordset
rs.MoveFirst
Do Until rs.EOF
' loop through recordset doing something
rs.MoveNext
Loop

Related

delphi create sql select statement at runtime

I am attempting to create a sql statement in XE8 at runtime to search an oracle database based on the value in a textbox. I find multiple different ways that attempt to explain this online, but I am not understanding what it is asking.
I want to search a server based on a select statement and populate TDB components (labels only) based on the data. The furthest I have gotten is to get data populated, but the where
' ... somevalue = ' + textbox.text;
seems to have no effect.
What components do I need to make this happen? I am connected to the database, and it appears that I can get some kinda data out of it, but I can't seem to figure out how to filter the results. Obviously, I cannot create this sql statement at design time as the value of textbox.text will change depending on the user's input.
My error was in how to dynamically change what the data aware components got data as it would not always be the same. I had to manually go in and modify their datafield properties. Once I did this, my query functioned correctly.

query filtering, finding the balance between flexibility and ease of execution

So I've been researching for days now on how to filter a rowsource result on a control in a way that is comfortable, hopefully you understand what I mean by that as I explain. I have found solutions, a bunch of solutions. I'm more concerned with evaluating their benefits and negatives.
I have a specific example, but my concern is really more generic. This, to me, seems like the backbone of my application and so I want to make sure it's being done correctly, the best way, not just in a way that "works".
Basically, I have progressive combo box filters. The first box filters the second box, which then selects a record in a Single Form view. The two combo boxes are in the header of the form.
Lets say I have a table CanadianCities. The two combo boxes might be, cboProvinceFilter "Filter by Province", and cboCitySelect "Select City"
When I load the form the province filter is off, so the cities list is populated with a rowsource that selects ALL the cities (SELECT ID, CityName FROM CanadianCities). But that's a big list, so I have the second combo box to narrow that list down by province (SELECT ID, ProvinceName FROM CanadianProvinces).
So the goal is that on cboProvinceFilter.AfterUpdate to requery cboCitySelect with an altered where clause ("[...] WHERE ProvinceID = [cboProvinceFilter]").
The problem is in how to alter the where clause. Ideally, the above would work right in the designer, but SQL designs seem to be out of the form's scope so cboProvinceFilter doesn't exist there. I agree with the opinion that direct referencing forms is bad. I don't want to marry my sql to the form like that. Plus, I want to use a navigation form, but also have a mobile option, so running the forms individually AND in navigation would be ideal, absolute referencing can't do this.
Having my repetitious SQL statements buried in code feels like poor design, and repeating the same queries with slightly different filtering is terrible when Parameters are exactly for that reason.
And some will scoff at this, but it also feels bad to rewrite the functionality of the Access designer in VBA. If I build my own SQL, execute my own queries, and populate my own lists, why did Microsoft put all the effort into building this productivity assisting tool for? Filtering is not exactly an obscure feature of database management... I feel like there must be a reasonable way to do this sort of thing.
Also, popup forms are obnoxious, so I won't be making specific forms just to have reliable absolute references. That definitely feels like a cop-out.
Solutions that do feel good but I haven't made work...
SQL Parameters
The most sensible way of doing this I feel should be with SQL Parameters, as that's what they're intended for right? The QueryDef would store values for it's parameters that could I could change as needed. However, I would let the queries execute naturally on requery.
So instead of writing the handful of lines to execute the Query and populate the control, I'd just set the parameter values and call requery on my control, which has all that functionality built into it.
So defined some parameters in the SQL statement, then tried to set the values of those parameters in VBA before the Query was executed, but JET always seems to pop-up for the parameters if it doesn't reference an actual object, it wasn't checking my code-set querydefs.
For that to work, it seems that I'd have to execute the SQL manually, and parse my own recordset, and populate the control. Which feels like an excessive amount of repetition for every filter option I'd want to offer.
Relative Referencing
I don't mind referencing forms as long as it's a relative path. Unfortunately [Screen].[ActiveForm] refers to the navigation form, not the actual, active form... So that seems to be out.
Right now I'm thinking my only option is to set rowsource manually then call the control's requery. that's the less offensive feeling option. Might be best to take the current query and string replace the where portion, so i don't have to update every event if the query structure changes.
Final Thought
Anyway, this is getting ranty, so let me know your thoughts. I'm not really looking for code solutions, which is why I offered few to no hard examples. I'm looking for a paradigm for managing this kind of filtering that isn't too restrictive (absolute referencing) or too repetitive/wheel-re-inventing (hard coded sql, executing, control populating).
If your Access version is >= 2007, you can use the TempVars Collection. Here is an Immediate window session.
' add a TempVar with value
TempVars.which_id = 12
' or do it explicitly with Add method
TempVars.Add "which_id", 12
? TempVars!which_id
12
' asking for the value of non-existent TempVar returns Null
? TempVars!bogus
Null
A query can reference the TempVar to filter the result set.
SELECT f.*
FROM tblFoo AS f
WHERE f.id=[TempVars]![which_id] OR [TempVars]![which_id] Is Null;
So you could use that approach in the row source query for the cboCitySelect combo box. Then assign the TempVar value in the After Update event of cboProvinceFilter and next Requery cboCitySelect.
For Access versions < 2007, the TempVars Collection is not available. In that situation you could use a custom VBA function to hold a static value which can be referenced in a query.
SELECT f.*
FROM tblFoo AS f
WHERE f.id=TargetId() OR TargetId() Is Null;
Public Function TargetId(Optional ByVal pValue As Variant) As Variant
Static varReturn As Variant
If IsMissing(pValue) Then
If VarType(varReturn) = vbEmpty Then
varReturn = Null
End If
Else
varReturn = pValue
End If
TargetId = varReturn
End Function

Access 2010 Database Clenup

I have problems with my records within my database, so I have a template with about 260,000 records and for each record they have 3 identification columns to determine what time period the record is from and location: one for year, one for month, and one for region. Then the information for identifying the specific item is TagName, and Description. The Problem I am having is when someone entered data into this database they entered different description for the same device, I know this because the tag name is the same. Can I write code that will go through the data base find the items with the same tag name and use one of the descriptions to replace the ones that are different to have a more uniform database. Also some devices do not have tag names so we would want to avoid the "" Case.
Also moving forward into the future I have added more columns to the database to allow for more information to be retrieved, is there a way that I can back fill the data to older records once I know that they have the same tag name and Description once the database is cleaned up? Thanks in advance for the information it is much appreciated.
I assume that this will have to be done with VBA of some sort to modify records by looking for the first record with that description and using a variable to assign that description to all the other items with the same tag name? I just am not sure of the correct VBA syntax to go about this. I assume a similar method would be used for the backfilling process?
Your question is rather broad and multifaceted, so I'll answer key parts in steps:
The Problem I am having is when someone entered data into this
database they entered different description for the same device, I
know this because the tag name is the same.
While you could fix up those inconsistencies easily enough with a bit of SQL code, it would be better to avoid those inconsistencies being possible in the first place:
Create a new table, let's call it 'Tags', with TagName and TagDescription fields, and with TagName set as the primary key. Ensure both fields have their Required setting to True and Allow Zero Length to False.
Populate this new table with all possible tags - you can do this with a one-off 'append query' in Access jargon (INSERT INTO statement in SQL).
Delete the tag description column from the main table.
Go into the Relationships view and add a one-to-many relation between the two tables, linking the TagName field in the main table to the TagName field in the Tags table.
As required, create a query that aggregates data from the two tables.
Also some devices do not have tag names so we would want to avoid the
"" Case.
In Access, the concept of an empty string ("") is different from the concept of a true blank or 'null'. As such, it would be a good idea to replace all empty strings (if there are any) with nulls -
UPDATE MyTable SET TagName = Null WHERE TagName = '';
You can then set the TagName field's Allow Zero Length property to False in the table designer.
Also moving forward into the future I have added more columns to the
database to allow for more information to be retrieved
Think less in terms of more columns than more tables.
I assume that this will have to be done with VBA of some sort to modify records
Either VBA, SQL, or the Access query designers (which create SQL code behind the scenes). In terms of being able to crunch through data the quickest, SQL is best, though pure VBA (and in particular, using the DAO object library) can be easier to understand and follow.

Get column name & table name from value

Actually I have a new client & their Database has no standard naming conventions & the application is in classic asp.I have a form in which a form there are many values in the different textboxes, it it very difficult to trace the value come from which table.& also there is no erd.
I need a query from which I can get the table name with column name by giving Value.
Let's suppose I have a value having label name abc#= '6599912268'
& the new project has no ERD no standard of naming conventions... I need a fast way to know the abc# ='6599912268' is taking from which table & which column name.... like this the UI has many values which is time taken to trace manually
Is there any way to trace it?
The simple answer is no. There is no way to trace table/column it comes from by mere inspection of the value.
I suggest the following.
Find out what type of db your product is using. Where it is situatede, do you have access to it.
If you have access to the database, get to know the db structure. What each table is meant to store, the relationships etc. Speak to the db administrator or the business analayst to increase your knowledge on the product domain.
Once you have the db structure, try and compare the table to the page. Eg. The user details will most like be stored in a db table named 'Users' or 'Membership' Catch my drift?
Then have a look at the web sites source code. Look at the specific page you are at. Is the sql code embedded in the source code (asp page) or does it call a COM server or something similar? If you are "lucky" (and I say lucky for on the purpose of your problem that you are having) you fill find the sql code in the asp page.
If it calls a COM object or something similar, then you will have to dig up the source code for that, and that is most likely where you sql will reside.
There is no easy way to do this, you have to use a stored procedure to loop over all the tables in the database and search for the value, and it will probably take a while.
There's a stored procedure and examples here: Search all columns in all the tables in a database for a specific value. You'll see there are stored procedures for finding dates, strings, numbers.
Not possible, and If you search the column with the value, there is a possible chance that you get multiple columns with the same value, so how would you differentiate them and the same case is for the table.

access report from dynamic crosstab query and vba to "manually" generate reports

I have come across the problem of generating complex access reports (by complex I mean with data processing, variable number of fields, among others).
Let me explain in deeper detail some of the things I need to implement:
Some fields should not show according to some values in a query
If a certain record does not exist, a nice colored (very noticeable) message should appear instead of the values that would be there (Suppose, for example, that a record with 03/04/2009 in the date field exists, a record with 03/06/2009 in the date field also exists but no record with 03/05/2009 exists. Before showing the data related to the last record, I should print something like "Didn't show up on 03/05/2009")
A bar chart that takes as data not the values in the records, but instead something else that is calculated over a set of records (like an average of all grades for a certain date). The number of series in this chart also varies according to values in the records, this chart would not be in the detail section, but instead in the page heading or some kind of group heading.
It should also be mentioned that the query is a TRANSFORM query (more precisely, an INNER JOIN of many TRANSFORM queries), and thus the number of columns returned by the query varies. While in the past I've been unable to bind this query as the recordsource for the report, somehow Access stopped complaining for now (can someone please clarify this? Is this normal, should I not worry about it and use it as a recordsource or should I avoid it?)
There are two options to achieve what I want (that I can see for now):
Create a report with no record source and lots of unbound fields, and through several events (Report_Open, Section_Format, etc.) and with the help of DAO, manually set the values of these fields. Changing the Data Series of the chart is also possible through VBA.
Set the record source to the query, and create some crazy and confusing VBA code to deal with the data and implement everything I need.
It seems to me that option 2 is going to be a huge headache and waste of time, and I recognize option 1 is pretty much like writing to an Excel file (since all the data is obtained with DAO), which would be much easier since I have much more control over almost everything there (but for many other reasons, we want everything in an access report)
While I'm biased and intend to go with option 1, I have found several problems with this option, for example:
I can't find a way to create new pages in the report with VBA, and thus I'm limited only to the first page.
Lack of some kind of free, online, decent and complete documentation on VBA and Access Reports
Also, if option 2 is more viable, I'm certainly willing to go with it, but I would also need some advice, and perhaps some tips to solving the problems I mentioned in this question.
So, the questions are:
Where can I find some decent and complete documentation on Access Reports and VBA?
How can I create pages in an access report, and choose which page I want to write to?
With the problem I have in my hands, will I reach any bottlenecks I should know about? Should I already be thinking of alternatives to Access Reports (writing to a spreadsheet, for example?)
Sounds like you want to dynamically create the report and avoid all the dummy text boxes.
In regard to:
I can't find a way to create new pages
in the report with VBA, and thus I'm
limited only to the first page.
Your solution #1 seems to assume an unbound report.
I think what I'd do is have the form the crosstab as the rowsource, so you'd have records to generate the pages, and then define your report's controls with no ControlSource (except for the controls that are bound to fields that are always present in the CrossTab). Then you could assign the ControlSources at runtime based on the particular columns. Here's the SQL for a crosstab grabbed from an app I'm working on now:
TRANSFORM First(impNoMatch.PersonID) AS FirstOfPersonID
SELECT impNoMatch.LastName, impNoMatch.FirstBame
FROM impNoMatch
GROUP BY impNoMatch.LastName, impNoMatch.FirstName
PIVOT impNoMatch.Status;
Now, you know that the fields in the SELECT clause will always be present, so if you opened a recordset on the SQL string you are using and count the number of fields in the recordset's Fields collection (you can't use the report's Recordset unless it's an ADO recordset, i.e., not bound to the Recordsource):
Dim strSQL As String
Dim rsFields As DAO.Recordset
Dim lngFieldCount As Long
strSQL = Me.Recordsource
Set rsFields = CurrentDB.OpenRecordset(strSQL)
lngFieldCount = rsFields.Fields.Count
From that, since you know the number of fields in the SELECT statement (i.e., the row headings), you can calculate the number of dynamic controls you want to assign, and you can use this recordset's fields collection to assign the ControlSources and unhide the controls.
You'd start out with all your controls that will display the dynamic fields set so their Visible property is FALSE. You'd also use a naming convention for those controls. In the code below, I've used txtNN, where NN is the numeric index in the Fields collection formatted as 2 digits. Here's the code (which adds lines to what's listed above, and is run in the OnOpen event):
Dim strSQL As String
Dim rsFields As DAO.Recordset
Dim lngFieldCount As Long
Dim l As Long
Dim strControlName As String
strSQL = Me.RecordSource
Set rsFields = CurrentDb.OpenRecordset(strSQL)
lngFieldCount = rsFields.Fields.Count
For l = 2 To lngFieldCount - 1
strControlName = "txt" & Format(l, "00")
Me(strControlName).ControlSource = rsFields.Fields(l).Name
Me(strControlName).Visible = True
Next l
rsFields.Close
Set rsFields = Nothing
Now, if you want to get fancy, you can reformat the controls, changing widths and horizontal/vertical position. If you do that, you have to do it in a different event, and it's a bit tricky to choose that. The only good place to put it is in a report group's header's OnFormat event. If you don't have any grouping, you can add one that doesn't do anything. In the case of my crosstab, a two-level sort on Lastname and Firstname and a header on the Firstname group with nothing in it is a good place to use the OnFormat event to change the appearance/layout of the controls on your report.
As to your question about how to learn how to do this, I recommend picking up an intermediate/advance Access programming book. The Access Developers Handbook is the gold standard on this, and includes tons of examples of programmatic control of reports.