SQL JOIN error in vb.net - sql

I have this sql string:
Dim sqlQuery As String = "SELECT TOP 1 ID, FName, FoodGroup, Calories, Protein, Carbohydrates, Fat, category.ID" &
" FROM food where Protein<='" & txtProt.Text.ToString() & "' and FoodGroup = 4 " & "and category.ID = 1 " & "JOIN foodCategory ON food.ID = foodCategory.Food_ID" & "JOIN category ON foodCategory.Category_ID = category.ID " & "ORDER BY NEWID() "
What i want to do is this: I want to type the value "FName" from table "food" to an textBox where the "ID" field of table "category" is 1.
I have 3 tables. The first is table food, the second one is table category and the third one is foodCategory.
The table foodCategory has the ID's from the first 2 tables to a one-to-many relationship.
I get the following error : Incorrect syntax near JOIN.
What do i do wrong?

your query is incorrect, the JOINs have to be set within the FROM clause, not in the WHERE clause.

Try the following query
dim sqlQuery As String
sqlQuery = "SELECT TOP 1 ID, FName, FoodGroup, Calories, Protein, " & _
"Carbohydrates, Fat, category.ID " &_
"FROM food JOIN foodCategory ON " & _
"food.ID = foodCategory.Food_ID JOIN category ON " & _
"foodCategory.Category_ID = category.ID " & _
"where Protein<='" & txtProt.Text.ToString() & "' and " & _
"FoodGroup = 4 and category.ID = 1 " & _
"ORDER BY NEWID() "
Furthermore you should have look at Parameter as your code is very vulnerable to SQL injection!

It's probably your concatenation:
... foodCategory.Food_ID" & "JOIN category ...
would evaluate to
foodCategory.Food_IDJOIN category

Your JOIN must be before the WHERE clause:
" FROM food" & " JOIN foodCategory ON food.ID = foodCategory.Food_ID" & "JOIN category ON foodCategory.Category_ID = category.ID " & " WHERE Protein<='" & txtProt.Text.ToString() & "' and FoodGroup = 4 " & "and category.ID = 1 " & " ORDER BY NEWID() ";

Related

MS Access SQL - Problem with subquery and function in ORDER BY clause

