Select Most Recent Items with dup values - mysql

Given the following information, how can I select the most recent line items (based on time_entered) on unique params and cron_action_id pairs that haven't been executed?
cron_schedule
For example, ids 1, 2, and 4 have the same params and cron_action_id, so I need not select all 3, just id 4. Same principle for id 3/5 and 7/8.
I can only get so far as
SELECT *
FROM cron_schedule cs
INNER JOIN cron_actions ca
ON cs.cron_action_id = ca.cron_action_id
WHERE time_executed = 0
-- GROUP BY (params, cron_action_id) ?
This should return rows with id 4, 5, 6, and 8
Thanks

SELECT t1.*
FROM cron_schedule t1
INNER JOIN (SELECT params,
cs.cron_action_id,
Max(time_entered) AS time_entered
FROM cron_schedule cs
INNER JOIN cron_actions ca
ON cs.cron_action_id = ca.cron_action_id
WHERE time_executed = 0
GROUP BY params, cron_action_id) AS t2
ON t1.params = t2.params
AND t1.cron_action_id = t2.cron_action_id
AND t1.time_entered = t2.time_entered
INNER JOIN cron_actions ca2
ON t1.cron_action_id = ca2.cron_action_id
WHERE t1.time_executed = 0

Not tested, but this basic idea should work:
SELECT *
FROM
cron_schedule outer_cron_schedule JOIN cron_actions
WHERE
time_entered = (
SELECT MAX(time_entered)
FROM cron_schedule inner_cron_schedule
WHERE
outer_cron_schedule.id = inner_cron_schedule.id
GROUP BY
params, cron_action_id
)
AND time_executed = 0
Give it a try

Related

Matching Exactly all values in IN clause

I am searching for the solution for this problem for hours now with no luck. I have a Workouts table as below. Each item in the workout table can have multiple target muscles, which are listed in the Target Muscles table.
Workouts table:
id
1
2
Target Muscles table:
id
muscle_key
workout_id
1
a
1
2
b
1
3
c
1
4
a
2
5
b
2
I need to fetch all items in the workouts table which match EXACTLY ALL target muscles keys in the given set, not less and not more. For example, given the set of muscle keys:
(a,b)
The desired output would be:
id
2
The row for workout id = 1 should NOT be selected since it contains an extra muscle key (c).
I am using the following query:
SELECT id
FROM workouts
LEFT JOIN target_muscles ON workouts.id = target_muscles.workout_id
WHERE target_muscles.muscle_key IN (a,b)
GROUP BY workouts.id
HAVING COUNT(DISTINCT target_muscles.muscle_key) = 2
The above query is also returning the workout id = 1, instead of only 2. How can I achieve this?
Any help is appreciated.
Skip the WHERE clause. Use HAVING to make sure exactly a and b are there.
SELECT workouts.id
FROM workouts
JOIN target_muscles ON workouts.id = target_muscles.workout_id
GROUP BY workouts.id
HAVING COUNT(DISTINCT target_muscles.muscle_key) =
COUNT(DISTINCT CASE WHEN target_muscles.muscle_key IN (a,b)
THEN target_muscles.muscle_key END)
AND COUNT(DISTINCT target_muscles.muscle_key) = 2
Can also be done as:
SELECT workouts.id
FROM workouts
JOIN target_muscles ON workouts.id = target_muscles.workout_id
GROUP BY workouts.id
HAVING MIN(target_muscles.muscle_key) = 'a'
AND MAX(target_muscles.muscle_key) = 'b'
AND COUNT(DISTINCT target_muscles.muscle_key) = 2
Or, perhaps less performant:
SELECT workouts.id
FROM workouts
JOIN (SELECT workout_id FROM target_muscles WHERE muscle_key = 'a'
INTERSECT
SELECT workout_id FROM target_muscles WHERE muscle_key = 'b'
EXCEPT
SELECT workout_id FROM target_muscles WHERE muscle_key NOT IN ('a', 'b')) dt
ON workouts.id = dt.workout_id
You can remove the filtering clause and use two conditions:
count of non-(a,b) muscle_keys = 0
distinct count of (a,b) muscle_keys = 2
SELECT w.id
FROM workouts w
LEFT JOIN target_muscles ts ON w.id = ts.workout_id
GROUP BY w.id
HAVING COUNT(CASE WHEN ts.muscle_key NOT IN ('a', 'b') THEN w.id END) = 0
AND COUNT(DISTINCT CASE WHEN ts.muscle_key IN ('a', 'b') THEN ts.muscle_key END) = 2
Check the demo here.
This is an other way to do it using inner join
select distinct s.id
from (
select w.id
from workouts w
inner join targets t on t.workout_id = w.id
group by workout_id
having count(1) = 2
) as s
inner join targets t on t.workout_id = s.id and t.muscle_key in ('a', 'b');
You can Try it from here : https://dbfiddle.uk/nPTQlhqT

