Select from two tables giving more rows than expected - sql

I am not sure why this behaves this way. I need to select few values from two tables based on some criteria which should be clear from the query i tried below.
query = #"SELECT n.borrower, a.sum, n.lender FROM Notification AS n, Acknowledgment AS a
WHERE n.deleted=#del2 AND n.id IN (SELECT parent_id FROM Acknowledgment
WHERE status=#status AND deleted=#del1)";
This returns more rows (12) than expected.
I have two tables Notification and Acknowledgment both which have field "sum". When I try the query below it gives the correct 3 rows as expected.
#"SELECT n.borrower, n.sum, n.lender FROM Notification AS n
WHERE n.deleted=#del2 AND n.id IN (SELECT parent_id FROM Acknowledgment
WHERE status=#status AND deleted=#del1)";
Now I need to extend this query so that I need a.sum and not n.sum. But when I try the first query, it gives a lot more rows, I mean the WHERE condition doesn't work. I dunno if its a quirk with MS Access or something wrong with query. I appreciate an alternate implementation in access if my query seems fine 'cos it simply doesn't work! :)
I have read here that different databases implement select in different ways. Dunno if its something specific with access..
After suggestion from Li0liQ, I tried this:
#"SELECT n.borrower, a.sum, n.lender FROM Notification AS n
INNER JOIN Acknowledgment AS a ON a.parent_id = n.id AND a.status=#status AND a.deleted=#deleted1
WHERE n.deleted=#deleted2"
But I now get a "JOIN expression not supported" error.

This is expected behavior because of the cartesian product:
FROM Notification AS n, Acknowledgment AS a
If you have 10 notifications and 5 acknowledgements, you'll get 50 rows in the result, representing all possible combinations of a notification and an acknowledgement. That set is then filtered by the WHERE clause. (That's standard for SQL, not specific to MS Access.)
It sounds like you need a JOIN:
FROM Notification AS n INNER JOIN Acknowledgement AS a ON n.id = a.parent_id
You can then get rid of the subquery:
WHERE n.deleted=#del2 AND a.status=#status AND a.deleted=#del1
EDIT
As requested by nawfal, here is the solution he arrived at, which essentially incorporates the above recommendations:
string query = #"SELECT n.borrower, a.sum, n.lender FROM Notification AS n
INNER JOIN Acknowledgment AS a ON a.parent_id=n.id
WHERE a.status=#status AND a.deleted=#deleted1 AND n.deleted=#deleted2";

In first query you seem to be trying to perform a JOIN.
However you end up performing CROSS JOIN, i.e. you query for all possible combinations from both tables (I bet you have 4 rows in the Acknowledgment table).
I hope the following query could do the trick or at least help you think in the right direction:
SELECT
n.borrower, a.sum, n.lender
FROM
Notification AS n
INNER JOIN
Acknowledgment AS a
ON
a.parent_id = n.id
WHERE
n.deleted=#del2 AND a.status=#status AND a.deleted=#del1

Something seems to be wrong with Access, that I could get this working only by reconstructing the query provided by the answerers here this way:
string query = SELECT n.borrower, a.sum, n.lender FROM Notification AS n
INNER JOIN Acknowledgment AS a ON a.parent_id=n.id
WHERE a.status=#status AND a.deleted=#deleted1 AND n.deleted=#deleted2;

Related

SQL Inner Join and Grouping

