How to use an if condition in a query? - mysql

Suppose I want select the matches with the MAX gameweek if the status of all matches is setted to 3, or the matches with MIN gameweek how can I do this?
Data sample
id | status | gameweek | round_id
1 3 3 1
2 3 3 1
3 1 3 1
4 1 4 1
5 1 4 1
6 1 4 1
the final result should be: 1, 2, 3 because not all the match has played.
I was able to setup a query for MAX:
SELECT MAX(gameweek) FROM `match` m WHERE round_id = 1 AND m.status = 3
but I have some difficult to implement an IF condition, someone could help me?
Thanks.
UPDATE
In the solution proposed by the users I noticed that I doesn't explain well a particular situation: if all the matches of a round doesn't have the status 3, the query should return the MIN(gameweek) of the round_id specified.

If I get this right, you could use a CASE. If a record with a status other than 3 exists return the minumum gameweek, else the maximum. Compare the result to the gameweek.
SELECT `m1`.*
FROM `match` `m1`
WHERE `m1`.`round_id` = 1
AND `m1`.`gameweek` = CASE
WHEN EXISTS (SELECT *
FROM `match` `m2`
WHERE `m2`.`round_id` = `m1`.`round_id`
AND `m2`.`status` <> 3) THEN
(SELECT min(`m3`.`gameweek`)
FROM `match` `m3`
WHERE `m3`.`round_id` = `m1`.`round_id`)
ELSE
(SELECT max(`m4`.`gameweek`)
FROM `match` `m4`
WHERE `m4`.`round_id` = `m1`.`round_id`)
END;
I'm not sure if you wanted to limit it to a certain round_id. It's in your query but not in the text. If you don't want it, remove all the conditions related to round_id.
Edit:
To use the maximum gameweek if not all status of a round are equal to 3 and the minimum gameweek otherwise you can check if the minimum of the status equals the maximum (i.e. all status are the same) and if it is equal to 3.
SELECT `m1`.*
FROM `match` `m1`
WHERE `m1`.`round_id` = 1
AND `m1`.`gameweek` = CASE
WHEN EXISTS (SELECT min(`m2`.`status`)
FROM `match` `m2`
WHERE `m2`.`round_id` = `m1`.`round_id`
HAVING min(`m2`.`status`) <> max(`m2`.`status`)
OR min(`m2`.`status`) <> 3) THEN
(SELECT min(`m3`.`gameweek`)
FROM `match` `m3`
WHERE `m3`.`round_id` = `m1`.`round_id`)
ELSE
(SELECT max(`m4`.`gameweek`)
FROM `match` `m4`
WHERE `m4`.`round_id` = `m1`.`round_id`)
END;

Assuming there can be more than one round_id:
SELECT *
FROM `match` m
WHERE (gameweek, round_id ) =
(
SELECT MAX(gameweek),round_id
FROM `match` m
WHERE round_id = 1 AND m.status = 3
GROUP BY round_id
)
DBFiddle DEMO

ok, simpler than I imagined, I discovered that I can achieve this target using the COALESCE operator, so:
m.gameweek = (SELECT COALESCE(MIN(
CASE WHEN m2.status < 3
THEN m2.gameweek END),
MAX(m2.gameweek))
FROM `match` m2
WHERE m2.round_id = m.round_id)

Related

check for two values in a table

I have a simple table where I store some data related to a user.
id
id_user
id_func
1
1
1
2
1
2
3
2
1
I want to check if a specific user has two specific functions (1 AND 2) assigned. So If I check for user 1 the query will return true. For user 2 it will return false.
The query I have so far is:
SELECT IF(
"SELECT id_user FROM funz_abilitate WHERE id_func=1 AND id_func=2 AND id_user=1",
true,
false
) as verifica
FROM funz_abilitate
WHERE id_user=1
but this is returning for user 1:
verifica
0
0
and for user 2:
verifica
0
While I'd like just to get a boolean true/false. So if I select user 1 it returns true, if I select user 2 it returns false
How to fix it?
You can do it with aggregation:
SELECT COUNT(*) = 2 AS verifica
FROM funz_abilitate
WHERE id_user = 1 AND id_func IN (1, 2)
or:
SELECT COUNT(DISTINCT id_func) = 2 AS verifica
FROM funz_abilitate
WHERE id_user = 1 AND id_func IN (1, 2)
if there are duplicate id_funcs for each user.
In MySql 8.0+ I would use a CTE which returns the id_funcs I search for, so there is no need to write how many they are:
WITH cte(id_func) AS (VALUES ROW(1), ROW(2))
SELECT COUNT(*) = (SELECT COUNT(*) FROM cte) AS verifica
FROM funz_abilitate
WHERE id_user = 1 AND id_func IN (SELECT id_func FROM cte)
See the demo.

