Select Case inside another Select - mysql

I’m trying to apply a CASE to a column that I create.
But the problem is that I have a select inside another select
And I’m using the value of that subquery to make the select case
How should I do this?
SELECT
gc.IDGastosComunes,
v.IDPropiedad,
v.Depto,
v.NombreDueno,
(SELECT u2.IDCategoria
FROM usuarios_tipos u2
WHERE u2.IDUsuario = v.IDDueno AND
u2.IDTipo = 10) AS gc.IDCategoria, <-- This return an int -> 1, 2 or 3
CASE
WHEN IDCategoria = 1 THEN 'Convenio'
WHEN IDCategoria = 2 THEN 'Plus'
WHEN IDCategoria = 3 THEN 'Preferente'
WHEN IDCategoria = 4 THEN 'Premium'
WHEN IDCategoria = 5 THEN 'La Serena'
ELSE ''
END AS Categoria, <-- This has to show the string
gc.monto,
gc.FechaEmisionPago AS Periodo
FROM
gastos_comunes gc
JOIN vcartera_propiedades v ON (v.IDPropiedad=gc.IDPropiedad)
WHERE v.IDGrupo = 1

You would typically move the case expression inside the subquery:
SELECT
gc.IDGastosComunes,
v.IDPropiedad,
v.Depto,
v.NombreDueno,
(
SELECT CASE u2.IDCategoria
WHEN 1 THEN 'Convenio'
WHEN 2 THEN 'Plus'
WHEN 3 THEN 'Preferente'
WHEN 4 THEN 'Premium'
WHEN 5 THEN 'La Serena'
ELSE ''
END
FROM usuarios_tipos u2
WHERE u2.IDUsuario = v.IDDueno AND u2.IDTipo = 10
) AS Categoria
gc.monto,
gc.FechaEmisionPago AS Periodo
FROM gastos_comunes gc
JOIN vcartera_propiedades v ON v.IDPropiedad=gc.IDPropiedad
WHERE v.IDGrupo = 1
Side note: this would need to be tested, but likely, your query can be rewritten to use a (LEFT) JOIN instead of an inline subquery, which would make the syntax much shorter. That would look like:
SELECT
gc.IDGastosComunes,
v.IDPropiedad,
v.Depto,
v.NombreDueno,
CASE u2.IDCategoria
WHEN 1 THEN 'Convenio'
WHEN 2 THEN 'Plus'
WHEN 3 THEN 'Preferente'
WHEN 4 THEN 'Premium'
WHEN 5 THEN 'La Serena'
ELSE ''
END AS Categoria
gc.monto,
gc.FechaEmisionPago AS Periodo
FROM gastos_comunes gc
JOIN vcartera_propiedades v ON v.IDPropiedad=gc.IDPropiedad
LEFT JOIN usuarios_tipos u2 ON u2.IDUsuario = v.IDDueno AND u2.IDTipo = 10
WHERE v.IDGrupo = 1

Related

how to get mysql values based on left join condition

job table
1.id
2.status = 'active'
3.name
repair table
1.repair id
2.job_id
3.process = 'yes|no'
4.status = '1|2'
job table
id name status
1 test active
2 check active
repair table
repair_id job_id process status
1 1 no 2
2 1 no 1
3 1 yes 2
4 2 no 1
5 2 no 2
here i need to show data which ( process != 'yes' and repair_status != 2 ) group by job_id
i need result after query
---------------------------------------------
job_id name( job.name ) status( job.status )
------------------------------------------------
2 check active
In order to get the results that you specify, you mean that process is not yes for any row for the job_id. And then that at least one row has a status <> 2. That would be:
select j.job_id, j.name, j.status
from repair r join
job j
on r.job_id = r.id
group by j.job_id, j.name, j.status
having max(process) = 'no' and
min(repair_status) = 1;
If you want jobs for which no repair exists with process = 'yes' and status = 2, you can use not exists:
select j.*
from jobs j
where not exists (
select 1
from repair r
where r.job_id = j.id and r.process = 'yes' and r.status = 2
)

How to use an if condition in a query?

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)

If the column is empty, select the same column using different where clause