How to select distinct max value from multiple join table MySQL

This is my current query for selecting data:
select a.No_Registrasi, a.Nama_CTKI, b.Nama_Negara, c.ID_Rad, d.ID_Lab
FROM tb_registrasi a
JOIN tb_negara_tujuan b
ON a.ID_Negara = b.ID_Negara
JOIN tb_radiologi c
ON a.No_Registrasi = c.No_Registrasi
JOIN tb_laboratorium d
ON a.No_Registrasi = d.No_Registrasi
And here's the result:
How do i distinct those ID_Rad and ID_Lab and I need the max value from each ID_Rad and ID_Lab so it will be like this:
Use GROUP BY and MAX, try this;)
select a.No_Registrasi, a.Nama_CTKI, b.Nama_Negara, CONCAT('RA-', MAX(substring(c.ID_Rad, 4) + 0)) AS ID_Rad, CONCAT('Lab-',MAX(substring(d.ID_Lab, 5) + 0)) AS Id_Lab
FROM tb_registrasi a
JOIN tb_negara_tujuan b
ON a.ID_Negara = b.ID_Negara
JOIN tb_radiologi c
ON a.No_Registrasi = c.No_Registrasi
JOIN tb_laboratorium d
ON a.No_Registrasi = d.No_Registrasi
GROUP BY a.No_Registrasi, a.Nama_CTKI, b.Nama_Negara

Select rows with show flag but based on another table

Can someone help me about this problem.
I have 2 tables:
TASKS:(id,once)
SAVED_tasks (id, task_id)
table where i save tasks..
I need to show all tasks but NOT if the task have value is 1 and if is already inserted in SAVED_tasks table..
EXAMPLE:
tasks:
id, name, once
1, task1, 0
2, task2, 1
3, task3, 0
4, task4, 1
saved_tasks:
id, task_id
1, 1
2, 2
3, 3
4, 4
I need result:
1, task1
3, task3
SELECT TASK.id, SAVED_tasks.task_id FROM TASKS Inner join SAVED_tasks ON TASK.id = SAVED_tasks.id
AND TASK.once > 1
Try this:
SELECT t.id, t.once
FROM TASKS t
LEFT JOIN SAVED_tasks st ON t.id = st.task_id
WHERE (t.once != 1 OR (t.once = 1 AND st.id IS NULL));
OR
SELECT t.id, t.once
FROM TASKS t
LEFT JOIN SAVED_tasks st ON t.id = st.task_id
WHERE NOT(t.once = 1 AND st.id IS NULL);
This ought to do it:
Select * from TASKS
Where TASKS.id Not In (Select task_id from SAVED_TASKS)
and TASK.once != 1
Try joining two tables if you need values if you have data in your SAVED_task table and once != 1 like below:
SELECT t.id
FROM TASKS t INNER JOIN SAVED_tasks st
ON t.id = st.id
WHERE t.once != 1

(My)SQL JOIN - get teams with exactly specified members

Assume tables
team: id, title
team_user: id_team, id_user
I'd like to select teams with just and only specified members. In this example I want team(s) where the only users are those with id 1 and 5, noone else. I came up with this SQL, but it seems to be a little overkill for such simple task.
SELECT team.*, COUNT(`team_user`.id_user) AS cnt
FROM `team`
JOIN `team_user` user0 ON `user0`.id_team = `team`.id AND `user0`.id_user = 1
JOIN `team_user` user1 ON `user1`.id_team = `team`.id AND `user1`.id_user = 5
JOIN `team_user` ON `team_user`.id_team = `team`.id
GROUP BY `team`.id
HAVING cnt = 2
EDIT: Thank you all for your help. If you want to actually try your ideas, you can use example database structure and data found here: http://down.lipe.cz/team_members.sql
How about
SELECT *
FROM team t
JOIN team_user tu ON (tu.id_team = t.id)
GROUP BY t.id
HAVING (SUM(tu.id_user IN (1,5)) = 2) AND (SUM(tu.id_user NOT IN (1,5)) = 0)
I'm assuming a unique index on team_user(id_team, id_user).
You can use
SELECT
DISTINCT id,
COUNT(tu.id_user) as cnt
FROM
team t
JOIN team_user tu ON ( tu.id_team = t.id )
GROUP BY
t.id
HAVING
count(tu.user_id) = count( CASE WHEN tu.user_id = 1 or tu.user_id = 5 THEN 1 ELSE 0 END )
AND cnt = 2
Not sure why you'd need the cnt = 2 condition, the query would get only those teams where all of users having the ID of either 1 or 5
Try This
SELECT team.*, COUNT(`team_user`.id_user) AS cnt FROM `team`
JOIN `team_user` ON `team_user`.id_team = `team`.id
where `team_user`.id_user IN (1,5)
GROUP BY `team`.id
HAVING cnt = 2

