SQL Statement with joins & where clause - sql

I am still working on a Social Networking script, and I have pretty much finished it up now, however there is one problem I have been unable to resolve, that is outputting all of the posts by users AND the user logged in, the latter being the issue.
With the following statement, I have been able to get the status message to output, however other information such as their name and profile information is not.. joined? I think that is what is not happening:
So, when it is not the logged in user, their alongside their status displays, however when its the person logged in (e.g UserID 1, and yes.. I have removed the variable and just put a number) it just shows their message and doesn't access the user information.
SELECT * FROM al_posts
LEFT JOIN al_friendships ON al_posts.user_id = al_friendships.user_b
LEFT JOIN al_users ON al_friendships.user_b = al_users.id
WHERE al_friendships.user_a = '{$_SESSION['UserID']}' OR al_posts.user_id = '{$_SESSION['UserID']}'
The database structure for the tables in question: (note, the friendship table is not an issue so I have left it out)
al_posts table
al_users table
If there is anything anyone notices wrong with the syntax, I would really appreciate it if you could explain what I did wrong so I can correct it. Thanks

Putting the condition on an outer joined table into the where clause turns it effictively into an inner join. You need to apply this in the join condition:
SELECT *
FROM al_posts
LEFT JOIN al_friendships
ON al_posts.user_id = al_friendships.user_b
AND al_friendships.user_a = '{$_SESSION['UserID']}'
LEFT JOIN al_users ON al_friendships.user_b = al_users.id
WHERE al_posts.user_id = '{$_SESSION['UserID']}'
The reason why the condition will make this an inner join is that the rows that "do not" match come back with NULL values in the columns of the outer joined table. Comparing a value against NULL returns "undefined" and thus the condition is false, filtering out all rows that were "outer joined".

I resolved this issue and forgot to mark it as resolved, essentially I got the joins in a real tangle. I sat back, thought about exactly what I wanted to achieve and this was the final working query that I came up with.
SELECT *
FROM al_posts
JOIN al_friendships
ON al_posts.user_id = al_friendships.user_b
AND al_friendships.user_a = '{$_SESSION['UserID']}'
JOIN al_users ON al_friendships.user_b = al_users.id
Thanks for the help guys!

Related

MS ACCESS SQL issue with combine LEFT JOINS and INNER JOINS

