How to create a query for items that appears only in one list - sql

The scenario I am working on is as follows:-
A number of interviews are conducted a food poisoning case
A query called qryFoodInCase ( fldCaseID, fldFood) is generate consisting of all the food mentioned in all the interviews
An other query call qryFoodInInterview( fldCaseID, fldInterviewID, fldFood) consist of the food mentioned in each Interview
Now I am after the sql for a query that will return the food that was not consumed by an interviewee but consumed by one or more other interviewees.
The closest I've got is:
select Q1.fldCaseID,Q1.fldfood,Q2.fldInterviewID,fldGotSick
from qryFoodInCases as Q1
left join
(select * from qryFoodInInterview where qryFoodInInterview.fldInterviewID=1) as Q2
on Q1.fldFood=Q2.fldFood
where Q1.fldCaseID=1
The field Q2.fldInterviewID returns 1 for the food consumed and null for the food not consumed. However, I don't want to hard code the fldInterviewID in the sql. I would like a similar recordset returned for all the interviews in one query.
The SQL for qryFoodInCase and qryFoodInInterview are as follows:-
CREATE VIEW `qryFoodInCases`
AS
SELECT tblCases.fldCaseID
,fldfood
,count(tblFoodHistory.fldFoodID) AS fldFoodFrequency
FROM tblFood
INNER JOIN tblFoodHistory
ON tblFoodHistory.fldFoodID = tblFood.fldFoodID
INNER JOIN tblMealHistory
ON tblFoodHistory.fldMealID = tblMealHistory.fldMealHistoryID
INNER JOIN tblInterviews
ON tblInterviews.fldInterviewID = tblMealHistory.fldInterviewID
INNER JOIN tblCases
ON tblCases.fldCaseID = tblInterviews.fldCaseID
GROUP BY tblCases.fldCaseID, tblFood.fldFood
OUTPUT:
+-----------+------------+------------------+
| fldCaseID | fldFood | fldFoodFrequency |
+-----------+------------+------------------+
| 1 | Banana | 3 |
| 1 | Beans | 5 |
| 1 | Cabagge | 3 |
| 1 | Chicken | 1 |
| 1 | Pork | 5 |
| 1 | Potatoes | 1 |
| 1 | Rice | 1 |
| 1 | fried fish | 1 |
| 2 | Cabagge | 1 |
| 2 | Chicken | 2 |
| 2 | Potatoes | 1 |
| 2 | Rice | 1 |
| 2 | Salad | 1 |
+-----------+------------+------------------+
and
CREATE VIEW `qryFoodInInterview`
AS
SELECT tblInterviews.fldCaseID
,tblInterviews.fldInterviewID
,tblFood.fldFood
,tblInterviews.fldGotSick
FROM tblInterviews
INNER JOIN tblMealHistory
ON tblInterviews.fldInterviewID = tblMealHistory.fldInterviewID
INNER JOIN tblFoodHistory
ON tblFoodHistory.fldMealID = tblMealHistory.fldMealHistoryID
INNER JOIN tblFood
ON tblFood.fldFoodID = tblFoodHistory.fldFoodID
GROUP BY tblInterviews.fldInterviewID, tblFoodHistory.fldFoodID
OUTPUT
+-----------+----------------+------------+------------+
| fldCaseID | fldInterviewID | fldFood | fldGotSick |
+-----------+----------------+------------+------------+
| 1 | 1 | Pork | 0 |
| 1 | 1 | Banana | 0 |
| 1 | 1 | Rice | 0 |
| 1 | 1 | Potatoes | 0 |
| 1 | 2 | Chicken | 1 |
| 1 | 2 | Banana | 1 |
| 1 | 2 | Beans | 1 |
| 1 | 4 | Pork | 1 |
| 1 | 4 | fried fish | 1 |
| 1 | 4 | Beans | 1 |
| 2 | 6 | Salad | 0 |
| 2 | 6 | Chicken | 0 |
| 2 | 6 | Cabagge | 0 |
| 2 | 6 | Rice | 0 |
| 2 | 6 | Potatoes | 0 |
| 1 | 8 | Pork | 0 |
| 1 | 8 | Cabagge | 0 |
| 1 | 9 | Pork | 1 |
| 1 | 9 | Banana | 1 |
| 1 | 9 | Beans | 1 |
| 1 | 10 | Cabagge | 1 |
| 1 | 10 | Beans | 1 |
| 1 | 11 | Pork | 1 |
| 1 | 11 | Cabagge | 1 |
| 1 | 11 | Beans | 1 |
+-----------+----------------+------------+------------+