Is there a way to select rpd.name using a different WHERE clause if the previous one returns an empty string?
I've looked into CASE, but I'm not sure how would I go about using it.
table replacement_part
part_id href
1 url_1
2 url_2
3 url_3
table replacement_part_description
part_id language_id name
1 2
1 1 hose
2 2
2 1 control module
3 2 vonkajsi kryt
3 1 outer casing
expected output
part_id href name
1 url_1 hose
2 url_2 control module
3 url_3 vonkajsi kryt
SELECT *
FROM replacement_part AS rp
LEFT JOIN replacement_part_description AS rpd
ON (rp.part_id = rpd.part_id)
WHERE language_id = :id
So something like
if rpd.name = ''
WHERE language_id = a,
else
WHERE language_id = b
This ?
SELECT *
FROM replacement_part AS rp
LEFT JOIN replacement_part_description AS rpd
ON (rp.part_id = rpd.part_id)
WHERE
(
language_id = :id
AND (rpd.name = '' OR rpd.name IS NULL)
)
OR language_id = b
One way is to join the rpd table twice, moving the where clause on the ON condition, and then use COALESCE:
SELECT
...,
COALESCE(rpd1.name, rpd2.name) AS name
FROM
replacement_part rp LEFT JOIN replacement_part_description rpd1
ON rp.part_id = rpd1.part_id AND rpd1.language=a
LEFT JOIN replacement_part_description rpd2
ON rp.part_id = prd2.part_id AND rpd2.language=b
here I suppose that the language is on the description table. If name is an empty string, instead of coalesce you could use CASE WHEN:
CASE WHEN rpd1.name='' OR rpd1.name IS NULL THEN rpd2.name ELSE rpd1.name END AS Name
You can use order by and limit to get one row with priorities:
select . . .
from . . .
where (language_id = a and rpd.name = '') or
language_id = b
order by (language_id = a) desc -- put the "a" rows first
limit 1;

SQL query problems transpose MySQL

There are 2 simple tables
People:
person_id
Name
Reading assestment
date
person_id
quality
speed
Trying to create sql query
SELECT
AVG(r.quality),
AVG(r.speed),
FROM reading_assestment r,people p
where r.person_id =p.person_id
and person_id="3"
Current output:
Quality Speed
77 65
Outcome I am looking for:
Assestment Value
Quality 77
Speed 65
It is something to do with transpose , pivots.
The most general way is to start with your query and then unpivot using separate logic:
select (case when n = 1 then 'Quality' else 'Speed' end) as Assessment,
(case when n = 1 then avg_quality else avg_speed end) as Value
from (select AVG(r.quality) as avg_quality, AVG(r.speed) as avg_speed
from reading_assestment r join
people p
on r.person_id =p.person_id
where person_id = 3
) t cross join
(select 1 as n union all select 2) n
SELECT
AggResults.person_id AS person_id,
Assesment.Name AS AssessmentName,
CASE WHEN Assessment.Name = 'Quality' THEN AggResults.AvgQuality
WHEN Assessment.Name = 'Speed' THEN AggResults.AvgSpeed
ELSE NULL
END AS AssessmentValue
FROM
(
SELECT
people.person_id AS person_id,
AVG(quality) AS AvgQuality,
AVG(speed) AS AvgSpeed
FROM
reading_assessment
INNER JOIN
people
ON reading_assessment.person_id = people.person_id
GROUP BY
people.person_id
)
AS AggResults
CROSS JOIN
(
SELECT 'Quality' AS Name
UNION ALL
SELECT 'Speed' AS Name
)
AS Assessment
WHERE
AggResults.person_id = 3
I moved the = 3 to the outer query, just for ease of use. Most optimisers will treat both options similarly.

Mysql: Finding parent of multiple childrens

I have 2 tables: players and items. Now I'm looking for player who has item with known properties ex.
SELECT players.`name` FROM `players`
INNER JOIN `items` ON players.`id`=items.`ownerId`
WHERE items.`itemType` = 1 AND items.`itemClass` = 2 AND items.`itemColor` = 3
How i can find player which has more than one item i want? It is even possible in one query?
Ex. i wanna find player which has both items : type=1 class=2 color=3 , type=2 class=3 color=4
I have an idea how to do it in multiple querys: just add players.id IN (...) on every next query.
Thanks for all your help!
The best way to do this is with aggregation.
select i.ownerId
from Items i
group by i.ownerId
having max(case when i.itemType = 1 and i.itemClass = 2 and i.itemColor = 3
then 1 else 0
end) = 1 and
max(case when i.itemType = 2 and i.itemClass = 3 and i.itemColor = 4
then 1 else 0
end) = 1
If you want other information about the owner, you need to join in the players table.
In MySQL, you can simplify the having clause to:
having max(i.itemType = 1 and i.itemClass = 2 and i.itemColor = 3) = 1 and
max(i.itemType = 2 and i.itemClass = 3 and i.itemColor = 4) = 1