SQL Table Joins - What am I doing wrong? - sql

I'm in a intro to database class, and one of my queries is seriously giving me trouble.
The assignment says to: Write a query to display the Passenger name, Seat No and Destination. Display this in one column title Travellers_info. This column should display data in the following format “ Mary Ann Jenkins is assigned to Seat 15 on the way to Bellmead”
This is the relationship view: http://prntscr.com/1jsoay
Can somebody please help me out, I'm not sure where I've gone wrong.
SELECT passenger.name + 'is assigned to Seat'
+ seat_info.seat_no + 'on the way to'
+ departure_info.destination AS Travellers_info
FROM passenger, seat_info, departure_info, seat_passenger, manages
WHERE passenger.Pass_id=seat_passenger.pass_id
AND seat_passenger.Seat_id=seat_info.Seat_id
AND seat_info.seat_id=manages.Seat_id
AND manages.Dept_id=departure_info.dept_id

You cant "add" text values using the "+" operator.
Without knowing which database you are using, the solution is probably either using CONCAT():
SELECT concat(passenger.name, 'is assigned to Seat', seat_info.seat_no,
'on the way to', departure_info.destination) AS Travellers_info
FROM passenger, seat_info, departure_info, seat_passenger, manages
WHERE passenger.Pass_id=seat_passenger.pass_id
AND seat_passenger.Seat_id=seat_info.Seat_id
AND seat_info.seat_id=manages.Seat_id
AND manages.Dept_id=departure_info.dept_id
or using the || operator:
SELECT passenger.name || 'is assigned to Seat'
|| seat_info.seat_no || 'on the way to'
|| departure_info.destination AS Travellers_info
FROM passenger, seat_info, departure_info, seat_passenger, manages
WHERE passenger.Pass_id=seat_passenger.pass_id
AND seat_passenger.Seat_id=seat_info.Seat_id
AND seat_info.seat_id=manages.Seat_id
AND manages.Dept_id=departure_info.dept_id

Have you tried double-checking all your tables (especially the joining tables like "manages" and "seat_passenger") to make sure you have valid data in them that would appropriately join up?
Also, make sure you have spaces in your text.
e.g.: 'is assigned to Seat' should be ' is assigned to Seat '

If you are getting no data it must be in your join criteria. Reduce your select to just a column from your first table and then join each table one at a time and see when it is that you stop getting data back

First off, you're going to want to put a space before is so that it won't look mushed together.
passenger.name + ' is assigned to seat'
Typically, you use subqueries and left outer joins for something of this sort. You do not just want to pull out all the data at once from all those tables. Let me see if I can explain this with some SQL. If you don't understand my example, go here: http://thenewboston.org/watch.php?cat=49&number=20 and watch 20-23 and you'll for sure understand it.
SELECT c.name + ' is assigned to Seat ' + c.seat_no + ' on the way to ' + departure_info.destination as Travellers_info
FROM departure_info
LEFT OUTER JOIN (SELECT b.Pass_id, b.name, b.seat_id, b.seat_no
FROM seat_no
LEFT OUTER JOIN (SELECT a.Pass_id, a.name, seat_passenger.seat_id
FROM seat_passenger
LEFT OUTER JOIN (SELECT passenger.name, passenger.Pass_id
from passenger
LEFT OUTER JOIN
ON passenger.Pass_id = seat_passenger.Pass_id) a seat_info
ON a.seat_id = seat_info.seat_id) b manages
ON b.seat_id = manages.seat_id) c departure_info
ON c.Dept_id = departure_info.Dept_id
I do not believe this will yield you the correct answer. But, it will get you working towards the right answer. I think I made a mistake after the third subquery. Remember that SQL evaluates things from the inside, then goes out. Just keep that in mind. Hope this helps.

try this in MSSQL or MSAccess.
for query optimization use ON (Join)
SELECT passenger.name + 'is assigned to Seat '
+ ltrim(rtrim(convert(char,seat_info.seat_no))) + ' on the way to'
+ departure_info.destination AS Travellers_info
FROM passenger p
join seat_passenger sp on sp.pass_id = p.Pass_id
join seat_info s on s.Seat_id = sp.Seat_id
join manages m on m.Seat_id = s.Seat_id
join departure_info d on d.dept_id = m.dept_id
concat in 2008R2 is not a valid function so you need to convert a number data to character.
while in 2012 it is available.

