MS Access SQL Switch Function - sql

I have several tables with the same data structure (they're filled with a bunch of stuff, in separate .accdb files to account for the 2GB limit) and need to retrieve info from one of them based on a field in a form.
Upon researching I came up with the following, but it won't seem to work.
SELECT MyNumber, MyName, MyPage, MyDrawing
FROM Switch([Forms]![View_Info]![Contract] = "Contract1", "tblContract1", [Forms]![View_Info]![Contract] = "Contract2", "tblContract2")
WHERE (MyNumber = [Forms]![View_Info]![MyNumber])
Syntax error in FROM clause.
In this example I only used 4 fields and 2 tables but in fact there are around 9 tables and 20 fields in each that I wish to retrieve.
Can someone shed some light on this? I have a really hard time with SQL, so I apologize if this is quite basic.
Thanks in advance, Rafael.

You cannot return the table name from a function in the SQL FROM clause. If your table is determined dynamically, then you must build the SQL command string dynamically.
Dim tableName As String, sql As String
tableName = Switch(...)
sql = "SELECT ... FROM [" & tableName & "] WHERE ..."
As #forpas explains in his answer, you can use a UNION query, but this will always query all the tables. Since the filter is not based on a table column, the filtering will occur on the client side, i.e. in your application.

Try this UNION:
SELECT MyNumber, MyName, MyPage, MyDrawing
FROM tblContract1
WHERE (MyNumber = [Forms]![View_Info]![MyNumber]) AND [Forms]![View_Info]![Contract] = "Contract1"
UNION
SELECT MyNumber, MyName, MyPage, MyDrawing
FROM tblContract2
WHERE (MyNumber = [Forms]![View_Info]![MyNumber]) AND [Forms]![View_Info]![Contract] = "Contract2"
Each query of the UNION contains in the WHERE clause the condition:
[Forms]![View_Info]![Contract] = "Contract?"

Related

How to get the list of non empty queries?

In MS Access I have 1 table that updates daily via external file and 50 queries (named 01_query, 02_query... 50_query), all with same columns and logic but with different filters. Some returns result, others are empty.
How can I get the list (using another query) with the names of NON empty queries?
I found the way to get a list of all query names with this code
SELECT MSysObjects.Name
FROM MsysObjects
WHERE (Left$([Name],1)<>"~") AND (MSysObjects.Type)=5
ORDER BY MSysObjects.Name
but I can't figure out how to filter out the "empty" queries.
If you absolutely must have an Access SQL solution to produce your list, consider something other than UNION of 50 data sources. Access does not allow you to UNION an unlimited number of data sources, but I don't recall what that limit is. And even if it allows you to UNION 50, I still wouldn't do it.
I tested this one in Access 2010 and it produces the result I think you're looking for. Since you've demonstrated you have read permission on MsysObjects it should work for you, too.
SELECT
sub.Name
FROM
(
SELECT
m.Name,
IIf(
m.Name ALike '[0-9][0-9][_]query' AND m.Type=5,
DCount('*', m.Name),
0
) AS non_empty_target_query
FROM MsysObjects AS m
) AS sub
WHERE sub.non_empty_target_query=True
ORDER BY sub.Name;
The IIf() expression is the key to this query. In human-like speak it says, if the object is a query and its name starts with 2 digits followed by an underscore followed by "query", return the count of rows from that query; otherwise just return zero.
Then the parent query filters away those rows where non_empty_target_query is zero (False), leaving only rows containing the names of your "non-empty" queries.
Assuming that all your queries follow the same format, you actually don't need to do anything with MSysObjects. You can just do a simple loop (in VBA):
Public Sub GetNonEmptyQueries()
Dim db As DAO.Database, qdf As DAO.QueryDef
Dim rs As DAO.Recordset
Dim queryName As String
Dim i As Integer
Set db = CurrentDb
For i = 1 To 50
queryName = format(i, "00") & "_query"
Set qdf = db.QueryDefs(format(i, "00") & "_query")
Set rs = qdf.OpenRecordset
If rs.recordCount > 0 Then
' do whatever you need to do with the query name here
Debug.Print qdf.Name
End If
Next i
End Sub
If you don't want to use VBA, it's possible to write a query that UNIONs the COUNT(*) of all your queries. Something like this:
SELECT "01_query" AS QueryName, Count(*) AS [Count] FROM 01_query HAVING COUNT(*) > 0
UNION
SELECT "02_query", COUNT(*) FROM 02_query HAVING count(*) > 0
...
UNION
SELECT "50_query", COUNT(*) FROM 50_query HAVING COUNT(*) > 0
Of course, you're going to have to add all the queries by hand, which is going to get rather tedious. I think the time you would spend hand-writing such a query might be better-spent reading up on VBA, so you can use the first option. :)

vb.net DAL Specify columns returned

I have a Data Access Layer class that has a method (GetPeople) that will retrieve records from a SQL Server table (people). This table has more than 20 fields, including varbinary type.
Right now, SQL query is something like
SELECT * FROM people
From my BLL class, I will call DAL.GetPeople(), which will return all columns.
What would be the best way to specify which columns to return, so I could improve performance? For example, sometimes I would like to return all fields, other times, just one or two.
UPDATE
To explain it better:
In DAL I have a method GetPeople() which calls a SQL Server function GetPeople.
In BLL I have a method GetPeople() which calls DAL.GetPeople(), after doing some business logic.
In my presentation layer, I call BLL.GetPeople().
This is working, but on SQL function, I have "SELECT * FROM people". Sometimes I would like to retrieve only one column (eg. name) from table, but in this case all columns are returned, which I think is affects performance.
So, I would like to have a kind of dynamic SELECT query on this SQL Server function, whose columns returned would depend on how I call the function...
I think you are after something like this where you can pass in a comma-seperated list of column names
Private Function GenerateQuery(ByVal columnNames As String) As String
' columnNames in the following format 'column1,column2,column3'
Dim lstColumnNames As String() = Split(columnNames, ",")
Dim strSQL As New StringBuilder
strSQL.Append("SELECT ")
For intColNumber As Integer = 0 To lstColumnNames.GetUpperBound(0)
strSQL.Append("[")
strSQL.Append(lstColumnNames(intColNumber))
strSQL.Append("]")
If intColNumber < lstColumnNames.GetUpperBound(0) Then
strSQL.Append(", ")
End If
Next
strSQL.Append(" FROM People ")
Return strSQL.ToString
End Function
You can use it like this: SqlCommand.CommandText = GenerateQuery("column1,column2,column3")
The column names are wrapped in [] symbols so you don't have to worry about reserved words causing the database to error.
Change your SQL-query to something like
SELECT column1, column2, column3 FROM people;
EDIT:
What you are going to need to do is create function that will put your SQL string together for you. When i did this before, I had all of the available fields in a checked-list control, and if i wanted them pulled, I checked them. The checked items were then put through the function to assemble the string. It should be pretty simple since there are not any joins going on.

How do I run an SQL update query using a like statement

I am trying to update a field in a table using an SQL update query where there is a like statement referencing a value in another table. They syntax unfortunately is not working. Below is my code. In short, I am trying to put a '1' in the field 'Query07ParolaChiave' in the table 'tblSearchEngine01' when the value located in table 'tblsearchengine07' is present in the field 'tblMasterListOfEventsNotes' located in the table 'tblSearchEngine01'. I think my code is almost complete but there is a syntax issue which i cant find.
st_sql = "UPDATE tblSearchEngine01, tblSearchEngine07 SET tblSearchEngine01.Query07ParolaChiaveSelect = '1' WHERE ((([tblSearchEngine01].[tblMasterListOfEventsNotes]) Like " * " & [tblsearchengine07].[ParolaChiave] & " * "))"
Application.DoCmd.RunSQL (st_sql)
I suggest you 2 solutions :
This one is using EXISTS functions, and will check for each row in tblSearchEngine01 if there is a matching value in tblsearchengine07
UPDATE
tblSearchEngine01
SET
tblSearchEngine01.Query07ParolaChiaveSelect = '1'
WHERE
EXISTS (SELECT 1
FROM tblsearchengine07
WHERE [tblSearchEngine01].[tblMasterListOfEventsNotes] Like '*' & [tblsearchengine07].[ParolaChiave] & '*')
This one is more performant because it uses JOIN
UPDATE
tblSearchEngine01
INNER JOIN tblsearchengine07
ON [tblSearchEngine01].[tblMasterListOfEventsNotes] Like '*' & [tblsearchengine07].[ParolaChiave] & '*'
SET
tblSearchEngine01.Query07ParolaChiaveSelect = '1'
I read something like in ADO/VBA, you have to use % instead of * as the wildcard.
You can have more information on wildcard and LIKE comparator here
UPDATE
Why the '1' after select in your first solution?
EXISTS (SELECT 1 ... is better for performance because it return only the number 1 instead of fields, anyway EXISTS just stop the excecution after 1 element found.
'Performant' means more consuming in regards to space and memory?
JOIN is more performant in term of time of execution, RDBMS are far better at joining tables than using subquery, in some rare case, it's more interesting to use the 1st solution.
Also, any initial thoughts as to why my original solution (coming straight from an Access Query which works) does not function?
I cannot really know but perhaps it's because of " * ", because you are saying SPACE + * + SPACE + VALUE + SPACE + * + SPACE. For ex : 'John' LIKE ' John '
May be with "*" instead of " * " could solve it...
I have no other track, I'm not Access sql developper, I usually play around Sql server/Oracle/mySql, hope it helped. ;)
Try to change your like this way:
... Like '*" & tblsearchengine07.parolachiave & "*'))"
The like statement go into the WHERE clause.
If you do want to use LIKE without you care about caps letters, then you can use it like this:
LIKE COLUMN_NAME = '%WhatYouLike%'
My suggestion is:
Use a table variable (#Table) with a unique/primary key coming from the table to be updated.
SELECT all the data to be updated (you can add the like statement here) and then INSERT that in the created table variable.
Construct the UPDATE statement with an INNER JOIN to the table variable matching with the unique/primary key.
I know this may take a lot of steps but believe me these are more efficient than using a black list approach.

how to replace text in a multifield value column in access

I've got a tablea such as below, I know its bad design having multifield value column but I'm really looking for a hack right now.
Student | Age | Classes
--------|------|----------
foo | 23 | classone, classtwo, classthree, classfour
bar | 24 | classtwo, classfive, classeight
When I run a simple select query as below, I want the results such a way that even occurrence of classtwo is displayed as class2
select student, classes from tablea;
I tried the replace() function but it doesnt work on multivalued fields >_<
You are in a tough situation and I can't think of a SQL solution for you. I think your best option would be to write a VB function that will take the string of data, parse it out (replacing) the returning you the updated string that you can update your data with.
I can cook up quite a few ways to solve this.
You can explode the mv by using Classes.Value in your query. This will cause one row to appear for each value in the query and thus you now can use replace on that. However, this will result in one separate row for each class.
So use this:
Select student, classes.Value from tablea
Or, for this example:
Select student, replace(classes.Value,"classtwo","class2") as myclass
from tablea
If you want one line, AND ALSO the multi value classes are NOT from another table (else they will be returning ID not text), then then you can use the following trick
Select student, dlookup("Classes","tablea","id = " & [id]) as sclasses
from tablea
The above will return the classes separated by a space as a string if you use dlookup(). So just add replace to the above SQL. I suppose if you want, you could also do replace on the space back to a "," for display.
Last but not least, if this those classes are coming from another table, then the dlookup() idea above will not work. So just simply create a VBA function.
You query becomes:
Select student, strClass([id]) as sclasses from tablea
And in a standard code module you create a public function like this:
Public Function strClass(id As Variant) As String
Dim rst As DAO.Recordset
If IsNull(id) = False Then
Set rst = CurrentDb.OpenRecordset("select Classes.Value from tableA where id = " & id)
Do While rst.EOF = False
If strClass <> "" Then strClass = strClass & ","
strClass = strClass & Replace(rst(0), "classtwo", "class2")
rst.MoveNext
Loop
rst.Close
Set rst = Nothing
End If
End Function
Also, if you sending this out to a report, then you can DUMP ALL of the above ideas, and simply bind the above to a text box on the report and put the ONE replace command around that in the text box control. It is quite likely you going to send this out to a report, but you did ask how to do this in a query, and it might be the wrong question since you can "fix" this issue in the report writer and not modify the data at the query level. I also think the replace() command used in the report writer would likely perform the best. However, the above query can be exported, so it really depends on the final goal here.
So lots of easy ways to do this.

Split a String in Microsoft Access SQL for use with a command parameter

I am using Microsoft Access 2000, and need to pass in a parameter that is a comma-delimited string. The comma-delimited string is for an IN clause of the where statement. An example of this would be:
SELECT * FROM Table1 WHERE Field1 IN (#MyValues)
where #MyValues might be something like 1,2,3
However, when I pass in 1,2,3 the Access parameter doesn't seem to accept the input. Is there a good split string function in Access SQL that will solve this issue? Or is there another way of tackling this problem?
For reference on what I am doing, I am trying to use parameterized SQL in .NET to get a result set.
EDIT:
Below is an example of some simplified .NET code that would call this query:
OleDbCommand cmd = new OleDbCommand("SELECT * FROM Table1 WHERE Field1 IN (#MyValues)");
cmd.Parameters.Add("#MyValues","1,2,3");
What about this:
SELECT * FROM Table1 WHERE #MyValues Like "%" & Field1 "%"
This should check to see if the value in the field is included as a substring of your #MyValues parameter. Now, this could be problematic if any of the individual values in #MyValues are substrings of each other:
SELECT * FROM Table1 WHERE "2, 5, 10" Like "%" & Field1 "%"
In that case, "1" in Field1 would match, but it shouldn't. So, it might be that you'd need to format the numbers or delimit them some other way, such as:
SELECT * FROM Table1 WHERE " 2 5 10 " Like "% " & Field1 " %"
Or, alternatively:
SELECT * FROM Table1 WHERE ", 2, 5, 10," Like "%, " & Field1 ",%"
I'm not sure how this would perform, but it at least would allow parameterization.
At first, your question looked a little familiar. Then it started looking REALLY familiar. Then I realized I had the same question not long ago. My solution was to toss the parameters into this function:
Public Function IsIn( _
ByVal value As Variant, _
ParamArray theset() As Variant) _
As Boolean
Dim i As Long
For i = LBound(theset) To UBound(theset)
If value = theset(i) Then
IsIn = True
Exit Function
End If
Next
End Function
In your sample SQL code, you could do something like:
SELECT * FROM Table1 WHERE IsIn(Field1,array(1,2,3))=true;
(Like you, I also think that a procedure like this one should have been built into Access. Perhaps it is in 2007 or 2010.)
Edit
See Is there a NotIn("A","B") function in VBA?
Can you put them in another table and do a join?
If you don't want to create another table, that's ok. What does your ADO code and query syntax look like?
From your edited code above, I don't think you need to use the cmd object's parameters collection. Just modify your sql to embed your parameter values:
OleDbCommand cmd = new OleDbCommand("SELECT * FROM Table1 WHERE Field1 IN (1,2,3)");
You would use the .parameters collection if you had a parametrized query in the mdb, which you don't. Your sql is in source code.