IN Clause selects all variables

When I run this procedure:
SELECT * FROM photo
LEFT JOIN photo_selectedTags
ON photo.COUNTER = photo_selectedTags.PHOTO_COUNTER
WHERE photo_selectedTags.TAGS_COUNTER IN (6,192)
It retrieves rows where TAGS_COUNTER = 6 OR 192
How do I retrieve the rows from 'photo' where TAGS_COUNTER = 6 AND 192?
Corrected: the IN for ALL
The basic idea is this:
SELECT PHOTO_COUNTER
FROM photo_selectedTags
WHERE TAGS_COUNTER in (6, 192)
group by PHOTO_COUNTER
having count(distinct TAGS_COUNTER) = 2 --2 matches # of items in IN clause
You can then do this to get the rest of the columns:
SELECT *
from PHOTO_COUNTER
LEFT JOIN photo_selectedTags
ON photo.COUNTER = photo_selectedTags.PHOTO_COUNTER
where photo.COUNTER in (
SELECT PHOTO_COUNTER
FROM photo_selectedTags
WHERE TAGS_COUNTER in (6,192)
group by PHOTO_COUNTER
having count(distinct TAGS_COUNTER) = 2 --2 matches # of items in IN clause
) a
Edit
Now that i understand what you want and DB structure, try with this:
SELECT * FROM photo
LEFT JOIN photo_selectedTags
ON photo.COUNTER = photo_selectedTags.PHOTO_COUNTER
WHERE photo_selectedTags.TAGS_COUNTER = 6 AND photo_id IN
(SELECT photo_id FROM photoSELECT * FROM photo
LEFT JOIN photo_selectedTags
ON photo.COUNTER = photo_selectedTags.PHOTO_COUNTER
WHERE photo_selectedTags.TAGS_COUNTER = 192)
I don't know if photo_id is an actual field of your table, but try to adapt it to your structure
Obviously in the first SELECT don't insert PHOTO_COUNTER because i'll be always the same value and it haven't much sense.
I would propose to use 2 joins
SELECT *
FROM photo
JOIN photo_selectedTags as photo_selectedTags6 -- this join restricts to 'photo.COUNTER' whic have TAGS_COUNTER = 6
ON photo.COUNTER = photo_selectedTags6.PHOTO_COUNTER
AND photo_selectedTags6.TAGS_COUNTER = 6
JOIN photo_selectedTags as photo_selectedTags192 -- this join restricts to 'photo.COUNTER' whic have TAGS_COUNTER = 192
ON photo.COUNTER = photo_selectedTags192.PHOTO_COUNTER
AND photo_selectedTags192.TAGS_COUNTER = 192
Also would be possible to achive it with analytical functions (if supported by your DB)
-- This one works on teradata. Something similar should work on oracle. Don't know about others
SELECT *
FROM photo
LEFT JOIN photo_selectedTags
ON photo.COUNTER = photo_selectedTags.PHOTO_COUNTER
QUALIFY max(case when photo_selectedTags.TAGS_COUNTER = 6 then 1 end) over (partition by photo.COUNTER) = 1
AND max(case when photo_selectedTags.TAGS_COUNTER = 192 then 1 end) over (partition by photo.COUNTER) = 1
If you have many values in the list (in addition to 192,6), then this might be possible solution
SELECT *
FROM photo
JOIN
(
SELECT PHOTO_COUNTER, count(distinct TAGS_COUNTER) cnt
FROM photo_selectedTags
WHERE TAGS_COUNTER in (192,6)
HAVING cnt = 2 -- adjust this according to the number of different values
) as pht
ON photo.COUNTER = pht.PHOTO_COUNTER
In subquery only PHOTO_COUNTERs are left which have both (192 and 6), then this is joined