mysql Select Query based on same table - mysql

i have a mysql table promotions main fields are
PromotionMaintenanceID (Primary)
PID
PromotionID
PromotionName
I have a special case where the PromotionID of one record (This will be the main Record) become the PID of some of some other records. I need to create a MySql statement to get record with PromotionMaintenanceID (of main Record) , PromotionID (of main Record) , PromotionName (of main Record) and PromotionID of all the records which has PID =PromotionID of the main record
PromotionMaintenanceID ,PID , PromotionID ,PromotionName
1 | T1 | 12 | Promo1
2 | 12 | 22 | PromoSub
3 | 12 | 33 | PromoSub2
I need my result like
PromotionMaintenanceID | PID | PromotionID | PromotionName | Sub PromoID
1 | T1 | 12 | Promo1 |22,33
Any one know how the query should be?

This query (SQLFiddle) should do what you want:
SELECT p1.PromotionMaintenanceID, p1.PID, p1.PromotionID, p1.PromotionName, GROUP_CONCAT(p2.PromotionID) AS `Sub PromoID`
FROM promotions p1
JOIN promotions p2
ON p2.PID = p1.PromotionID
GROUP BY p1.PromotionID
Output:
PromotionMaintenanceID PID PromotionID PromotionName Sub PromoID
1 T1 12 Promo1 33,22

For that you should be able to do a straight join (or double select depending on your favourite way)
SELECT
a.PromotionID,
a.MaintenanceId,
a.PromotionName,
GROUP_CONCAT(b.PID) as SubIds
FROM
PromotionTable a
LEFT JOIN
PromotionTable b
ON
a.PromotionID = b.PID
//ADD AND's here with a.(column) = b.PID if you absolutely need all the ID's for each column to link up
GROUP BY
a.PromotionID, a.MaintenanceID, a.PromotionName

Related

Exclude based on sub-table's value

Consider the table Audit, and AuditStatus.
Where auditId in AuditStatus is a foreign key, mapping the pk of table Audit.
table Audit
id | auditName |
1 | test |
2 | fooTest |
3 | barTest |
table AuditStatus
id | auditId | status |
11 | 1 | started |
12 | 1 | completed |
13 | 2 | started |
How can I only select the entries of table Audit, which do not have a AuditStatus.status 'completed'.
The result in this case would be:
2 | fooTest |
3 | barTest |
I have updated the question and the result example, to make it more clear. The relation Audit -> AuditStatus is a one to many. And I want to exclude the Audits which have a refrerence to an AuditStatus with status 'complete'
You should post your attempted query into your question, not as comment. Anyway, your query is actually correct but your condition is incorrect. Let's inspect your query:
SELECT *
FROM Audit a
WHERE NOT EXISTS (
SELECT s.auditId
FROM AuditStatus s
WHERE a.id = s.auditId AND s.status != 'completed'
);
You're suppose to find where the status is not complete, which is true in the subquery but the problem here is you're doing a NOT EXISTS which negates the correct result you're getting from the subquery.
This is what your subquery will return:
id
auditId
status
11
1
started
13
2
started
Then when your NOT EXIST negates the auditId being returned, you'll get this result instead:
id
auditName
3
barTest
Which is correct according to the condition; auditId=3 wasn't returned in the subquery. What you need to modify is actually very simple, you just need to make the subquery return status = completed as true then NOT EXISTS will return any Audit.Id that doesn't match with the correlated subquery. Therefore:
SELECT *
FROM Audit a
WHERE NOT EXISTS (
SELECT s.auditId
FROM AuditStatus s
WHERE a.id = s.auditId AND s.status = 'completed'
);
And that's it, you should be getting the result you looking for.
Demo fiddle
maybe use a left join like below which only joins on Audit Status on Fk as well as status constraint
SELECT *
FROM Audit A
LEFT JOIN AuditStatus ATS
ON A.id= ATS.auditId AND ATS.Status ='completed'
WHERE AS.auditId IS NULL

How to find all the opposite combinations between two columns in SQL

I am making a web dating app that needs to match users and let them chat with each other.
I want to figure out how to find all the matches for a particular user.
Right now I have a table called follows that has 2 columns.
UserID | MatchUserID
--------------------
1 | 2
2 | 1
1 | 3
1 | 4
1 | 5
4 | 1
5 | 4
The idea is that for two users to match they need to follow one another. The table above shows which user follows which.
Assuming that the user who is currently logged on is UserID = 1.
I need a query that will return from the MatchUserID table the following results:
2, 4
In a way, I am looking to find all the opposite combinations between the two columns.
This is the code I use to create the table.
CREATE TABLE Match
(
UserID INT NOT NULL,
MatchUserID INT NOT NULL,
PRIMARY KEY (UserID, MatchUserID)
);
You can do it with a self join:
select m.MatchUserID
from `Match` m inner join `Match` mm
on mm.MatchUserID = m.UserId
where
m.UserId = 1
and
m.MatchUserID = mm.UserId
See the demo.
Results:
| MatchUserID |
| ----------- |
| 2 |
| 4 |
The simplest way possibly is to use EXISTS and a correlated subquery that searches for the other match.
SELECT t1.matchuserid
FROM elbat t1
WHERE t1.userid = 1
AND EXISTS (SELECT *
FROM elbat t2
WHERE t2.matchuserid = t1.userid
AND t2.userid = t1.matchuserid);

Select rows which are not present in other table in mysql [duplicate]