It's been a while since I've done SQL, but I have a rather pressing issue.
My db-layout is as following:
Now, starting from a Users.ID, I want to get all the Rounds the user has played. The user could be Hosts.HostID, Host.GuestID, or even both. Where he is both, it should not show op in the results.
The results I need from the Query are the Hosts.Name and all the fields of Rounds. In general what I want to do is display a list of all the Hosts (actually these are the Games) in which the user has participated, as a Host or as a Guest, along with perhaps a total score. When clicking on this, some dropdown will appear showing the individual round scores, words, ...
Now I was wondering whether this was possible in a single query. Of course I could do a query getting all the Hosts and then per Host a query for each Round, but that doesn't seem that performant. This is what I've come up with so far:
SELECT Rounds.ID, Rounds.GameID, Rounds.Round, Rounds.Score, Rounds.Word
, Hosts.ID, Hosts.HostID, Hosts.GuestID
FROM Rounds INNER JOIN Hosts
ON Rounds.GameID = Hosts.ID
INNER JOIN Users
ON Hosts.hostID = Users.ID
WHERE Users.ID = 5
The issue is however that it doesn't filter out where the user is both host AND guest, and I can't seem to Group it by Hosts.ID either.
Add Hosts.hostID <> Hosts.guestID to the where clause.
If you are using SQL Server 2005 or later version, you could modify your present query like this:
SELECT Rounds.ID, Rounds.GameID, Rounds.Round, Rounds.Score, Rounds.Word
, Hosts.ID, Hosts.HostID, Hosts.GuestID
FROM Rounds INNER JOIN Hosts
ON Rounds.GameID = Hosts.ID
CROSS APPLY
(
SELECT Hosts.HostID
UNION
SELECT Hosts.GuestID
) AS u (UserID)
WHERE u.UserID = 5
;
The CROSS APPLY clause would produce either one or two rows, depending on whether HostID and GuestID are equal. In either event, the WHERE condition would ultimately leave at most one. Thus, the above query would give you only the games (with all their rounds) where the specified user participated.
And from that query you could easily get to something like this:
SELECT Hosts.ID,
TotalScore = SUM(Rounds.Score)
FROM
...
GROUP BY
Hosts.ID
;

Trouble with integrating COUNT function in SQL query using Oracle

I am trying to self educate myself in SQL in order to better use databases at work. For this purpose I am using Oracle Application Express. This if my first time using the COUNT function and I am having some difficulties integrating it within my query. I have done a great deal of research and read quite a bit of literature but I just can't seem to get it right.
My goal is to display the channel_name and channel_number columns (from the channel table) for each channel along with a count of the number of customers that have that channel as a favorite channel (survey_result column from the survey table). Please see below for code:
SELECT channel.channel_number,
channel.channel_name,
survey.survey_result,
count(SELECT survey.survey_result FROM survey)
From Channel, survey
WHERE survey.channel_number = channel.channel_number
Currently I am getting the error message:
ORA-00936: missing expression.
Try this:
Below query gives you only those channels which have minimum 1 customer.
SELECT C.channel_number, C.channel_name, COUNT(S.survey_result) NoOfCustomers
FROM Channel C
INNER JOIN survey S ON S.channel_number = C.channel_number
GROUP BY C.channel_number, C.channel_name;
And below query gives you all channels whether it has customer or not.
SELECT C.channel_number, C.channel_name, COUNT(S.survey_result) NoOfCustomers
FROM Channel C
LEFT JOIN survey S ON S.channel_number = C.channel_number
GROUP BY C.channel_number, C.channel_name;
Either of these may work for you
SELECT channel.channel_number,
channel.channel_name,
count(survey.survey_result)
From Channel, survey
WHERE survey.channel_number = channel.channel_number
GROUP BY
channel.channel_number,
channel.channel_name
or
SELECT channel.channel_number,
channel.channel_name,
survey.survey_result,
(SELECT count(survey_result) FROM survey)
From Channel, survey
WHERE survey.channel_number = channel.channel_number
count is an aggregate function thus you should have a group by on channel.channel_number and channel.channel_name. then just use count(survey.survey_result) instead of count(SELECT survey.survey_result FROM survey). Madhivanan's and Saharsh Shah's answers look good to me. including this answer to explain why.

SQL joins vs nested query