SQL Fiddle Demo
create a cross join off all food with all interviewrs
then a left join to see which one didnt had interview
the null mean interview didnt consume food
and exists mean someone different to interview consume food
.
SELECT F.fldFood, I.fldInterviewID, FI.fldInterviewID
FROM qryFoodInCases F, (SELECT DISTINCT fldInterviewID FROM qryFoodInInterview) I
LEFT JOIN qryFoodInInterview FI
ON F.fldFood = FI.fldFood
AND I.fldInterviewID = FI.fldInterviewID
WHERE FI.fldInterviewID IS NULL
AND EXISTS (SELECT 1
FROM qryFoodInInterview Q1
WHERE Q1.fldFood = F.fldFood
AND Q1.fldInterviewID <> I.fldInterviewID)
;
The trick was do the thing one step at the time. Once I realize I need all the combinations and create the cross join, the rest was easy.

select Q1.fldCaseID,Q1.fldfood,Q2.fldInterviewID,fldGotSick
from qryFoodInCases as Q1
left join
(select * from qryFoodInInterview QF1
JOIN qryFoodInInterview QF2
where QF1.fldInterviewID <> QF2.fldInterviewID
AND QF1.fldInterviewID > QF2.fldInterviewID
) as Q2
on Q1.fldFood=Q2.fldFood
where Q1.fldCaseID=1
As you mentioned you want to duplicate the items FoodInterviews, self JOIN will suffice your question. Please try this out , caution I didn't tested it.
Fixing Missed Self Join Condition to fix duplicates.

Related

SQL Merge two Tables

Let's say I have these 2 tables:
ArticleTBL
+---------+----------+-------------+------------+
|articleid| typeid | price | user |
+---------+----------+-------------+------------+
| 0 | 2 | 1 | 122 |
| 1 | 3 | 2 | 344 |
| 2 | 3 | 1 | 455 |
| 3 | 1 | 4 | 34 |
+---------+----------+-------------+------------+
TypeTBL
+---------+----------+-------------+
|typeid | type | factory |
+---------+----------+-------------+
| 0 | wooden | factry1 |
| 1 | plastic | factry2 |
| 2 | metal | factry3 |
| 3 | sth. | factry4 |
+---------+----------+-------------+
How do I request all this information only with articleid for each row?
Isn't this what you want? Read more
SELECT a.articleid,
a.price.a.USER,
t.typeid,
t.type,
t.factory
FROM form ArticleTBL a
INNER JOIN typetbl t
ON a.typeid = t.typeid
WHERE a.articleid = 0

Join and Group Three Tables On Multiple Criteria - SQL

I am trying to join three separate tables based on certain criteria. Here are table examples:
TABLE A
+----+------------+----------+---------+
| id | entry num | line num | inv line|
+----+------------+----------+---------+
| 1 | 1 | 1 | 1 |
| 2 | 1 | 1 | 2 |
| 3 | 2 | 1 | 1 |
| 4 | 2 | 2 | 1 |
| 5 | 3 | 1 | 1 |
| 6 | 3 | 1 | 2 |
| 7 | 3 | 1 | 3 |
+----+------------+--------+-----------+
TABLE B
+----+------------+----------+---------+
| id | entry num | line num | code |
+----+------------+----------+---------+
| 1 | 1 | 1 | 100 |
| 2 | 2 | 1 | 370 |
| 3 | 2 | 2 | 120 |
| 4 | 3 | 1 | 300 |
+----+------------+--------+-----------+
TABLE C
+----+------------+--------+-----------+
| id | rate | amt | code |
+----+------------+--------+-----------+
| 1 | 25% | $50 | 100 |
| 2 | 50% | $20 | 370 |
| 3 | 50% | $25 | 120 |
| 4 | 30% | $150 | 300 |
+----+------------+----------+---------+
I need the final table to look like this, but I am at a loss on how to write the syntax:
FINAL TABLE
+----+------------+----------+---------+---------+---------+---------+
| id | entry num | line num | inv line| code | rate | amt |
+----+------------+----------+---------+---------+---------+---------+
| 1 | 1 | 1 | 1 | 100 | 25% | $50 |
| 2 | 1 | 1 | 2 | 100 | 25% | $50 |
| 3 | 2 | 1 | 1 | 370 | 50% | $20 |
| 4 | 2 | 2 | 1 | 120 | 50% | $25 |
| 5 | 3 | 1 | 1 | 300 | 30% | $150 |
| 6 | 3 | 1 | 2 | 300 | 30% | $150 |
| 7 | 3 | 1 | 3 | 300 | 30% | $150 |
+----+------------+----------+---------+---------+---------+---------+
Ultimately, I need table A and B joined where both entry num and line num match, but then I need to show each individual row for the inv line number.
For example, entry num 3 / line num 1 will has 3 invoice numbers. All entry num 3/ line num 1 will have the code 300, 30% rate, and $150 amount, but I need to visibly see that there are 3 invoice lines.
I've tried to join tables, group them, and get total counts, but to no avail. Thanks for your help!
I think that you need to create joins between TableA and Table B on EntryNum and LineNum, and then between TableB and TableC on Code. Your SQL should look like:
SELECT A.ID, A.EntryNum, A.LineNum, A.InvLine, B.Code, C.Rate, C.Amt
FROM TableC AS C INNER JOIN (TableB AS B INNER JOIN TableA AS A ON (B.LineNum = A.LineNum) AND (B.EntryNum = A.EntryNum))
ON C.Code = B.Code;
Which produces the result that you want:
Regards,