Related

how to select a row if multiple values are in a related table

I am trying to make a filter to find all the stuffs made of various substances.
In the database, there is:
a stuffs table
a substances table
a stuffs_substances join table.
Now, I want to find only all the stuffs that are made of gold AND silver (not all the stuffs that contain gold and all stuffs that contain silver).
One last thing: the end user can type only a part of the substance name in the filter form field. For example he will type silv and it will show up all the stuffs made of silver.
So I made this query (not working):
select "stuffs".*
from "stuffs"
inner join "stuffs_substances" as "substances_join"
on "substances_join"."stuff_id" = "stuffs"."id"
inner join "substances"
on "substances_join"."substance_id" = "substances"."id"
where ("substances"."name" like '%silv%')
and ("substances"."name" like '%gold%')
It returns an empty array. What am I doing wrong here?
Basically, you just want aggregation:
select st.*
from "stuffs" st join
"stuffs_substances" ss join
on ss."stuff_id" = st."id" join
"substances" s
on ss."substance_id" = s."id"
where s."name" like '%silv%' or
s."name" like '%gold%'
group by st.id
having count(*) filter (where s."name" like '%silv%') > 0 and
count(*) filter (where s."name" like '%gold%') > 0;
Note that this works, assuming that stuff.id is the primary key in stuffs.
I don't understand your fascination with double quotes and long table aliases. To me, those things just make the query harder to write and to read.
if you want to do search by part of word then do action to re-run query each time user write a letter of word , and the filter part in query in case of oracle sql way
in case to search with start part only
where name like :what_user_write || '%'
or in case any part of word
where name like '%' || :what_user_write || '%'
you can also use CAB, to be sure user can search by capital or small whatever
ok, you ask about join, I test this in mysql , it work find to get stuff made from gold and silver or silver and so on, hope this help
select sf.id, ss.code, sf.stuff_name from stuffs sf, stuffs_substances ss , substances s
where sf.id = ss.id
and s.code = ss.code
and s.sub_name like 'gol%'

Syntax error. in query (MS Access sql)