I have 2 tables - reservation:
id | some_other_column
----+------------------
1 | value
2 | value
3 | value
And second table - reservation_log:
id | reservation_id | change_type
----+----------------+-------------
1 | 1 | create
2 | 2 | create
3 | 3 | create
4 | 1 | cancel
5 | 2 | cancel
I need to select only reservations NOT cancelled (it is only ID 3 in this example).
I can easily select cancelled with a simple WHERE change_type = cancel condition, but I'm struggling with NOT cancelled, since the simple WHERE doesn't work here.
SELECT *
FROM reservation
WHERE id NOT IN (select reservation_id
FROM reservation_log
WHERE change_type = 'cancel')
OR:
SELECT r.*
FROM reservation r
LEFT JOIN reservation_log l ON r.id = l.reservation_id AND l.change_type = 'cancel'
WHERE l.id IS NULL
The first version is more intuitive, but I think the second version usually gets better performance (assuming you have indexes on the columns used in the join).
The second version works because LEFT JOIN returns a row for all rows in the first table. When the ON condition succeeds, those rows will include the columns from the second table, just like INNER JOIN. When the condition fails, the returned row will contain NULL for all the columns in the second table. The WHERE l.id IS NULL test then matches those rows, so it finds all the rows that don't have a match between the tables.
Just for completeness (and I honestly believe it fits better), I encourage you to use a simple NOT EXISTS.
SELECT * FROM reservation R
WHERE NOT EXISTS (
SELECT 1 FROM reservation_log
WHERE reservation_id = R.id
AND change_type = 'cancel'
);

mysql using limit in a left join not working properly

I have two tables looking like this
Patient (table 1)
id | name
------------
1 | robel
2 | dave
Patient_followup (table 2)
id | Patient_id | date_created
-----------------------
1 | ---- 1 -- | 01/01/2015
2 | -----1 -- | 01/07/2016
I want to display all the patients with their perspective latest followup data. so i tried using this query
Select * from patient
left join Patient_followup pf on pf.Patient_id = patient.id
order by pf.date_created
Limit 1
but this is giving me only the first patient robel. i tryed removing the limit and its giving me two records of robel and one record of dave because robel has two followup data. so what should i do to get only one record of each patient ?
Try this:
Select
*
from
patient
left join
(SELECT
id as pf_id,
MAX(date_created) as latest_followup_date,
Patient_id
FROM
Patient_followup
GROUP BY
Patient_id) as pf
ON pf.Patient_id = patient.id
As mentioned by anton in the first comment, you need to use aggregation to get one record per patient.
Select patient.*,MAX(pf.date_created) as followupdate,group_concat(pf.date_created) from patient
left join Patient_followup pf on pf.Patient_id = p.patient.id
group by patient.id
order by pf.date_created
Here, you will get your values comma separated.
1) "Limit 1" will only return the first result. Typically this is used if the query will result in a very large result set and you only want the first few results.
Ex:
"LIMIT 30" will show the first 30 rows of the query.
2) I would change to setup of the tables so the query is smoother. Right now, you create a new line for each follow-up date even if the patient is already created. You could add another column in the table named "FollowUpDate". That way each patient record has the table id, patient id, creation date and followup date in the same row. That way, each patient has only one row.
EX:
Patient (table 1)
id | name | created_date | next_followup_date |
1 | Robel | 01/01/2015 | 01/01/2016 |
2 | Dave |[created_date]| [next_follup_date] |
Patient_followup (table 2)
id | Patient_id | date_created | followUpDate |
1 | 1 | 01/01/2015 | 06/01/2016 | // example date
2 | 1 | 01/01/2015 | 01/01/2016 |
3 | 2 |[date created]| [FollowUpDate] |
3) Change query to:
Use this select statement to get all patient records.
Select * from patient
left join Patient_followup pf on pf.Patient_id = patient.id
order by pf.Patient_id
Use this select statement to get the specific patient record information.
Select * from patient
inner join Patient_followup pf on pf.Patient_id = patient.id
where patient.id = 1 //to get robel. Edit this line as necessary, perhaps by user input...
order by pf.followUpDate
NOTE: When you insert a new record in Patient_followup, make sure you update Patient.next_followup_date.
I hope this helps!

MySql: Join on 3 tables [duplicate]

I have 2 tables - reservation:
id | some_other_column
----+------------------
1 | value
2 | value
3 | value
And second table - reservation_log:
id | reservation_id | change_type
----+----------------+-------------
1 | 1 | create
2 | 2 | create
3 | 3 | create
4 | 1 | cancel
5 | 2 | cancel
I need to select only reservations NOT cancelled (it is only ID 3 in this example).
I can easily select cancelled with a simple WHERE change_type = cancel condition, but I'm struggling with NOT cancelled, since the simple WHERE doesn't work here.
SELECT *
FROM reservation
WHERE id NOT IN (select reservation_id
FROM reservation_log
WHERE change_type = 'cancel')
OR:
SELECT r.*
FROM reservation r
LEFT JOIN reservation_log l ON r.id = l.reservation_id AND l.change_type = 'cancel'
WHERE l.id IS NULL
The first version is more intuitive, but I think the second version usually gets better performance (assuming you have indexes on the columns used in the join).
The second version works because LEFT JOIN returns a row for all rows in the first table. When the ON condition succeeds, those rows will include the columns from the second table, just like INNER JOIN. When the condition fails, the returned row will contain NULL for all the columns in the second table. The WHERE l.id IS NULL test then matches those rows, so it finds all the rows that don't have a match between the tables.
Just for completeness (and I honestly believe it fits better), I encourage you to use a simple NOT EXISTS.
SELECT * FROM reservation R
WHERE NOT EXISTS (
SELECT 1 FROM reservation_log
WHERE reservation_id = R.id
AND change_type = 'cancel'
);