The senario is that some people apply for some positions.
So there are tApplicant, tPosition and a join table tPreferences for a many-to-many relationship between them.
I need to build a SQL expression where these should happen:
get some fields from a join of tApplicant and tPosition into a new table.
create a new field called AM which should be either 1 or 0.
1 = If tApplicant.applicationID is found in a third not relevant table called tInfo.
0 = If tApplicant.applicationID is not found there.
ORDER BY AM.
It is executed in VBA. This is what I 've got so far:
sSQL = "SELECT tApplicant.applicationID, tApplicant.name, tApplicant.ID, tPreferences.fld3, " & _
"NZ((SELECT 1 FROM tInfo WHERE tInfo.applicationID = tApplicant.applicationID), 0) AS AM " _
"INTO " & sTable & " FROM tPreferences INNER JOIN tApplicant " & _
"ON tPreferences.IDapplic = tApplicant.applicationID " & _
"WHERE tPreferences.IDposit = " & rsRos!ID & ";"
CurrentDB.Execute sSQL, dbFailOnError
It seems like step 3 cannot be done.
Adding ORDER BY AM, throws Run-time error '3061'. Too few parameters. Expected 1..
While adding ORDER BY NZ((SELECT 1 FROM tInfo WHERE tInfo.applicationID = tApplicant.applicationID), 0), throws Run-Time Error 3075: Syntax Error in Query Expression 'NZ((SELECT 1 FROM tAMEA WHERE tAMEA.aitisiID = tAiton.aitisiID), 0'..
If omitted, everything works fine but there's no ORDER BY.
How can I achieve this?
PS: If values 1 and 0 for AM make things complicated, and some other values instead could be easier to get with the query, it will be OK, I will deal with this in the rest of the code.
Nz is an application-level function (technically, a method of the Access.Application object exposed as a function. It is unavailable for use in DAO.
CurrentDb.Execute is using DAO.
There are two rewrite possibilities:
Rewrite to avoid Nz:
IIF((SELECT 1 FROM tInfo WHERE tInfo.applicationID = tApplicant.applicationID) IS NOT NULL, 1, 0)
Or my preferred rewrite:
ORDER BY EXISTS(SELECT 1 FROM tInfo WHERE tInfo.applicationID = tApplicant.applicationID) DESC
Rewrite to DoCmd.RunSQL which does allow these functions (and suppress warnings as desired:
DoCmd.RunSQL sSQL
First, Access might think that the subquery may return more than one record, thus Top 1 should be used.
Next, it makes no sense to order the records to be inserted, as records per definition carries no order unless you specify this in the target table or the query where that table is used as source.
Also, even if you insisted to sort the insert, Access can't do this, as it doesn't know the output for AM.
Thus, this will run:
sSQL = "SELECT tApplicant.applicationID, tApplicant.name, tApplicant.ID, tPreferences.fld3, " & _
"NZ((SELECT Top 1 1 FROM tInfo WHERE tInfo.applicationID = tApplicant.applicationID), 0) AS AM " _
"INTO " & sTable & " FROM tPreferences INNER JOIN tApplicant " & _
"ON tPreferences.IDapplic = tApplicant.applicationID " & _
"WHERE tPreferences.IDposit = " & rsRos!ID & ";"
CurrentDB.Execute sSQL, dbFailOnError
That said, Erik's suggestion to replace Nz with Exists is preferable as this will result in "clean SQL" which always will run faster:
sSQL = "SELECT tApplicant.applicationID, tApplicant.name, tApplicant.ID, tPreferences.fld3, " & _
"EXISTS (SELECT Top 1 1 FROM tInfo WHERE tInfo.applicationID = tApplicant.applicationID) AS AM " _
"INTO " & sTable & " FROM tPreferences INNER JOIN tApplicant " & _
"ON tPreferences.IDapplic = tApplicant.applicationID " & _
"WHERE tPreferences.IDposit = " & rsRos!ID & ";"
CurrentDB.Execute sSQL, dbFailOnError
Neither will this be sortable on AM. Also, it will in Access SQL return -1 and 0 for AM. To obtain 1, apply ABS:
sSQL = "SELECT tApplicant.applicationID, tApplicant.name, tApplicant.ID, tPreferences.fld3, " & _
"ABS(EXISTS (SELECT Top 1 1 FROM tInfo WHERE tInfo.applicationID = tApplicant.applicationID)) AS AM " _
"INTO " & sTable & " FROM tPreferences INNER JOIN tApplicant " & _
"ON tPreferences.IDapplic = tApplicant.applicationID " & _
"WHERE tPreferences.IDposit = " & rsRos!ID & ";"
CurrentDB.Execute sSQL, dbFailOnError
#ErikA and #Gustav 's answers pointed me to the right direction. Thank you both for your time.
The problem in this case was that I tried to use a subquery in the ORDER BY clause. Which I found out now that is not allowed. eg. see here
More over, I found this question, which makes mine a possible duplicate. Here it is suggested to wrap the query.
So I firstly SELECT the data in no order with the subquery and then, INSERT INTO the new table using ORDER BY with the new column of the subquery.
So I'm posting what finally worked for me.
sSQL = "SELECT * INTO " & sTable & " FROM (" & _
"SELECT tApplicant.applicationID, tApplicant.name, tApplicant.ID, tProtimisi.fld3, " & _
"NZ((SELECT 1 FROM tInfo WHERE tInfo.applicationID = tApplicant.applicationID), 0) AS AM " & _
"FROM tPreferences INNER JOIN tApplicant " & _
"ON tPreferences.IDapplic = tApplicant.applicationID " & _
"WHERE tPreferences.IDposit = " & rsRos!ID & ") " & _
"ORDER BY AM DESC;"
CurrentDb.Execute sSQL, dbFailOnError

Simplify return data from join SQL

I am just curious, how do I concat join table so the result doesn't return many rows?
What I want is the firstname d return only one row like 001;004;005;003;007 in column interest, so in my grid doesn't display many rows.
Here's my code
.CommandText = String.Format("select aa.code, aa.firstname, cc.interest as interest from db.name aa ") _
'& ("left join db.interest cc on cc.lead = aa.code ") _
'& ("where convert(date,time) between '" & date1& "' and '" & date2& "' order by aa.code ")
I am asking here because I don't know the keyword that relates to this
You need to add GROUP BY Steatment to your query:
.CommandText = String.Format("select aa.code, aa.firstname,COUNT(aa.firstname) as 'FnameCount', cc.interest as interest from db.name aa ") _
'& ("left join db.interest cc on cc.lead = aa.code ") _
'& ("where convert(date,time) between '" & date1& "' and '" & date2& "' GROUP BY aa.code, aa.firstname, cc.interest order by aa.code ")

How to get last 5 games of a team out of my access database

Hi all below you see a screenshot of my database:
But now I want to be able to make a table that calculates every players last 5 games. As I'm totaly new to access db I really have no clue how to do this.
Can you guys help me a hand with this one?
When I use the 2nd snippet in the answer below I get these:
Below are SQL routes according to your data. To use in MS Access simply create a new query under Create Tab on Ribbon and place the below SQL in the SQL view of a new created query. You may need to adjust query according to your actual table names and/or fields.
SAME GAMES FOR ALL PLAYERS
Assuming every player shares the same last five games, you could run an aggregate query across all players, using a subquery in INNER JOIN clause to calculate last five game dates. Do note: subquery, LastFiveDates can be saved as its own query and used directly in INNER JOIN.
SELECT [LookUp to Players],
Sum(GamesWon) As SumOfGamesWon, Sum(GamesLost) As SumOfGamesLost,
Sum(OwnOdds) As SumOfOwnOdds, Sum(OppOdds) As SumOfOppOdds,
Sum(GamesPlayed) As SumOfGamesPlayed
FROM GamesTable
INNER JOIN
(
SELECT DISTINCT TOP 5 [Date]
FROM GamesTable
ORDER BY [Date] DESC
) As LastFiveDates
ON GamesTable.[Date] = LastFiveDates.[Date]
GROUP BY [LookUp to Players];
DIFFERING GAMES FOR EACH PLAYER
SIMPLE SELECT APPROACH
Now, if players differ in their last five games, you have to join on different queries or union queries. Again, the below uses a subquery in an inner join but you can save that LastFiveGames as its own stored query and join in INNER JOIN line.
SELECT GamesTable.[LookUp to Players],
Sum(GamesWon) As SumOfGamesWon, Sum(GamesLost) As SumOfGamesLost,
Sum(OwnOdds) As SumOfOwnOdds, Sum(OppOdds) As SumOfOppOdds,
Sum(GamesPlayed) As SumOfGamesPlayed
FROM GamesTable
INNER JOIN
(
SELECT [Lookup to Players], [Date],
(SELECT Count(*)
FROM GamesTable t2
WHERE GamesTable.[Date] <= t2.[Date]
AND GamesTable.[Lookup to Players] = t2.[Lookup to Players]) AS GameOrder
FROM GamesTable
) As LastFiveDates
ON GamesTable.[Date] = LastFiveDates.[Date]
AND GamesTable.[Lookup to Players] = LastFiveDates.[Lookup to Players]
WHERE LastFiveDates.GameOrder <= 5
GROUP BY GamesTable.[LookUp to Players];
DIFFERING GAMES FOR EACH PLAYER
VBA CREATE TABLE APPROACH
Due to performance issues of Access running the query as a stored query, VBA can re-create the GamesStats iteratively looping through all distinct players using the very first query condition for player.
Public Function GameTableStats()
Dim db As Database
Dim tbldef As TableDef, rst As Recordset
Dim strSQL As String, i As Integer
Set db = CurrentDb
Set rst = db.OpenRecordset("SELECT DISTINCT PlayerName FROM GamesTable", dbOpenDynaset)
For Each tbldef In db.TableDefs
If tbldef.Name = "GamesStats" Then
db.Execute "DROP TABLE [GamesStats]", dbFailOnError
End If
Next tbldef
rst.MoveLast
rst.MoveFirst
i = 1
Do While Not rst.EOF
If i = 1 Then
' FIRST PLAYER (MAKE-TABLE QUERY) '
strSQL = "SELECT GamesTable.[PlayerName]," _
& " Sum(GamesWon) As SumOfGamesWon, Sum(GamesLost) As SumOfGamesLost," _
& " Sum(OwnOdds) As SumOfOwnOdds, Sum(OppOdds) As SumOfOppOdds," _
& " Sum(GamePlayed) As SumOfGamePlayed" _
& " INTO GamesStats" _
& " FROM GamesTable" _
& " INNER JOIN" _
& " (" _
& " SELECT DISTINCT TOP 5 [Date], [PlayerName]" _
& " FROM GamesTable" _
& " WHERE [PlayerName]=""" & rst!PlayerName & """" _
& " ORDER BY [Date] DESC" _
& " ) As LastFiveDates" _
& " ON GamesTable.[Date] = LastFiveDates.[Date]" _
& " WHERE GamesTable.[PlayerName]= """ & rst!PlayerName & """" _
& " GROUP BY GamesTable.[PlayerName];"
Else
' ALL OTHER PLAYERS (INSERT APPEND QUERIES) '
strSQL = "INSERT INTO GamesStats ([PlayerName], [SumOfGamesWon], [SumOfGamesLost]," _
& " [SumOfOwnOdds], [SumOfOppOdds], [SumOfGamePlayed])" _
& " SELECT GamesTable.[PlayerName], " _
& " Sum(GamesWon) As SumOfGamesWon, Sum(GamesLost) As SumOfGamesLost, " _
& " Sum(OwnOdds) As SumOfOwnOdds, Sum(OppOdds) As SumOfOppOdds, " _
& " Sum(GamePlayed) As SumOfGamePlayed " _
& " FROM GamesTable " _
& " INNER JOIN " _
& " ( " _
& " SELECT DISTINCT TOP 5 [Date], [PlayerName] " _
& " FROM GamesTable " _
& " WHERE [PlayerName]=""" & rst!PlayerName & """" _
& " ORDER BY [Date] DESC" _
& " ) As LastFiveDates " _
& " ON GamesTable.[Date] = LastFiveDates.[Date]" _
& " WHERE GamesTable.[PlayerName]= """ & rst!PlayerName & """" _
& " GROUP BY GamesTable.[PlayerName];"
End If
db.Execute strSQL, dbFailOnError
i = i + 1
rst.MoveNext
Loop
rst.Close
Set rst = Nothing
Set db = Nothing
MsgBox "Successfully created GamesStats table!", vbInformation
End Function

Using insert into where not exists in VBA

I have a lovely form and a lovely table in MS access (I promise). I would like to insert into this table at the press of a button using where not exists but I am getting a not-so-friendly run-time error 3067: "Query input must contain at least one table or query."
My query already does...
strSQL = "insert into tbl_MAP_systemTask (TaskID, SystemID) " & _
" Values (" & taskID & ", " & sysID & _
") where not exists " & _
" (select M.TaskID, M.SystemID from tbl_MAP_systemTask as M where M.TaskID = " & taskID & _
" and M.SystemID = " & sysID & ");"
Debug.Print strSQL
DoCmd.RunSQL (strSQL)
strSQL is now
insert into tbl_MAP_systemTask (TaskID, SystemID)
Values (1, 1)
where not exists
(select M.TaskID, M.SystemID
from tbl_MAP_systemTask as M where M.TaskID = 1 and M.SystemID = 1);
Can anyone shed any light on
a) what I broke?
b) how to fix it?
Well instead of using a SubQuery, you could use a Domain function to get this going,
If Dcount("*", "tbl_MAP_systemTask", "TaskID = " & taskID & " AND SystemID = " &sysID) = 0 Then
strSQL = "INSERT INTO tbl_MAP_systemTask (TaskID, SystemID) " & _
" VALUES (" & taskID & ", " & sysID & ")
CurrentDb.Execute strSQL
Else
MsgBox "The Data already exists in the table, so nothing was added."
End If
Try this:
strSQL = "insert tbl_MAP_systemTask (TaskID, SystemID) " & _
" select " & taskID & ", " & sysID & _
" where not exists " & _
" (select M.TaskID, M.SystemID from tbl_MAP_systemTask as M where M.TaskID = " & taskID & _
" and M.SystemID = " & sysID & ");"
=>
insert tbl_MAP_systemTask (TaskID, SystemID)
select 1, 1
where not exists
(select M.TaskID, M.SystemID
from tbl_MAP_systemTask as M where M.TaskID = 1 and M.SystemID = 1);
and seems to work in my case. Seems like the where not exists needs a select statement, so you have to model your insert like this.
Maybe you can use a recordset to insert these values.
Dim rs as Recordset
Set rs = Currentdb.openRecordset("SELECT * FROM tbl_MAP_systemTask WHERE TaskID=" & Me.TaskID & " AND SystemID=" & Me.SystemID)
if not (rs.eof or rs.bof) then
rs.addnew
rs.TaskID = Me.TaskID
rs.SystemID = Me.SystemID
rs.update
end if
rs.close
set rs = nothing
TOP 1 clause is must in the main query.
INSERT INTO tbl_MAP_systemTask (TaskID, SystemID)
SELECT TOP 1 1 AS TaskID 1 AS SystemID
FROM tbl_MAP_systemTask
WHERE NOT EXISTS (SELECT TOP 1 TaskID,SystemID FROM
tbl_MAP_systemTask WHERE TaskID = 1 and SystemID=1);
If tbl_MAP_systemTask table is empty or if there is only one record in the table then TOP 1 clause must be omitted in sub-query.
I have included Top 1 clause is sub-query for performance purpose.

Displaying "Similar" or "Related" Vehicles

I have a vehicle database and would like to show "related" vehicles when a user clicks to view a vehicle. For instance, the user views a '2013 Chevy Tahoe' that is listed by dealership 'ABC Dealers'.
I need to create a SQL statement to grab 4 vehicles that are similar to the vehicle they are viewing. Here is the order of importance for now:
1) Dealer Listings (d_id)(Show vehicles also listed by that dealer)
2) Vehicle Category (vc_id)(Vehicle category such as Car, Truck, SUV, etc.)
3) Vehicle Make (vm_id)(Vehicle make such as Ford, Chevy, Lexus, etc.)
I have created a SQL statement, but it does not seem to do what I am looking for it to do. Can anyone offer any suggestions on how to properly build a SQL statement to grab the most relevant records in the order defined above?
strSQL = "SELECT TOP 4 v.v_id, vm.vm_name, v.v_year, v.v_model, v.v_search_price, d.d_name, u.u_name " & _
"FROM tbl_Vehicles v " & _
"LEFT JOIN tbl_VehicleMake vm ON vm.vm_id = v.vm_id " & _
"LEFT JOIN tbl_Dealers d ON d.d_id = v.d_id " & _
"LEFT JOIN tbl_Users u ON u.u_id = v.u_id " & _
"WHERE v.v_processed = 1 AND v.v_active = 1 AND v.v_id <> " & v_id
If Not CheckBlank(d_id) Then
strSQL = strSQL & " OR v.d_id = " & d_id
End If
If Not CheckBlank(vm_id) Then
strSQL = strSQL & " OR v.vm_id = " & vm_id
End If
If Not CheckBlank(vc_id) Then
strSQL = strSQL & " OR v.vc_id = " & vc_id
End If
strSQL = strSQL & " ORDER BY v.d_id, v.vc_id, v.vm_id"
I have a couple of thoughts for you.
Your current query has some ANDs and some ORs. You may need brackets to indicate your preferred order of operations, for example:
strSQL = "SELECT TOP 4 v.v_id, vm.vm_name, v.v_year, v.v_model, v.v_search_price, d.d_name, u.u_name " & _
"FROM tbl_Vehicles v " & _
"LEFT JOIN tbl_VehicleMake vm ON vm.vm_id = v.vm_id " & _
"LEFT JOIN tbl_Dealers d ON d.d_id = v.d_id " & _
"LEFT JOIN tbl_Users u ON u.u_id = v.u_id " & _
"WHERE v.v_processed = 1 AND v.v_active = 1 AND v.v_id <> " & v_id
If Not CheckBlank(d_id) Or Not CheckBlank(vm_id) Or Not CheckBlank(vc_id) Then
strSQL = strSQL & "("
End If
If Not CheckBlank(d_id) Then
strSQL = strSQL & " OR v.d_id = " & d_id
End If
If Not CheckBlank(vm_id) Then
strSQL = strSQL & " OR v.vm_id = " & vm_id
End If
If Not CheckBlank(vc_id) Then
strSQL = strSQL & " OR v.vc_id = " & vc_id
End If
If Not CheckBlank(d_id) Or Not CheckBlank(vm_id) Or Not CheckBlank(vc_id) Then
strSQL = strSQL & ")"
End If
strSQL = strSQL & " ORDER BY v.d_id, v.vc_id, v.vm_id"
But based on what you wrote in your question, you may be better with a query that uses the ORDER BY clause to get the most appropriate records based on the criteria you specified.
strSQL = "SELECT TOP 4 v.v_id, vm.vm_name, v.v_year, v.v_model, v.v_search_price, d.d_name, u.u_name " & _
"FROM tbl_Vehicles v " & _
"LEFT JOIN tbl_VehicleMake vm ON vm.vm_id = v.vm_id " & _
"LEFT JOIN tbl_Dealers d ON d.d_id = v.d_id " & _
"LEFT JOIN tbl_Users u ON u.u_id = v.u_id " & _
"WHERE v.v_processed = 1 AND v.v_active = 1 AND v.v_id <> " & v_id & " ORDER BY"
If Not CheckBlank(d_id) Or Not CheckBlank(vm_id) Or Not CheckBlank(vc_id) Then
If Not CheckBlank(d_id) Then
strSQL = strSQL & " CASE WHEN v.d_id = " & d_id & " THEN 0 ELSE 1 END,"
End If
If Not CheckBlank(vm_id) Then
strSQL = strSQL & " CASE WHEN v.vm_id = " & vm_id & " THEN 0 ELSE 1 END,"
End If
If Not CheckBlank(vc_id) Then
strSQL = strSQL & " CASE WHEN v.vc_id = " & vc_id & " THEN 0 ELSE 1 END,"
End If
strSQL = Left(strSQL, Len(strSQL) - 1)
Else
strSQL = strSQL & "v.d_id, v.vc_id, v.vm_id"
End If
This query will still give you results even if there are no vehicles for that dealer, make or category, so you will always have related vehicles (assuming you have at least 5 records).
It looks like the OR clauses you're using are not going to bring you you want. Assuming I'm understanding the snippet and the unseen db correctly, you need to create a subclause of the OR statements that is "ANDED" in. Try the following, after the initial strSQL assignment:
...
dim strSubClause
strSubClause = ""
If Not CheckBlank(d_id)) Then
strSubClause = "v.d_id = " & d_id
End If
If Not CheckBlank(vm_id) Then
If len(strSubClause) > 0 then
strSubClause = strSubClause & " OR v.vm_id = " & vm_id
Else
strSubClause = "v.vm_id = " & vm_id
End If
End If
If Not CheckBlank(vc_id) Then
If len(strSubClause) > 0 then
strSubClause = strSubClause & " OR v.vc_id = " & vc_id
Else
strSubClause = "v.vc_id = " & vc_id
End if
End If
If len(strSubClause) > 0 then
strSQL = " AND (" & strSubClause & ")"
End If
strSQL = strSQL & " ORDER BY v.d_id, v.vc_id, v.vm_id"
So, assuming all of your checks came back with values, you'd have a where clause that looks like:
...WHERE v.v_processed = 1 AND v.v_active = 1 AND v.v_id <> NNN AND (v.d_id = XXX OR v.vm_id = YYY OR v.vc_id = ZZZ) ORDER BY v.d_id, v.vc_id, v.vm_id
Does that make sense and/or get you closer or all the way to where you're wanting to go?