Select rows with show flag but based on another table - mysql

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

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

Django Intersection on Mysql database

My table with this values:
id, product, category
1, A, 1
2, B, 1
3, B, 2
4, C, 1
5, C, 2
6, D, 2
7, E, 2
8, E, 3
9, F, 3
10, F, 4
I need to select only products matching category (1 OR 2) AND category (3 OR 4) in Django. Expected result is only product: E
I have error "intersections are not supported in mysql" How i can achieve this using Q() ?
This query return no result but work.
main_query = Q()
main_query &= Q(category__in=[1,2])
main_query &= Q(category__in=[3,4])
models.Table.objects.filter(main_query)
SELECT product
FROM yourTable
GROUP BY product
HAVING COUNT(CASE WHEN category IN (1,2) THEN 1 END) > 0
AND COUNT(CASE WHEN category IN (3,4) THEN 1 END) > 0
Here is one option with inline tables.
SELECT a.* FROM
(SELECT * FROM tab WHERE category IN (1,2)) AS a,
(SELECT * FROM tab WHERE category IN (3,4)) AS b
WHERE a.product = b.product ;
Demo here
Another option using WITH Clause as following
WITH cat_1_2 AS (
SELECT * FROM tab WHERE category IN (1,2)
),
cat_3_4 AS (
SELECT * FROM tab WHERE category IN (3,4)
)
SELECT a.* FROM cat_1_2 AS a, cat_3_4 AS b
WHERE a.product = b.product ;
Demo here
The AND condition is applied to each single row so you have not the result you expected ..but for select the rows associated to the category you have in IN clause.
You could try using a couple of inner join on subquery
SELECT t.*
FROM table t
INNER JOIN (SELECT 1 cat
UNION
SELECT 2) t1 ON t1.cat = t.category
INNER JOIN (SELECT 3 cat
UNION
SELECT 4) t2 ON t2.cat = t.category
I learned from #RajmondNijland that INTERSECT doesn't exist in MySQL. Thanks him. So, You can use the following query with IN operator to link the subquery with the main:
SELECT product
FROM table1
WHERE category IN (1,2)
AND product IN ( SELECT product FROM table1 WHERE category IN (3,4) );
product
-------
E

(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

SQL order by multiple condition

I have a table with 'name','status'-fail or success,'counts'- 1 to 100. I want to order it in such a way that names of only 'fail' should show on top together, then same name with fail and success together, then names with only success together.
Can we do it sql query language ?
Thank you.
Ok, this should work on most RDBMS:
SELECT A.*
FROM YourTable A
INNER JOIN (SELECT name,
COUNT(DISTINCT status) StatusCount,
MIN(status) MinStatus
FROM YourTable
GROUP BY name) B
ON A.name = B.name
ORDER BY CASE WHEN StatusCount = 1 AND MinStatus = 'fail' THEN 1
WHEN StatusCount = 2 THEN 2
ELSE 3 END, A.name, A.status
If it is MySQL
select *, 0 as o
from t
union all
select *, 1 as o
from t
order by
o = 1 and status != 'fail', o != 1, status = fail

Select Most Recent Items with dup values

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