MS Access has been just killing me when It comes to writing my own SQL queries and I hate it's GUI query tool. I gave up trying to combine LEFT JOINS and INNER JOINS now I'm doing all inner join's and i'm still getting murdered. Can someone link to me to a comprehensible MS Access SQL guide and/ or tell me what I am doing wrong here. I've tried putting my code in parenthesis, bracketing my fields. I'm at my wits end.
SELECT answers.*
FROM (((answers
INNER JOIN caseInfo
ON answers.[ABAWDNum] = caseinfo.[ABAWDNum])
INNER JOIN Questions)
ON answers.[questionID] = questions.[questionID])
INNER JOIN responseCodes
ON answers.[responseIDCode] = responseCodes.[responsecode]
I'm not sure if my picture of the error is coming up but it says Sytnax error in FROM clause and it has the parenthesis right after the Questions table is mentioned
enter image description here
EDIT: Database relationships:
enter image description here
Access INNER JOIN can only work on two data sets at once, so if you want to join more than two tables, you have to nest the INNER JOINS using brackets, as described here:
https://learn.microsoft.com/en-us/previous-versions/office/developer/office-2007/bb208854(v=office.12)
From that page it says the syntax to do this is...
SELECT fields FROM table1 INNER JOIN (table2 INNER JOIN [( ]table3 [INNER JOIN [( ]tablex [INNER JOIN …)] ON table3.field3compoprtablex.fieldx)] ON table2.field2compoprtable3.field3) ON table1.field1compoprtable2.field2;
I believe this will give you all fields from the table answers that meet your join conditions.
SELECT answers.*
FROM answers
INNER JOIN caseInfo
ON answers.[ABAWDNum] = caseinfo.[ABAWDNum]
INNER JOIN Questions
ON answers.[questionID] = questions.[questionID]
INNER JOIN responseCodes
ON answers.[responseIDCode] = responseCodes.[responsecode]
Just to humor Access I used the GUI/Design mode to build a query.
Here's the query I got that ran. From a table with 674 records, it only returned 6 answers, but that is a separate problem that I have to deal with. At least this thing runs.
But I have a feeling once I start asking for left joins I'm in trouble. <_< F* access.
SELECT answers.*
FROM (Questions
INNER JOIN (CaseInfo
INNER JOIN answers ON CaseInfo.ABAWDNum = answers.ABAWDNum)
ON Questions.questionID = answers.questionID)
INNER JOIN responseCodes ON (Questions.questionID = responseCodes.questionCode)
AND (answers.responseIDCode = responseCodes.responseCode);
EDIT:
I used the GUI/Designer again to try to make a query that was closer to what I needed, which is all of the answers in the answers table plus just a few things from the question table, caseinfo table, and responsecode tables , and this is what I got
SELECT
CaseInfo.ABAWDNum, CaseInfo.Admin, CaseInfo.Unit,
CaseInfo.[ASV-DRV Completed By], CaseInfo.reviewerID, CaseInfo.[Recieved Date],
CaseInfo.[Date Reviewed],
Questions.Question,
answers.responseIDCode, responseCodes.responseDescription, answers.comments
FROM
CaseInfo
RIGHT JOIN
((Questions
RIGHT JOIN
answers ON Questions.questionID = answers.questionID)
LEFT JOIN
responseCodes ON answers.responseIDCode = responseCodes.responseCode)
ON CaseInfo.ABAWDNum = answers.ABAWDNum;
This is really insane. I'm going to have to study this really hard. It looks like access is very particular on how it wants it's joins, but this seems to give me the correct results. 674 records returned.

Is it possible to detect where the join fails on a certain record?

Please bear with me as this may be a question without a possible answer, but I hope I describe it correctly..
I have a query which joins a number of tables and produces results, and here is the SQL:
SELECT
dbo.Property.PropertyPK,
dbo.Tenancy.TenancyPK,
dbo.Tenant.ContactFK,
dbo.Contacts.strTitle,
dbo.Contacts.strFirstName,
dbo.Contacts.strSurname
FROM dbo.Property
INNER JOIN dbo.Tenancy ON dbo.Property.PropertyPK = dbo.Tenancy.PropertyFK
INNER JOIN dbo.Tenant ON dbo.Tenancy.TenancyPK = dbo.Tenant.TenancyFK
INNER JOIN dbo.Contacts ON dbo.Tenant.ContactFK = dbo.Contacts.ContactPK
The main table is the Property table and I filter out one row by specifying a PropertyPK in my criteria..
My question is.. If the Tenant or Contact record does not exist and I run my query in SQL Management Studio of course I get a message saying there are no rows but can I determine at what stage the join has failed between two tables?
I can of course check this in management studio but I am trying to help the user on the application side to inform them of why there are no rows. My application is in VB and I will write that check if there are no rows and I cannot determine it in SQL..
Sorry for the question in advance..
Derek.. :)
Simply use a LEFT JOIN:
SELECT p.PropertyPK, ty.TenancyPK, t.ContactFK,
c.strTitle, c.strFirstName, c.strSurname
FROM dbo.Property p LEFT JOIN
dbo.Tenancy ty
ON p.PropertyPK = ty.PropertyFK LEFT JOIN
dbo.Tenant t
ON ty.TenancyPK = t.TenancyFK LEFT JOIN
dbo.Contacts c
ON t.ContactFK = c.ContactPK;
This will keep all rows in the Property table. You can then see which primary keys are NULL to see if there were matches in the other tables.
Note that the query is much easier to write and to read when you use table aliases.

Left join fails if not explicitly using ISNULL