I have a MS access query which I am running in my c sharp application, I am able to run the query fine using SSMS (I know this isn't an access sql but its all I can use) and when I import it into my c sharp application I get an incorrect syntax error. (My c sharp application reads from access dbf files) Here is the full sql below:
SELECT ([T2_BRA].[REF] + [F7]) AS NewStyle,
Sum(T2_BRA.Q11) AS QTY1, Sum(T2_BRA.Q12) AS QTY2,
Sum(T2_BRA.Q13) AS QTY3, Sum(T2_BRA.Q14) AS QTY4, Sum(T2_BRA.Q15) AS QTY5, Sum(T2_BRA.Q16) AS QTY6, Sum(T2_BRA.Q17) AS QTY7, Sum(T2_BRA.Q18) AS QTY8,
Sum(T2_BRA.Q19) AS QTY9, Sum(T2_BRA.Q20) AS QTY10, Sum(T2_BRA.Q21) AS QTY11, Sum(T2_BRA.Q22) AS QTY12, Sum(T2_BRA.Q23) AS QTY13, T2_HEAD.REF,
Sum(T2_BRA.LY11) AS LY1, Sum(T2_BRA.LY12) AS LY2, Sum(T2_BRA.LY13) AS LY3, Sum(T2_BRA.LY14) AS LY4, Sum(T2_BRA.LY15) AS LY5,
Sum(T2_BRA.LY16) AS LY6, Sum(T2_BRA.LY17) AS LY7, Sum(T2_BRA.LY18) AS LY8, Sum(T2_BRA.LY19) AS LY9, Sum(T2_BRA.LY20) AS LY10,
Sum(T2_BRA.LY21) AS LY11, Sum(T2_BRA.LY22) AS LY12, Sum(T2_BRA.LY23) AS LY13, T2_BRA.BRANCH, T2_HEAD.LASTDELV, T2_EAN.EAN_CODE, T2_SIZES.S01 AS S1,
T2_SIZES.S02 AS S2,
T2_SIZES.S03 AS S3,
T2_SIZES.S04 AS S4,
T2_SIZES.S05 AS S5,
T2_SIZES.S06 AS S6,
T2_SIZES.S07 AS S7,
T2_SIZES.S08 AS S8,
T2_SIZES.S09 AS S9,
T2_SIZES.S10 AS S10,
T2_SIZES.S11 AS S11,
T2_SIZES.S12 AS S12,
T2_SIZES.S13 AS S13
FROM ((((((T2_BRA INNER JOIN T2_HEAD ON T2_BRA.REF = T2_HEAD.REF)) INNER JOIN T2_SIZES ON T2_HEAD.SIZERANGE = T2_SIZES.SIZERANGE) INNER JOIN
(SELECT Right(T2_LOOK.[KEY],3) AS NewCol, T2_LOOK.F1 AS MasterColour, Left(T2_LOOK.[KEY],3) AS Col, T2_LOOK.F7
FROM T2_LOOK
WHERE (Left(T2_LOOK.[KEY],3))='COL') as Colour ON T2_BRA.COLOUR = Colour.NewCol) LEFT JOIN T2_EAN ON T2_EAN.T2T_CODE LIKE (SELECT ('#' + ([T2_BRA].[REF] + [F7]) + '#'))))
WHERE [T2_BRA].[REF] = '010403' AND T2_BRA.BRANCH in ('A','G')
GROUP BY ([T2_BRA].[REF] + [F7]),T2_HEAD.REF, T2_BRA.BRANCH, T2_HEAD.LASTDELV, T2_EAN.EAN_CODE, T2_SIZES.S01,
T2_SIZES.S02, T2_SIZES.S03, T2_SIZES.S04, T2_SIZES.S05, T2_SIZES.S06, T2_SIZES.S07, T2_SIZES.S08, T2_SIZES.S09, T2_SIZES.S10, T2_SIZES.S11, T2_SIZES.S12, T2_SIZES.S13
The line I am getting the syntax error is:
LEFT JOIN T2_EAN ON T2_EAN.T2T_CODE LIKE (SELECT ('#' + ([T2_BRA].[REF] + [F7]) + '#')
Any help would be great! :)
Your problem JOIN clause has some issues for the MS Access dialect:
SELECT that uses a column and table reference must have FROM source;
String concatenation does not use + but & operator;
LIKE expressions can be used in ON clauses but the comparison will be row by row (not searching values across all rows of joining table as possibly intended).
Correcting above still imposes a challenge since you are attempting to join a table by the LIKE expression in a LEFT JOIN relationship.
Consider first comma-separating your table, T2_EAN, which equates to a cross join then add a WHERE clause running an EXISTS subquery. Doing so, WHERE becomes the implicit join and T2_EAN column will point to field in main query. Do be aware other tables in query must use INNER JOIN for this comma-separated table. And adjust parentheses with removal of LEFT JOIN.
FROM T2_EAN, (((((
...
WHERE [T2_BRA].[REF] = '010403' AND T2_BRA.BRANCH in ('A','G')
AND EXISTS
(SELECT 1 FROM [T2_BRA] t
WHERE T2_EAN.T2T_CODE LIKE ('%' & (t.[REF] & t.[F7]) & '%')
Now, the challenge here is the WHERE will correspond to an INNER JOIN and not LEFT JOIN. To overcome this, consider adding a UNION (not UNION ALL) query exactly the same as above but without the EXISTS subquery. This will then return records that did not meet LIKE criteria and UNION will leave out duplicates. See LEFT JOIN Equivalent here. Be sure to add a NULL to SELECT wherever T2_EAN column was referenced:
SELECT ... T2_HEAD.LASTDELV, T2_EAN.EAN_CODE, T2_SIZES.S01 AS S1 ...
UNION
SELECT ... T2_HEAD.LASTDELV, NULL AS EAN_CODE, T2_SIZES.S01 AS S1 ...
Do note: performance is not guaranteed with this adjustment. Further considerations include:
Once query compiles and runs, be sure to save this large query or view as a stored object in the MS Access database and not as a scripted C# string query. Even if you do not have MS Access GUI .exe, you can save queries via code using MS Access' querydefs object with VBA (i.e., Excel VBA) or COM-interface with C# or any other language that supports COM like open-source Python, PHP, R.
Then have C# app simply retrieve the view for its purposes: SELECT * FROM mySavedQuery. Stored queries tend to be more efficient especially for many joins and complex queries than coded queries since the Access engine saves best execution plan and caches stats.
Remove the need of LIKE by saving matching values without extraneous other characters so = can be used as I believe MS Access's LIKE will not use indexes in query plans.
Upsize your Access database to SQL Server for more sophisticated handling with the T-SQL dialect. SQL Server has easy facilities in SSMS to import Access .mdb/.accdb files.
You LEFT OUTER JOIN's ON clause makes no sense:
LEFT JOIN T2_EAN ON T2_EAN.T2T_CODE LIKE (SELECT ('#' + ([T2_BRA].[REF] + [F7]) + '#')
You need to join T2_EAN to your values in ALREADY PRESENT T2_BRA table in your FROM clause. By sticking T2_BRA into a subquery here you are bringing the table in twice, which is nonsense. It's also not allowed to use a subquery inside a LIKE condition.
If it were allowed and did make sense, you would end up with a cartesian product between all the intermediate result set from those inner joins and your left outer join'd table, which is almost definitely not what you are after.
Instead (probably something like):
LEFT JOIN T2_EAN ON T2_EAN.T2T_CODE LIKE '#' + [T2_BRA].[REF] + [F7] + '#'
This is now saying "Left outer join t2_ean to T2_Bra where the T2T_Code matches the concatenation of <any one digit> + T2_Bra.Ref + F7 + <any one digit>" Without knowing your data, I cant' vouch for that being the thing you want, but it feels like the closest interpretation when reverse engineering your incorrect query.
You mention in a comment "I have tried using all the wildcard symbols *, # and ?" Don't just try wildcard symbols hoping something will work. They each do something VERY different. Use the one that you need for you situation. Decent explanation of the three wildcards that work with the LIKE operator in access here. You may want to switch to the asterisk while debugging (since it's the most wide open of the wild cards) and then once you are getting reasonable results, use the much tighter # (match only one digit) operator.

Searching in SQL per POST-Variable in joined Table

I tried to solve this for some time and didn't come to a solution.
I read from a table filled with Mobile Devices and list them and give the user the possibilty to search the list per Movile Device Name and Username.
This is my Code:
SELECT
*
FROM
tbl_mobdev
LEFT JOIN
tbl_mobdev_type ON mobdev_type_id = mobdev_type
LEFT JOIN
tbl_marke ON marke_id = mobdev_type_marke
LEFT JOIN
tbl_user ON tbl_user.id = mobdev_user
WHERE
CONCAT(tbl_marke.marke_name,' ',tbl_mobdev_type.mobdev_type_bezeichnung) LIKE '%".$_POST['marke_name']."%'
AND
CONCAT(tbl_user.name,' ',tbl_user.vorname) LIKE '%".$_POST['user']."%'
AND
mobdev_aktiv = '1'
ORDER BY
".$_GET['sort']." ".$_GET['sort2']."
Everything works as intended as long as tbl_mobdev.mobdev_user contains an User-ID, while table-rows that doesn't contain an User-ID are left out.
Any Solutions for this?
Edit: The solution of putting the "filter" in the LEFT JOIN for tbl_user doesn't work. An SQL like the following results in every row will be shown.
If the LIKE contains something only the not matching results will not be joined, the row doesn't get filtered.
SELECT mobdev_id, mobdev_type_bezeichnung, marke_name, tbl_user.name AS user_name, tbl_user.vorname AS user_vorname
FROM tbl_mobdev
LEFT JOIN tbl_mobdev_type ON mobdev_type_id = mobdev_type
LEFT JOIN tbl_marke ON marke_id = mobdev_type_marke
LEFT JOIN tbl_user ON tbl_user.id = mobdev_user
AND CONCAT( tbl_user.name, ' ', tbl_user.vorname ) LIKE '%%'
WHERE CONCAT( tbl_marke.marke_name, ' ', tbl_mobdev_type.mobdev_type_bezeichnung ) LIKE '%%'
AND mobdev_aktiv = '1'
ORDER BY marke_name ASC
LIMIT 0 , 30
Edit2: Setting the SQL to the following didn't changed the behavior.
SELECT mobdev_id, mobdev_type_bezeichnung, marke_name, tbl_user.name AS user_name, tbl_user.vorname AS user_vorname
FROM tbl_mobdev
LEFT JOIN tbl_mobdev_type ON mobdev_type_id = mobdev_type
LEFT JOIN tbl_marke ON marke_id = mobdev_type_marke
LEFT JOIN tbl_user ON tbl_user.id = mobdev_user
AND CONCAT( tbl_user.name, ' ', tbl_user.vorname ) LIKE '%G%'
WHERE CONCAT( tbl_marke.marke_name, ' ', COALESCE( tbl_mobdev_type.mobdev_type_bezeichnung, '' ) ) LIKE '%%'
AND mobdev_aktiv = '1'
ORDER BY marke_name ASC
LIMIT 0 , 30
Rows without matching $_POST['user'] still aren't filtered out.
I uploaded an example picture of the behavior with blurred out names, the left picute is a Select without any filter, right pictura is a Select with an actual Username (Blurred out, but its the exact same name as in mobdev_id '3'.
http://fs5.directupload.net/images/160404/tmdbyzws.png
As you can see, the other five rows are still there, just without the joins. I want them to be gone completely, because they are not matching the filter.
Edit3: Well, i made it now...sadly in a pretty dirty way using PHP. I just leave the code here, if someone comes up with a better solution for this please let me know.
$query = "
SELECT
mobdev_id,
mobdev_type_bezeichnung,
marke_name,
tbl_user.name AS user_name,
tbl_user.vorname AS user_vorname
FROM
tbl_mobdev
LEFT JOIN
tbl_mobdev_type ON mobdev_type_id = mobdev_type
LEFT JOIN
tbl_marke ON marke_id = mobdev_type_marke
LEFT JOIN
tbl_user ON tbl_user.id = mobdev_user
WHERE
CONCAT(tbl_marke.marke_name,' ',tbl_mobdev_type.mobdev_type_bezeichnung) LIKE '%".$_POST['marke_name']."%'
";
if($_POST['user'])
{
$query .= "
AND
CONCAT(tbl_user.name,' ',tbl_user.vorname) LIKE '%".$_POST['user']."%'
";
}
$query .= "
AND
mobdev_aktiv = '1'
ORDER BY
".$_GET['sort']." ".$_GET['sort2']."
";
The problem is in the line
CONCAT(tbl_user.name,' ',tbl_user.vorname) LIKE '%".$_POST['user']."%'
Your LEFT JOIN on tbl_user will allow the main query to return independent of whether there's a value in that row. However, that particular WHERE clause line effectively overrides that; if tbl_user.name or tbl_user.vorname is null, the result will always be false.
If I need to do something like that, I'll often put the test into the ON clause of the JOIN statement. That way it filters the JOINed table where it exists, but doesn't cause problems where it doesn't.
Example query text that should ensure tbl_user gets filtered when required but not when nothing's specified -
SELECT
md.mobdev_id,
mdt.mobdev_type_bezeichnung,
m.marke_name,
u.name AS user_name,
u.vorname AS user_vorname
FROM
tbl_mobdev md
LEFT JOIN tbl_mobdev_type mdt
ON mdt.mobdev_type_id = md.mobdev_type
LEFT JOIN tbl_marke m
ON m.marke_id = mdt.mobdev_type_marke
LEFT JOIN tbl_user u
ON u.id = md.mobdev_user
AND CONCAT(u.name,' ',u.vorname) LIKE '%".$_POST['user']."%'
WHERE
CONCAT(m.marke_name,' ',COALESCE(mdt.mobdev_type_bezeichnung,''))
LIKE '%".$_POST['m.marke_name']."%'
AND md.mobdev_aktiv = '1'
ORDER BY
".$_GET['sort']." ".$_GET['sort2']."
Two asides -
As Rene M. says above, this code is an SQL Injection vulnerability. It might be safe due to its current application but I still wouldn't roll it out; the chances of someone taking this application or code fragment and later moving it online without doing a full audit is not insignificant, and you've then got a problem. Practice doing it right - don't leave SQL Injection vulnerabilities in code.
Please alias your table names! The query having every table name written out in full for each field reference makes it very bulky.

Slow SQL query when joining tables

This query is very very slow and i'm not sure where I'm going wrong to cause it to be so slow.
I'm guessing it's something to do with the flight_prices table
because if I remove that join it goes from 16 seconds to less than one.
SELECT * FROM OPENQUERY(mybook,
'SELECT wb.booking_ref
FROM web_bookings wb
LEFT JOIN prod_info pi ON wb.location = pi.location
LEFT JOIN flight_prices fp ON fp.dest_date = pi.dest_airport + '' '' + wb.sort_date
WHERE fp.dest_cheapest = ''Y''
AND wb.inc_flights = ''Y''
AND wb.customer = ''12345'' ')
Any ideas how I can speed up this join??
You're unlikely to get any indexing on flight_prices.dest_date to be used as you're not actually joining to another column which makes it hard for the optimiser.
If you can change the schema I'd make it so flight_prices.dest_date was split into two columns dest_airport and dest_Date as it appears to be currently a composite of airport and date. If you did that you could then join like this
fp.dest_date = wb.sort_date and fp.dest_airport = pi.dest_airport
Try EXPLAIN PLAN and see what your database comes back with.
If you see TABLE SCAN, you might need to add indexes.
That second JOIN looks rather odd to me. I'd wonder if that could be rewritten.
Your statement reformatted gives me this
SELECT wb.booking_ref
FROM web_bookings wb
LEFT JOIN prod_info pi ON wb.location = pi.location
LEFT JOIN flight_prices fp ON fp.dest_date = pi.dest_airport + ' ' + wb.sort_date
WHERE fp.dest_cheapest = 'Y'
AND wb.inc_flights = 'Y'
AND wb.customer = '12345'
I would make sure that following fields have indexes
dest_cheapest
dest_date
location
customer, inc_flights, booking_ref (covering index)

Help converting multi DB SQL Query to LINQ

I have the below SQL Query, which returns what I expect, and I would LIKE to accomplish the same thing in LINQ but so far my results have been less then spectacular. The major hurdle, as I see it, is that the data is coming from 3 separate DB's. I was able to accomplish this in LINQ but it is extremely slow, see here.
So, with out further ado, here it is, with the hardcoded Guid() being the only exception as that gets passed in:
SELECT en.ClientID, p.LastName, p.FirstName, NurseName = dm2.FirstName + ' ' + dm2.LastName, SocialWorkerName = dm.FirstName + ' ' + dm.LastName, en.EnrollmentDate, en.DisenrollmentDate, ESWorkerName = sw.FirstName + ' ' + sw.LastName, sw.Phone
FROM CMO.dbo.tblCMOEnrollment en
LEFT OUTER JOIN CMO.dbo.tblSupportWorker sw
ON en.EconomicSupportWorkerID = sw.SupportWorkerID
INNER JOIN Connect.dbo.tblPerson p
ON en.ClientID = p.PersonID
LEFT OUTER JOIN aspnetdb.dbo.tblDemographics dm
ON en.CMOSocialWorkerID = dm.UserID
LEFT OUTER JOIN aspnetdb.dbo.tblDemographics dm2
ON en.CMONurseID = dm2.UserID
WHERE (en.CMOSocialWorkerID = '060632EE-BE09-4057-B17B-2D0190D0FF74'
OR
en.CMONurseID = '060632EE-BE09-4057-B17B-2D0190D0FF74')
AND (en.DisenrollmentDate IS NULL
OR
en.DisenrollmentDate > GetDate())
ORDER BY en.DisenrollmentDate, p.LastName
Since you want to issue 1 query, you should only use 1 datacontext. Add views to one of the databases to represent the other databases tables, then add it all to one LinqToSqlClasses file.
If you can't modify any of the three databases, create a fourth database with views to the other three.