This two SQL statements return equal results but first one is much slower than the second:
SELECT leading.email, kstatus.name, contacts.status
FROM clients
JOIN clients_leading ON clients.id_client = clients_leading.id_client
JOIN leading ON clients_leading.id_leading = leading.id_leading
JOIN contacts ON contacts.id_k_p = clients_leading.id_group
JOIN kstatus on contacts.status = kstatus.id_kstatus
WHERE (clients.email = 'some_email' OR clients.email1 = 'some_email')
ORDER BY contacts.date DESC;
SELECT leading.email, kstatus.name, contacts.status
FROM (
SELECT *
FROM clients
WHERE (clients.email = 'some_email' OR clients.email1 = 'some_email')
)
AS clients
JOIN clients_leading ON clients.id_client = clients_leading.id_client
JOIN leading ON clients_leading.id_leading = leading.id_leading
JOIN contacts ON contacts.id_k_p = clients_leading.id_group
JOIN kstatus on contacts.status = kstatus.id_kstatus
ORDER BY contacts.date DESC;
But I'm wondering why is it so? It looks like in the firt statement joins are done first and then WHERE clause is applied and in second is just the opposite. But will it behave the same way on all DB engines (I tested it on MySQL)?
I was expecting DB engine can optimize queries like the fors one and firs apply WHERE clause and then make joins.
There are a lot of different reasons this could be (keying etc), but you can look at the explain mysql command to see how the statements are being executed. If you can run that and if it still is a mystery post it.
You always can replace join with nested query... It's always faster but lot messy...

SQL to query drupal nodes with multiple taxonomies

Good morning all.
I've read some of the suggested question before posting this but seems like no one has my same issue (probably and inidicator of how bad I am in Drupal and coding in general)
I need to write a query that returns all the nodes with TWO SPECIFIC taxonomies associated to it (of which I know the IDs), but it seems I don't know the right syntax cause I just manage to get it work with ONE term id.
Here's what I have so far (and works)
SELECT * FROM node
INNER JOIN term_node AS tn ON node.vid = tn.vid
LEFT JOIN content_type_extra_content AS xc ON node.vid = xc.vid
WHERE tn.tid IN (SELECT th.tid FROM term_hierarchy AS th WHERE th.tid = '146')
That '146' is the id of the first taxonomy term I need to check (call it "shoes")
Now I have to check that the node has also the taxonomy id '223' (call it "season")
I've tried different solutions with no avail.
I'm pretty sure the solution is under my nose but at the moment I can't wrap my head around it.
Please note that the taxonomies are in different vocaboularies and they are at level-0
Thanks in advance for any help
If I understand you correctly, you want the nodes which have 2 specific terms (shoes and season), then try something like this:
SELECT * FROM node
INNER JOIN term_node AS tn ON node.vid = tn.vid
LEFT JOIN content_type_extra_content AS xc ON node.vid = xc.vid
WHERE tn.tid IN ('146','223')
GROUP BY node.vid
HAVING count(*) = 2

SQL - Count query question

I want to know how many users answerd a question, so I made that query :
SELECT answer.idAnswer,
answer.title,
answercategory.label,
(SUM(1)) as nbAnswer
FROM ANSWER
INNER JOIN answerCategory ON answer.idAnswerCategory = answercategory.idAnswerCategory
LEFT JOIN answerUser ON answer.idAnswer = answerUser.idAnswer
GROUP BY answer.idAnswer
Its almost working, the only thing that doesn't work is that it's giving me "one" answer if nobody answered the question (it means even if there are no records in answerUser). I would like to have zero instead of one in that case. If I add a "-1", when there is one answer, I'll get zero. Any idea how I can correct that?
Use COUNT(answerUser.idAnswer) instead of SUM(1). Count will ignore the NULL rows created by the LEFT JOIN.
Use COUNT(*) instead of SUM(1).
SELECT answer.idAnswer, answer.title, answercategory.label, count(*) as nbAnswer
FROM answer
INNER JOIN answerCategory on answer.idAnswerCategory = answercategory.idAnswerCategory
LEFT JOIN answerUser ON answer.idAnswer = answerUser.idAnswer
GROUP BY answer.idAnswer