I have a large table User and a small table User_purchase in google bigquery.
If I join the two with
SELECT User.id, User_purchase.amount FROM User
LEFT JOIN User_purchase on User.id = User_purchase.user_id,
the query returns error:
Query Failed. Error: Not Implemented: This table cannot be read
But if I join the two with
SELECT User.id, ISNULL(INTEGER(User_purchase.amount), INTEGER(0)) FROM User
LEFT JOIN User_purchase on User.id = User_purchase.user_id,
the query works.
Don't quite understand why the first case does not work.
I assume in the first case I can get all users with their purchase_amount though some users will have NULL as their purchase_amount.
Thanks.
This is a bug relating to nested field names in query replies. I've got a fix for the bug but it won't go out until next week's release. Thanks for bringing it to our attention.

Sql syntax to always get one

SELECT dbo.Calls.Description, dbo.TicketRead.IsRead, dbo.TicketRead.UserID
FROM dbo.Calls
LEFT OUTER JOIN dbo.TicketRead ON dbo.Calls.CallID = dbo.TicketRead.TicketID
WHERE dbo.TicketRead.UserID = 1 or is null
I want to get a list of all calls, but also a value indicating if the user have read the call. so I made when a user open's the ticket a new record is added in a special table.
now if no user have read it then it's ok, but if just one user have read this ticket, then the other users don't have this call in the list..
I'm using msSql and .net entity framework.
Are you sure you want to limit the TicketRead table to just UserID # 1?
SELECT c.Description, r.IsRead, r.UserID
FROM dbo.Calls c
LEFT JOIN dbo.TicketRead r
ON c.CallID = r.TicketID
AND r.UserID = 1
This is done joining on multiple conditions... You'll get all of the Calls, but only the IsRead flag from TicketRead when UserID #1 has read it.
I'm not convinced this is actually what you're looking for, and I will be available to update this later if not.
Also please consider using table aliases in the future, I think you'll like it.
you are wanting to do the following:
SELECT dbo.Calls.Description, dbo.TicketRead.IsRead, dbo.TicketRead.UserID
FROM dbo.Calls
LEFT OUTER JOIN dbo.TicketRead ON dbo.Calls.CallID = dbo.TicketRead.TicketID
WHERE
dbo.TicketRead.UserID = 1
or dbo.TicketRead.CallID IS NULL
basically, we are saying here, if there a userid, it has to be 1. otherwise, the records primary key is null (because of the join). Fosco's answer is also right, and much smaller :)

Super Slow Query... What have I done wrong?

