I am trying to offer tickets for other events to people who have booked for one event. I have two tables like
---Concerts----------------
| ConcertID | Concert |
---------------------------
| 101 | Mozart |
| 102 | Beethoven |
| 103 | Chopin |
---------------------------
---Tickets--------------------------------------------
| TicketNum | Name | email | ConcertID |
------------------------------------------------------
| 5001 | Amy Jones | aaa#aaa.com | 101 |
| 5002 | Amy Jones | aaa#aaa.com | 102 |
| 5003 | John Doe | bbb#bbb.com | 102 |
| 5004 | Adam Smith | ccc#ccc.com | 101 |
| 5005 | Jerry Coe | ddd#ddd.com | 102 |
------------------------------------------------------
I am trying to construct a statement like
SELECT Tickets.email, Concerts.ConcertID, Concerts.Concert FROM Tickets, Concerts
WHERE (Show Concerts Not Booked)
AND Concerts.ConcertID = Tickets.ConcertID
AND email = "bbb.com"
This show then return the two concerts that John Doe is not booked on to i.e. 101 Mozart and 102 Chopin.
It's the (Show Concerts Not Booked) that I am struggling with
I can construct a query to show the intersection of which concerts he is booked on to, but I cannot show the ones that he is not booked on to.
Any help gratefully appreciated.
Select c.ConcertID, C.Concert
From Concerts c
Left join Tickets t On t.ConcertID = c.ConcertID
Where t.ConcertID is null and t.Name = 'John Doe'
Would do that.
Without the aliases might make what is going on clearer
Select Concerts.ConcertID, Concerts.Concert
From Concerts
Left join Tickets On Tickets.ConcertID = Concerts.ConcertID
Where Tickets.ConcertID is null and Tickets.Name = 'John Doe'
Think of it this way, if you wanted a list of all the concerts and whether John had bought a ticket
you would do
Select *
From Concerts
Left join Tickets On Tickets.ConcertID = Concerts.ConcertID
Where Tickets.Name = 'John Doe'
and get
101 Mozart NULL NULL NULL NULL
102 Beethoven 5003 John Doe bbb#bbb.com 102
103 Chopin NULL NULL NULL NULL
so the extra condition in the where statement filters out the rows where no ticket exists.
Well that was irritating, after playing about with #JungSu Heo's sql fiddle, I found this worked
Select *
From Concerts c
Left join Tickets t On t.ConcertID = c.ConcertID and t.Name = 'John Doe'
Where t.ConcertID is null
Makes sense after a bit of thought, because John Doe was in where clause the nulls were being chopped out. Do it in the join clause, then John Doe is only used to constrain the outer join.
Thank you learnt something, though I wouldn't normally see something like this because I'd have had a names/bookers type table.
I can't understand why Tony's query is not working. could you try this?
SELECT c.ConcertID, c.Concert
FROM Concerts c
WHERE c.ConcertID NOT IN
(
SELECT ConcertID
FROM Tickets
WHERE Name = 'John Doe'
)
If you post you data at http://www.sqlfiddle.com/, we would appreciate you. easy to test.
Related
I have two tables in my database.
Couples table:
+---------------------------------------+
| ID | Partner 1 | Partner 2 |
+---------------------------------------+
| 1 | 101 | 102 |
+---------------------------------------+
B table:
+--------------------------------------------------------------
| ID | name | date | Letter | Phonenumber
+--------------------------------------------------------------
| 101| Mark | 1/1/2001 | D | 061234
| 102| lisa | 1/1/2002 | E | 061235
I cant quite figure out how to do the following:
Select from couples table the partners 1 & 2.
From partner 1, grab the name, date, letter & phonenumber.
From partner 2, grab the name, letter and date.
Do this for every couple in the couples table
I cant figure out how to do this, anyone know how? I have been stuck for quite some time now haha.
something like this
+------------------------------------------------------------------------
| ID | name | date | Letter | Phonenumber | name | Letter| date
+------------------------------------------------------------------------
| 1 | Mark | 1/1/2001 | D | 061234 | lisa | E | 1/1/2002
+------------------------------------------------------------------------
You need to join twice - once for each partner. e.g.:
SELECT p1.id, p1.name, p1.date, p1.letter, p1.phonenumber, p2.name, p2.letter, p2.date from couples
JOIN B on (B.id = partner_1) as p1
JOIN B on (B.id = partner_2) as p2
My syntax may not be perfect, but it sounds like you know enough SQL to not need a copy+paste solution, just a pointer on how to solve.
this issue has been bothering me for a few hours now. After finding out my old query had an issue, I had to rebuild it.
The situation:
I need to match each patient_id with a clinic_id, and for that I get all the appointments using the patient_id,
find the highest appointment_id and use its clinic_id to set the last known clinic_id.
My old query did this, but it skipped patients that never had an appointment.
These are my current results, but I need to filter my results. Question is, how?
+---------------+-------------------+-------------------+---------------+
| patient_id | country_code | appointment_id | clinic_id |
+---------------+-------------------+-------------------+---------------+
| 111 | UK | 620 | 3 |
| 111 | UK | 621 | 2 |
| 111 | UK | 1995 | 1 |
| 222 | UK | 609 | 3 |
| 222 | UK | 610 | 2 |
| 333 | UK | null | null |
| 444 | UK | null | null |
+---------------+-------------------+-------------------+---------------+
What I want is the following:
+---------------+-------------------+-------------------+---------------+
| patient_id | country_code | appointment_id | clinic_id |
+---------------+-------------------+-------------------+---------------+
| 111 | UK | 1995 | 1 |
| 222 | UK | 610 | 2 |
| 333 | UK | null | null |
| 444 | UK | null | null |
+---------------+-------------------+-------------------+---------------+
I am using the following query right now:
SELECT
patient.id,
systemcountry.country_code,
appointment_patient.appointment_id,
appointment.clinic_id
FROM
patient
LEFT JOIN
systemcountry ON patient.country_id = systemcountry.id
LEFT JOIN
appointment_patient ON patient_id = patient.id
LEFT JOIN
appointment ON appointment_patient.appointment_id = appointment.id
This was my old query, which had an issue causing it to skip patients that never had an appointment:
SELECT
patient.id AS patient_id,
systemcountry.code AS systemcountry_code,
appointment.clinic_id
FROM
patient
LEFT JOIN
systemcountry ON patient.land_id = systemcountry.id,
appointment
WHERE
appointment.id = (SELECT
MAX(appointment_id)
FROM
appointment_patient
WHERE
patient_id = patient.id);
I am still a beginner, so go easy on me.
I appreciate any input, thanks!
Move the sub-select in your original query's WHERE clause into a LEFT JOIN (something like this):
LEFT JOIN
(SELECT MAX(appointment_id), patient_id
FROM appointment_patient
GROUP BY patient_id) as apt ON patient.patient_id=apt.patient_id
You can try function max() over columns whose only highest value you want, then group by the result set using patient.id
SELECT
patient.id,
systemcountry.country_code,
max(appointment_patient.appointment_id),
appointment.clinic_id
FROM
patient
LEFT JOIN
systemcountry ON patient.country_id = systemcountry.id
LEFT JOIN
appointment_patient ON patient_id = patient.id
LEFT JOIN
appointment ON appointment_patient.appointment_id = appointment.id
GROUP BY patient.id
I'm trying to run a query that shows all the members of a customer that do not belong in one of their groups. I'm comparing two tables that have a common CustomerID and using their member id's to show which members are not in the second table, CustomerGroupMember.
Here is a sample of the two tables.
Customer Member
id | CustomerID | First | Last
---------------------------------
123 | 1234 | Jim | Sample
129 | 1234 | Julie | Clark
137 | 1234 | Jack | Thomas
289 | 1234 | Sue | Smith
Customer Group Member
MemberID | CustomerID | GroupID
---------------------------------
129 | 1234 | 19
289 | 1234 | 20
Below is my query which does not seem to produce any results. I'd like it to output anyone not found in that Customer Group Member table. In the table examples above I'd see an output of members 123 and 137.
SELECT CustomerMember.* FROM CustomerMember
LEFT JOIN
CustomerGroupMember ON CustomerMember.id = CustomerGroupMember.MemberID
WHERE
CustomerMember.CustomerID = '1234' AND CustomerGroupMember.CustomerID = '1234'
AND CustomerGroupMember.MemberID IS NULL
With the second condition (CustomerGroupMember.CustomerID = '1234') you are converting your LEFT JOIN to an INNER JOIN. All rows which have NULLs in the CustomerGroupMember columns will be filtered out, since NULL can not be equal to '1234'. You need to move that condition into the ON clause:
SELECT CustomerMember.* FROM CustomerMember
LEFT JOIN
CustomerGroupMember
ON CustomerMember.id = CustomerGroupMember.MemberID
AND CustomerGroupMember.CustomerID = '1234'
WHERE
CustomerMember.CustomerID = '1234'
AND CustomerGroupMember.MemberID IS NULL;
http://rextester.com/DLTQ86207
I need to perform a relatively easy to explain but (given my somewhat limited skills) hard to write SQL query.
Assume we have a table similar to this one:
exam_no | name | surname | result | date
---------+------+---------+--------+------------
1 | John | Doe | PASS | 2012-01-01
1 | Ryan | Smith | FAIL | 2012-01-02 <--
1 | Ann | Evans | PASS | 2012-01-03
1 | Mary | Lee | FAIL | 2012-01-04
... | ... | ... | ... | ...
2 | John | Doe | FAIL | 2012-02-01 <--
2 | Ryan | Smith | FAIL | 2012-02-02
2 | Ann | Evans | FAIL | 2012-02-03
2 | Mary | Lee | PASS | 2012-02-04
... | ... | ... | ... | ...
3 | John | Doe | FAIL | 2012-03-01
3 | Ryan | Smith | FAIL | 2012-03-02
3 | Ann | Evans | PASS | 2012-03-03
3 | Mary | Lee | FAIL | 2012-03-04 <--
Note that exam_no and date aren't necessarily related as one might expect from the kind of example I chose.
Now, the query that I need to do is as follows:
From the latest exam (exam_no = 3) find all the students that have failed (John Doe, Ryan Smith and Mary Lee).
For each of these students find the date of the first of the batch of consecutively failing exams. Another way to put it would be: for each of these students find the date of the first failing exam that comes after their last passing exam. (Look at the arrows in the table).
The resulting table should be something like this:
name | surname | date_since_failing
------+---------+--------------------
John | Doe | 2012-02-01
Ryan | Smith | 2012-01-02
Mary | Lee | 2012-03-04
How can I perform such a query?
Thank you for your time.
You can take advantage of the fact that if someone passed the most recent exam, then they have not failed any exams since their most recent pass: therefore the problem reduces to finding the first exam failed since the most recent pass:
SELECT name, surname, MIN(date) date_since_fail
FROM results NATURAL LEFT JOIN (
SELECT name, surname, MAX(date) lastpass
FROM results
WHERE result = 'PASS'
GROUP BY name, surname
) t
WHERE result = 'FAIL' AND date > IFNULL(lastpass,0)
GROUP BY name, surname
See it on sqlfiddle.
I should use a subquery that fetch last passed exam,
somthing like:
SET #query_exam_no = 3;
SELECT
name,
surname,
MIN(IF(date > last_passed_exam, date, NULL)) AS date_failing_since
FROM
exam_results
LEFT JOIN (
SELECT
name,
surname,
MAX(date) AS last_passed_exam
FROM exam_results
WHERE result = 'PASS'
GROUP BY name, surname
) AS last_passed_exams USING (name, surname)
HAVING
MAX(IF(exam_no = #query_exam_no, result, NULL)) = 'FAIL'
GROUP BY name, surname
This is enough:
select t.name,
t.surname,
t.date as 'date_since_failing'
from tablename t
inner join
(
select name,
surname,
max(exam_no) as exam_no
from tablename
group by name, surname
having min(result) = 'FAIL'
) aux on t.name = aux.name and t.surname = aux.surname and t.exam_no = aux.exam_no
The condition you are asking for is good for nothing you can do it without it. Here is the working example.
select
e.name,
e.sur_name,
min(e.date) as `LastFailed`
from exams as e
where e.result = 'Fail'
group by e.name
order by e.name
This produces this result
name sur_name LastFailed
Ann Evans 2012-02-03
John Doe 2012-02-01
Mary Lee 2012-01-04
Ryan Smith 2012-01-02
I have two tables:
Parent Information
Child Information
both are structured (almost) the same with a few nuances.
The table structures are as follows:
Parent
ID | First | Last | DOB | Address
-------------------------------------------------
1 | John | Doe | 1980-01-01 | 123 street
Dependents
ParentID | Type | First | Last | DOB
--------------------------------------------------
1 | Spouse | Jane | Doe | 1981-02-01
1 | Child | Mike | Doe | 1999-08-01
1 | Child | Zoe | Doe | 2002-04-01
I want to build a query (ideally single call with joins which returns the following:
Table Results
First | Last | Type | DOB | Address
----------------------------------------------------------------
John | Doe | Parent | 1980-01-01 | 123 Street
Jane | Doe | Spouse | 1981-02-01 | 123 Street
Mike | Doe | Child | 1999-08-01 | 123 street
Zoe | Doe | Child | 2002-04-01 | 123 Street
I suppose I could build the originally subquery with a LEFT JOIN on the dependents table (not all parents have dependents) then run a primary query which filters that table, however - when i do this, the query takes over a full minute to produce. (my tables change hundreds of times a day so keeping an index of the tables is not really an option as I'd have to rebuild constantly).
UPDATE
The more I think about it even the left join would not work necessarily because the parent information and first set of dependent information would reside on the same row from the subquery (and in turn make it 'impossible' for the primary query to filter the single row into multiple).
Any ideas?
SELECT t.First, t.Last, t.Type, t.DOB, t.Address
FROM (SELECT ID, First, Last, 'Parent' as Type, DOB, Address, 1 as SortKey
FROM Parent
UNION ALL
SELECT p.ID, d.First, d.Last, d.Type, d.DOB, p.Address,
CASE WHEN d.Type = 'Spouse' THEN 2 ELSE 3 END as SortKey
FROM Dependents d
INNER JOIN Parent p
ON d.ParentID = p.ID) t
ORDER BY t.ID, t.SortKey