SQL - Get rows where all columns are in a list that have the same value in another column

I have a database as follows:
drinks_id ingredients_master_id
1 2
1 3
1 4
2 2
2 4
3 5
And I'm looking for a query where I can give it a list of ingredients_master_id such as 2,4 and it returns all of the drinks_id's that have exactly 2,4.
So in this case if I gave it ingredients_master_id 2,4,5 it would return drinks_id 2 and 3. And if I gave it 5 it would return drinks_id 3.
This is what I have so far but it's currently not displaying the correct info.
SELECT DISTINCT drinks.id
FROM drinks
WHERE drinks.id NOT IN
(
SELECT drinks.id
FROM ingredients
JOIN drinks ON ingredients.drinks_id = drinks.id
WHERE ingredients.ingredients_master_id NOT IN
(
2,3,4,5,6
)
);
You probably achieve the desired result using not exists as follows:
Select t.*
From your_table t
Where t.ingredients_master_id in (2,4,5)
And not exists
(Select 1 from your_table tt
Where tt.drinks_id = t.drinks_id
And tt.ingredients_master_id not in (2,4,5))
And I'm looking for a query where I can give it a list of ingredients_master_id such as 2,4 and it returns all of the drinks_id's that have exactly 2,4.
You can use group by and having:
select drinks_id
from t
group by drinks_id
having sum( ingredients_master_id in (2, 4) ) = 2;
The "= 2" is the size of the list, so you need to adjust that for different lists.
You can use as below:
select drink_id
from (
select drink_id,listagg(ingredients_master_id,',') within group( order by ingredients_master_id) val from <Table> group by drink_id)
where case
when instr('**2,4,5**',val)> 0
Then 'Y'
else 'N'
end = 'Y';

MySQL Putting in duplicate id's

I'm trying to run an UPDATE query that uses the same table and I'm getting an error saying "1093 - Table 'queues_monitor_times' is specified twice, both as a target for 'UPDATE' and as a separate source for data".
UPDATE queues_monitor_times
SET queue_id = IF((
SELECT id
FROM queues_monitor_times
INNER JOIN(
SELECT pcc_group, pcc, gds, queue, category, `name`
FROM queues_monitor_times
GROUP BY pcc_group, pcc, gds, queue, category, `name`
HAVING COUNT(id) > 1
)temp ON queues_monitor_times.pcc_group = temp.pcc_group AND
queues_monitor_times.pcc = temp.pcc AND
queues_monitor_times.gds = temp.gds AND
queues_monitor_times.queue = temp.queue AND
queues_monitor_times.category = temp.category AND
queues_monitor_times.`name` = temp.`name`), 1, id)
WHERE
id NOT IN (SELECT MIN(id) FROM queues_old GROUP BY pcc_group, pcc, gds, queue, category, `name`);
I ran the select query by itself and it showed all the rows that were duplicates, which is what I wanted. I want queue_id to be set with the lowest duplicate row's id if the row is a duplicate or the row id if it is not.
Example of what the query should do:
id dup_id name value
1 1 John 13
2 2 John 13
3 3 Sally 6
4 4 Frank 4
5 5 Sally 6
And after running the query it will turn into
id dup_id name value
1 1 John 13
2 1 John 13
3 3 Sally 6
4 4 Frank 4
5 3 Sally 6
Please advise and thank you for your help.
I was able to solve my problem. Thanks for all your help!
UPDATE queues_monitor_times
SET queue_id = (
SELECT
id
FROM
queues_old
WHERE
queues_old.pcc_group = queues_monitor_times.pcc_group
AND queues_old.pcc = queues_monitor_times.pcc
AND queues_old.gds = queues_monitor_times.gds
AND queues_old.queue = queues_monitor_times.queue
AND queues_old.category = queues_monitor_times.category
AND queues_old.`name` = queues_monitor_times.`name`
GROUP BY pcc_group, pcc, gds, queue, category, `name`
HAVING COUNT(id) > 1)
WHERE
id NOT IN (SELECT MIN(id) FROM queues_old GROUP BY pcc_group, pcc, gds, queue, category, `name`);
For those that will want to use this in the future, queues_monitor_times table and queues_old table have the exact same data.