How to structure a proper SQL subquery?

I'm trying to wrap my head around how to do a proper subquery, it's not making sense to me, lets say I have two tables books and chapters:
Books
+----+------------------+----------+---------------------+
| id | name | author | last_great_chapters |
+----+------------------+----------+---------------------+
| 1 | some book title | john doe | 2 |
| 2 | foo novel title | some guy | 4 |
| 3 | other book title | lol man | 3 |
+----+------------------+----------+---------------------+
Chapters
+----+---------+----------------+
| id | book_id | chapter_number |
+----+---------+----------------+
| 1 | 1 | 1 |
| 2 | 1 | 3 |
| 3 | 1 | 4 |
| 4 | 1 | 5 |
| 5 | 2 | 1 |
| 6 | 2 | 2 |
| 7 | 2 | 3 |
| 8 | 2 | 4 |
| 9 | 2 | 5 |
| 10 | 3 | 1 |
| 11 | 3 | 2 |
| 12 | 3 | 3 |
| 13 | 3 | 4 |
| 14 | 3 | 5 |
+----+---------+----------------+
How can I join the two tables, and just print out the number of rows (sorted limit(last_great_chapters)) of the "last_great_chapters" from the books table list for each book?
if I understood correctly, you want to print out table books and last_great_chapters count in Chapters table?
if yes, try it
select b.id, b.name, b.author , b.last_great_chapter, COUNT(c.chapter_number) as rownumbers FROM Books as b
LEFT JOIN Chapters AS C ON c.chapter_number = b.last_great_chapters
group by b.id, b.name, b.author , b.last_great_chapter

trying to write a query with Table A,B where Cond1: A.pc=B.pc & Cond2: (preferred (A.sub = B.Sub) or else any 1 row that meet only Cond1)