You guys are amazing. I've posted here twice in the past couple of days - a new user - and I've been blown away by the help. So, I figured I'd take the slowest query I've got in my software and see if anyone can help me speed it up. I use this query as a view, so it's important that it be fast (and it isn't!).
First, I have a Contacts Table that store my company's customers. In the table is a JobTitle column which contains an ID which is defined in the Contacts_Def_JobFunctions table. There is also a table called contacts_link_job_functions which holds the contactID number and additional job functions the customer has - also defined in the Contacts_Def_JobFunctions table.
Secondly, the Contacts_Def_JobFunctions table records have a parent/child relationship with themselves. In this manner, we cluster similar job functions (for example: maid, laundry service, housekeeping, cleaning, etc. are all the same basic job - while the job title may vary). Job functions which we don't currently work with are maintained as children of ParentJobID 1841.
Third, the institutionswithzipcodesadditional simply provides geographical data to the final result.
Lastly, like all responsible companies, we maintain a remove list for any of our customers that wish to opt-out of our newsletter (after opting in).
I use the following query to build a table of those people who have opted-in to receive our newsletter and who have a job function or job title relevant to the services/products we offer.
Here's my UGLY query:
SELECT DISTINCT
dbo.contacts_link_emails.Email, dbo.contacts.ContactID, dbo.contacts.First AS ContactFirstName, dbo.contacts.Last AS ContactLastName, dbo.contacts.InstitutionID,
dbo.institutionswithzipcodesadditional.CountyID, dbo.institutionswithzipcodesadditional.StateID, dbo.institutionswithzipcodesadditional.DistrictID
FROM
dbo.contacts_def_jobfunctions AS contacts_def_jobfunctions_3
INNER JOIN
dbo.contacts
INNER JOIN
dbo.contacts_link_emails
ON dbo.contacts.ContactID = dbo.contacts_link_emails.ContactID
ON contacts_def_jobfunctions_3.JobID = dbo.contacts.JobTitle
INNER JOIN
dbo.institutionswithzipcodesadditional
ON dbo.contacts.InstitutionID = dbo.institutionswithzipcodesadditional.InstitutionID
LEFT OUTER JOIN
dbo.contacts_def_jobfunctions
INNER JOIN
dbo.contacts_link_jobfunctions
ON dbo.contacts_def_jobfunctions.JobID = dbo.contacts_link_jobfunctions.JobID
ON dbo.contacts.ContactID = dbo.contacts_link_jobfunctions.ContactID
WHERE
(dbo.contacts.JobTitle IN
(SELECT JobID
FROM dbo.contacts_def_jobfunctions AS contacts_def_jobfunctions_1
WHERE (ParentJobID <> '1841')))
AND
(dbo.contacts_link_emails.Email NOT IN
(SELECT EmailAddress
FROM dbo.newsletterremovelist))
OR
(dbo.contacts_link_jobfunctions.JobID IN
(SELECT JobID
FROM dbo.contacts_def_jobfunctions AS contacts_def_jobfunctions_2
WHERE (ParentJobID <> '1841')))
AND
(dbo.contacts_link_emails.Email NOT IN
(SELECT EmailAddress
FROM dbo.newsletterremovelist AS newsletterremovelist))
I'm hoping some of you superstars can help me tune this up.
Thanks so much,
Russell Schutte
UPDATE - UPDATE - UPDATE - UPDATE - UPDATE
After getting several feedback messages, most notably from Khanzor, I've worked hard on tuning this query and have come up with the following:
SELECT DISTINCT
contacts_link_emails.Email, contacts.ContactID, contacts.First AS ContactFirstName, contacts.Last AS ContactLastName, contacts.InstitutionID,
institutionswithzipcodesadditional.CountyID, institutionswithzipcodesadditional.StateID, institutionswithzipcodesadditional.DistrictID
FROM contacts
INNER JOIN
contacts_def_jobfunctions ON contacts.jobtitle = contacts_def_jobfunctions.JobID AND contacts_def_jobfunctions.ParentJobID <> '1841'
INNER JOIN
contacts_link_jobfunctions ON contacts_link_jobfunctions.JobID = contacts_def_jobfunctions.JobID AND contacts_def_jobfunctions.ParentJobID <> '1841'
INNER JOIN
contacts_link_emails ON contacts.ContactID = contacts_link_emails.ContactID
INNER JOIN
institutionswithzipcodesadditional ON contacts.InstitutionID = institutionswithzipcodesadditional.InstitutionID
LEFT JOIN
newsletterremovelist ON newsletterremovelist.emailaddress = contacts_link_emails.email
WHERE
newsletterremovelist.emailaddress IS NULL
This isn't quite perfect (I suspect I should have made something an outer join or a right join or something, and I'm not really sure). My result set is about 40% of the records my original query provided (which I'm no longer 100% positive was a perfect query).
To clean things up, I took out all the "dbo." prefixes that SQL Studio adds. Do they do anything?
What am I doing wrong now?
Thanks,
Russell Schutte
== == == == ==
== ANOTHER UPDATE == ANOTHER UPDATE == ANOTHER UPDATE == ANOTHER UPDATE == ANOTHER UPDATE
== == == == ==
I've been working on this one query for several hours now. I've got it down to this:
SELECT DISTINCT
contacts_link_emails.Email, contacts.contactID, contacts.First AS ContactFirstName, contacts.Last AS ContactLastName, contacts.InstitutionID,
institutionswithzipcodesadditional.CountyID, institutionswithzipcodesadditional.StateID, institutionswithzipcodesadditional.DistrictID
FROM
contacts INNER JOIN institutionswithzipcodesadditional
ON contacts.InstitutionID = institutionswithzipcodesadditional.InstitutionID
INNER JOIN contacts_link_emails
ON contacts.ContactID = contacts_link_emails.ContactID
LEFT OUTER JOIN contacts_def_jobfunctions
ON contacts.JobTitle = contacts_def_jobfunctions.JobID AND contacts_def_jobfunctions.ParentJobID <> '1841'
LEFT OUTER JOIN contacts_link_jobfunctions
ON contacts_link_jobfunctions.JobID = contacts_def_jobfunctions.JobID AND contacts_def_jobfunctions.ParentJobID <> '1841'
LEFT OUTER JOIN
newsletterremovelist ON newsletterremovelist.EmailAddress = contacts_link_emails.Email
WHERE (newsletterremovelist.EmailAddress IS NULL)
Disappointingly, I'm just not able to fill in the gaps in my knowledge. I'm new to joins, except when I have the visual tool build them for me, so I'm thinking I want everything from contacts, institutionswithzipcodesadditional, and contacts_link_emails, so I've INNER JOINed them (above).
I am stumped on the next bit. If I INNER JOIN them, then I get people who have the proper jobs (<> 1841) - but I'm thinking I LOSE out on people who don't have an entry for both JobTitle AND JobFunctions. In many cases, this isn't right. I could have a JobTitle "Custodian" which I'd want to keep on our newsletter list, but if he doesn't also have a JobFunction entry, I think he'll fall off the list if I use INNER JOIN.
BUT, if I do the query with LEFT OUTER JOINs, as above, I think I get lots of people with the wrong JobTitles, simply because anyone who is lacking EITHER a JobTitle OR a JobFunction would be ON my list - they could be a "High Level Executive" with no JobFunction, and they'd be on the list - which isn't right. We no longer have services appropriate to "High Level Executives".
Then I see how the LEFT OUTER JOIN works for the newsletterremovelist. It's pretty slick and I think I've done it right...
But I'm still stuck. Hopefully someone can see what I'm trying to do here and steer me in the right direction.
Thanks,
Russell Schutte
UPDATE AGAIN
Sadly, this thread seems to have died, without a perfect solution - but I'm getting close. Please see a new thread started which restarts the discussion: click here
(awarded a correct answer for the massive amount of work provided - even while a correct answer hasn't quite been reached).
Thanks!
Russell Schutte
Move the queries in your WHERE out to actual joins. These are called correlated subqueries, and are the work of the Voldemort. If they are joins, they are only executed once, and will speed up your query.
For the NOT IN sections, use a left outer join, and check that the column you joined on is NULL.
Also, avoid using OR in WHERE queries where possible - remember that OR is not neccesarily a short circuit operation.
An example is as follows:
SELECT
*
FROM
dbo.contacts AS c
INNER JOIN
dbo.contacts_def_jobfunctions AS jf
ON c.JobTitle = jf.JobId AND jf.ParentJobID <> '1841'
INNER JOIN
dbo.contacts_link_emails AS e
ON c.ContactID = e.ContactID AND jf.JobID = c.JobTitle
LEFT JOIN
dbo.newsletterremovelist AS rl
ON e.Email = rl.EmailAddress
WHERE
rl.EmailAddress IS NULL
Please don't use this, as it's almost certainly incorrect (not to mention SELECT *), I've ignored the logic for contacts_ref_jobfunctions_3 to provide a simple example.
For a (really) nice explanation of joins, try this visual explanation of joins
Create some views representing some common associations that you make so that your sub-query is simpler. Also views execute a bit quicker as they do not need to be interpreted each time they are run.
It could be any number of things. My first question is are the columns you're joining on indexed?
Better yet, do a SHOWPLAN and paste it into your question.