Two tables with all rows including allocated based on id

Im trying to make this generic as it might help others in the future.
For an example i have two tables one with books and the other is the user with which book they have read, So ide like to display all the books and include a temporary column value as a (yes / no or 0/1), i have tried a join but the ( WHERE user_id = 3) clause only then return the one row and not all the other rows.
book.book_id book.book_name
10 Book 1
11 Book 2
12 Book 3
-------------
user.user_id user.book_id
1 10
1 12
2 11
3 12
Desired output:
user_id book_id temp_col_read
3 10 0 // yes, on or null
3 12 1 // or yes
3 13 0
This is actually quite simple. In the event that a user could read a book multiple times, I would go with exists in the select:
select b.*,
(case when exists (select 1
from reads r
where r.book_id = b.book_id and r.user_id = 3
)
then 1 else 0
end) as user_read_book
from book b;
In MySQL, the case is not strictly necessary because a boolean expression is treated as 0/1 in many contexts:
select b.*,
(exists (select 1
from reads r
where r.book_id = b.book_id and r.user_id = 3
) as user_read_book
from book b;
You can use a left join and where the join is unresolved then is not read
select
user.user_id
, book.book_id
, case
when book.book_id is null
then 'NO' else 'YES'
end as temp_col_read
from book
left join user on user.book_id = book.book_id

Conditional condition in ON clause

I am trying to apply a conditional condition inside ON clause of a LEFT JOIN. What I am trying to achieve is somewhat like this:
Pseudo Code
SELECT * FROM item AS i
LEFT JOIN sales AS s ON i.sku = s.item_no
AND (some condition)
AND (
IF (s.type = 0 AND s.code = 'me')
ELSEIF (s.type = 1 AND s.code = 'my-group')
ELSEIF (s.type = 2)
)
I want the query to return the row, if it matches any one of the conditions (Edit: and if it matches one, should omit the rest for the same item).
Sample Data
Sales
item_no | type | code | price
1 0 me 10
1 1 my-group 12
1 2 14
2 1 my-group 20
2 2 22
3 2 30
4 0 not-me 40
I want the query to return
item_no | type | code | price
1 0 me 10
2 1 my-group 20
3 2 30
Edit: The sales is table is used to apply special prices for individual users, user groups, and/or all users.
if type = 0, code contains username. (for a single user)
if type = 1, code contains user-group. (for users in a group)
if type = 2, code contains empty-string (for all users).
Use the following SQL (assumed, the the table sales has a unique id field as usual in yii):
SELECT * FROM item AS i
LEFT JOIN sales AS s ON i.sku = s.item_no
AND id = (
SELECT id FROM sales
WHERE item_no = i.sku
AND (type = 0 AND code = 'me' OR
type = 1 AND code = 'my-group' OR
type = 2)
ORDER BY type
LIMIT 1
)
Try following -
SELECT *,SUBSTRING_INDEX(GROUP_CONCAT(s.type ORDER BY s.type),','1) AS `type`, SUBSTRING_INDEX(GROUP_CONCAT(s.code ORDER BY s.type),','1) AS `code`,SUBSTRING_INDEX(GROUP_CONCAT(s.price ORDER BY s.type),','1) AS `price`
FROM item AS i
LEFT JOIN sales AS s
ON i.sku = s.item_no AND (SOME CONDITION)
GROUP BY i.sku