I trying to get the result table to contain rows where
Condition1: A.pc=B.pc AND
Condition2: (preferred (A.sub = B.Sub) or
else any one row that satisfy only Condition1)
I have tried the following inner join query and few other join and sub-query but can not figure out exact way to write a query with above strange condition.
SELECT * FROM tblA AS A INNER JOIN tblB AS B
ON A.sub=B.sub
WHERE A.pc=B.pc
tblA
-------------------
| id | pc | sub |
-------------------
| 0 | 5 | abc |
| 1 | 8 | def |
| 2 | 6 | ghi |
| 3 | 2 | jkl |
| 4 | 7 | mno |
| 5 | 19 | pqr |
-------------------
tblB
-------------------------
| pc | sub | uml | ull |
-------------------------
| 3 |arm | 1 | 1 |
| 3 |gtk | 1 | 2 |
| 3 |lmn | 1 | 3 |
| 3 |pop | 1 | 4 |
| 5 |abc | 1 | 5 |
| 5 |hlq | 1 | 6 |
| 5 |pon | 2 | 1 |
| 5 |qrt | 2 | 2 |
| 7 |alo | 2 | 3 |
| 7 |mno | 2 | 4 |
| 7 |ghm | 2 | 5 |
| 7 |stm | 2 | 6 |
| 9 |mck | 2 | 7 |
| 9 |plo | 3 | 1 |
| 9 |rtk | 3 | 2 |
| 9 |ert | 3 | 3 |
| 6 |gji | 3 | 4 |
| 6 |ghi | 3 | 5 |
| 6 |yux | 4 | 1 |
| 6 |del | 4 | 2 |
| 2 |jkl | 4 | 3 |
| 2 |jll | 5 | 4 |
| 2 |uin | 6 | 1 |
| 2 |tro | 6 | 2 |
| 19 |ppm | 6 | 3 |
| 19 |kde | 6 | 4 |
| 19 |grp | 6 | 5 |
| 19 |sho | 6 | 6 |
-------------------------
Expected Result Table:
-------------------------------
| id | pc | sub | uml | ull |
-------------------------------
| 0 | 5 |abc | 1 | 5 |
| 2 | 6 |ghi | 3 | 5 |
| 3 | 2 |jkl | 4 | 3 |
| 4 | 7 |mno | 2 | 4 |
| 5 | 19 |ppm | 6 | 3 | *
-------------------------------
* notice this is a arbitrary row as (A.sub=B.sub) not found
** notice there is no result for id=1 as pc=8 do not exist in tblB
Until someone comes up with a better answer, here is some code that does what you want.
Please, note it might not be a good solution in terms of performance (espcially as your tables grow).
SELECT *
FROM (
SELECT tblA.id, tblB.*
FROM tblA INNER JOIN tblB
ON tblA.pc = tblB.pc AND
tblA.id NOT IN (SELECT tblA.id
FROM tblA INNER JOIN tblB
ON tblA.sub = tblB.sub)
GROUP BY tblA.id
UNION
SELECT tblA.id, tblB.*
FROM tblA INNER JOIN tblB
ON tblA.sub = tblB.sub
GROUP BY tblA.id
) AS tu
ORDER BY id ASC;
See, also, this short demo.
One way of doing it I came up with is to repeat a join condition in where clause:
SELECT *
FROM tblA AS A
INNER JOIN tblB AS B
ON A.pc = B.pc
WHERE A.sub = B.sub
OR A.pc = B.pc

SQL query from multiple tables

I am new to SQL, I need some help,
I want to find out confirmed (confirmed=1) reservation date with last name Steven
Can some one help for with the this SQL Query
table_member
+-----------+-----------+
|Member_id | last_name |
+-----------+-----------+
| 1 | David |
| 2 | owen |
| 3 | Tom |
| 4 | Steven |
| 5 | Steven |
| 6 | Steven |
| 7 | Steven |
| 8 | Steven |
| 9 | Steven |
+-----------+-----------+
table_resevation
+-----------+-----------+-----------+-----------+
|resvationID|Member_id | day | month |
+-----------+-----------+-----------+-----------+
| 1 | 1 | 1 | 6 |
| 2 | 1 | 2 | 6 |
| 3 | 2 | 1 | 6 |
| 4 | 4 | 1 | 6 |
| 5 | 4 | 2 | 6 |
| 6 | 5 | 1 | 6 |
| 7 | 5 | 2 | 6 |
| 8 | 7 | 3 | 6 |
+-----------+-----------+-----------+-----------+
Confirm
+-----------+-----------+-----------+
|confirmID |resvationID| confirmed |
+-----------+-----------+-----------+
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 3 | 0 |
| 4 | 4 | 0 |
| 5 | 5 | 1 |
| 6 | 6 | 1 |
| 7 | 7 | 0 |
| 8 | 8 | 1 |
+-----------+-----------+-----------+
Does something like this work for you?
SELECT
m.Member_ID, m.Last_Name,
r.Day, r.Month,
c.ConfirmID
FROM
table_member m
INNER JOIN
table_reservation r ON r.Member_ID = m.Member_ID
INNER JOIN
Confirm c ON c.resvationID = r.resvationID
WHERE
m.Last_Name = 'Steven' AND c.confirmed = 1
Select c.*, r.*, m.*
from confirm c
left join table_reservation r on c.reservationID = r.reservationID
left join table_member m on m.member_id = r.Member_id
Where c.confirmed = 1
and m.name = "Steven"
I did not test it, but that should point you to the way.
(Edit: second "where" was a typo)
Apply inner join on all table
select day,month from table_reservation inner join table_member on table_member.member_id=table_reservation.member_id
inner join confirm on confirm.reservationid=table_reservation.reservationid where confirm.confirmid=1
and table_member.last_name like 'Steven'