Using an IF Statement in a MySQL SELECT query - mysql

I am trying to use an IF statement in a MySQL select query.
I am getting an error after the AND statement where the first IF.
SELECT J.JOB_ID,E.COMPANY_NAME,J.JOB_DESC,JT.JOBTYPE_NAME,J.COMPENSATION,ST.STATE_NAME,MC.METRO_CITY_NAME,I.INDUSTRY_NAME,
J.JOB_CONTACT_PERSON,J.DT_INSRT,J.JOB_TITLE,J.JOB_EXP_DATE,J.SKILLS
FROM JOBS J
JOIN EMPLOYER E ON J.COMPANY_ID=E.COMPANY_ID
JOIN LOOKUP_JOBTYPE JT ON J.JOB_TYPE=JT.JOBTYPE_ID
JOIN LOOKUP_STATE ST ON J.STATE_ID=ST.STATE_ID
JOIN JOBS_LOCATION JL ON J.JOB_ID=JL.JOB_ID
JOIN LOOKUP_METRO_CITY MC ON JL.METRO_CITY_ID=MC.METRO_CITY_ID
JOIN LOOKUP_INDUSTRY I ON J.INDUSTRY_ID=I.INDUSTRY_ID
JOIN JOBS_QUALIFICATION JQ ON J.JOB_ID=JQ.JOB_ID
JOIN LOOKUP_DEGREE_QUALIFICATION LDQ ON LDQ.QUALIFICATION_ID = JQ.QUALIFICATION_ID
WHERE J.ACTIVE='Y' AND J.DT_INSRT > COALESCE(pEmailSntDt,DATE_SUB(SYSDATE(),INTERVAL 4 DAY))
AND
IF(JQ.COURSE_ID=0)
THEN
IF(JQ.DEGREE_ID=0)
THEN J.SKILLS LIKE CONCAT('%', pSkills,'%')
ELSE
JQ.DEGREE_ID=pDegreeId OR J.SKILLS LIKE CONCAT('%', pSkills,'%')
END IF
ELSE
JQ.COURSE_ID=pCourseId OR IF(JQ.DEGREE_ID=0)
THEN
J.SKILLS LIKE CONCAT('%', pSkills,'%')
ELSE
JQ.DEGREE_ID=pDegreeId OR J.SKILLS LIKE CONCAT('%', pSkills,'%')
END IF
END IF
GROUP BY J.JOB_ID ORDER BY J.DT_INSRT DESC;
Why doesn't this work and what is the proper way to do an IF statement in a MySQL query?

The IF/THEN/ELSE construct you are using is only valid in stored procedures and functions. Your query will need to be restructured because you can't use the IF() function to control the flow of the WHERE clause like this.
The IF() function that can be used in queries is primarily meant to be used in the SELECT portion of the query for selecting different data based on certain conditions, not so much to be used in the WHERE portion of the query:
SELECT IF(JQ.COURSE_ID=0, 'Some Result If True', 'Some Result If False'), OTHER_COLUMNS
FROM ...
WHERE ...

How to use an IF statement in the MySQL "select list":
select if (1>2, 2, 3); //returns 3
select if(1<2,'yes','no'); //returns yes
SELECT IF(STRCMP('test','test1'),'no','yes'); //returns no
How to use an IF statement in the MySQL where clause search condition list:
create table penguins (id int primary key auto_increment, name varchar(100))
insert into penguins (name) values ('rico')
insert into penguins (name) values ('kowalski')
insert into penguins (name) values ('skipper')
select * from penguins where 3 = id
-->3 skipper
select * from penguins where (if (true, 2, 3)) = id
-->2 kowalski
How to use an IF statement in the MySQL "having clause search conditions":
select * from penguins
where 1=1
having (if (true, 2, 3)) = id
-->1 rico
Use an IF statement with a column used in the select list to make a decision:
select (if (id = 2, -1, 1)) item
from penguins
where 1=1
--> 1
--> -1
--> 1
If statements embedded in SQL queries is a bad "code smell". Bad code has high "WTF's per minute" during code review. This is one of those things. If I see this in production with your name on it, I'm going to automatically not like you.

try this code worked for me
SELECT user_display_image AS user_image,
user_display_name AS user_name,
invitee_phone,
(CASE WHEN invitee_status = 1 THEN "attending"
WHEN invitee_status = 2 THEN "unsure"
WHEN invitee_status = 3 THEN "declined"
WHEN invitee_status = 0 THEN "notreviwed"
END) AS invitee_status
FROM your_table

Related

SQL: is there a single query to get "all rows with X, or if none, all rows with Y"?

I'm wondering how to get "all rows where col='X'; if there are none, all rows where col='Y'"
Simplfied database;
CREATE TABLE CHARACTER_NAMES(CHARACTER_ID, LANG VARCHAR(3), NAME);
INSERT INTO CHARACTER_NAMES(1, "ENG", "DONALD DUCK");
INSERT INTO CHARACTER_NAMES(1, "ENG", "GOOD OL' DONALD");
INSERT INTO CHARACTER_NAMES(1, "SWE", "KALLE ANKA");
INSERT INTO CHARACTER_NAMES(1, "SWE", "KALLEN");
INSERT INTO CHARACTER_NAMES(2, "ENG", "MICKEY MOUSE");
INSERT INTO CHARACTER_NAMES(2, "SWE", "MUSSE PIGG");
INSERT INTO CHARACTER_NAMES(2, "SWE", "MUSEN");
INSERT INTO CHARACTER_NAMES(3, "ENG", "GOOFY");
INSERT INTO CHARACTER_NAMES(3, "NOR", "FEDTMULE");
(It's a bit forced that the characters have several names in the same language, but that's how the real database looks like. Also, "CHARACTER_ID" is also a foreign key to the CHARACTER table, but that's not part of the problem, so omitted.)
The user has a language setting, and when there is a database query for a specific character, the query should return the names in the selected language, or the names in English, if the selected language has no results. In the above example, if the setting was "Swedish" and the users selected character 3 (Goofy) the name search should return "Goofy", as there is no Swedish name registered. If the user selected Mickey Mouse, the search should return 2 rows: "Musse Pigg" and "Musen".
I wonder if this is possible to express in an SQL query.
If I just wanted the FIRST in the selected language, if none, english, I could use:
SELECT NAME
FROM CHARACTER_NAMES
WHERE CHARACTER_ID=?
ORDER BY CASE
WHEN LANG='NOR' THEN 1
WHEN LANG='ENG' THEN 2
END
LIMIT 1;
But as I can't know how many names there will be in the selected language, I have to let this LIMIT vary, and I don't really know how to do that in a nice and proper way.
I'm wondering how to get "all rows where col='X'; if there are none, all rows where col='Y'"
SELECT *
FROM table
WHERE col='X'
UNION ALL
SELECT *
FROM table
WHERE col='Y'
AND NOT EXISTS ( SELECT NULL
FROM table
WHERE col='X' )
If a row(s) with col='X' exists then WHERE EXISTS will give FALSE and 2nd subquery will return nothing - i.e. only output of 1st subquery only will be returned.
And backward, if there is no row with col='X' then 1st subquery won't return rows, but WHERE EXISTS will give TRUE and 2nd subquery will return all rows with col='Y' - i.e. only output of 2nd subquery only will be returned.
Or you may use
SELECT *
FROM table
WHERE col = CASE WHEN EXISTS ( SELECT NULL
FROM table
WHERE col='X' )
THEN 'X'
ELSE 'Y'
END;
There are more variants, of course...
In MySQL 8 you can use CASE expression with RANK to get the desired result:
WITH cte AS (
SELECT *, RANK() OVER (PARTITION BY character_id ORDER BY CASE
WHEN lang = 'NOR' THEN 1
WHEN lang = 'ENG' THEN 2
ELSE 3
END) AS rnk
FROM character_names
)
SELECT *
FROM cte
WHERE rnk = 1
Identical result could be achieved with NOT EXISTS:
SELECT *
FROM character_names AS t1
WHERE lang = 'NOR'
OR lang = 'ENG' AND NOT EXISTS (
SELECT *
FROM character_names AS t2
WHERE t2.character_id = t1.character_id
AND t2.lang = 'NOR'
)
Result:
character_id
lang
name
rnk
1
ENG
DONALD DUCK
1
1
ENG
GOOD OL' DONALD
1
2
ENG
MICKEY MOUSE
1
3
NOR
FEDTMULE
1

Enabling Duplicates in WHERE … IN?

I want to use a simple query to decrement a value in a table like so:
UPDATE `Table`
SET `foo` = `foo` - 1
WHERE `bar` IN (1, 2, 3, 4, 5)
This works great in examples such as the above, where the IN list contains only unique values, so each matching row has its foo column decremented by 1.
The problem is when the list contains duplicates, for example:
UPDATE `Table`
SET `foo` = `foo` - 1
WHERE `bar` IN (1, 3, 3, 3, 5)
In this case I would like the row where bar is 3 to be decremented three times (or by three), and 1 and 5 to be decremented by 1.
Is there a way to change the behaviour, or an alternative query that I can use where I can get the desired behaviour?
I'm specifically using MySQL 5.7, in case there are any MySQL specific workarounds that are helpful.
Update: I'm building the query in a scripting language, so feel free to provide solutions that perform any additional processing prior to running the query (perhaps as pseudo code, to be as useful to as many as possible?). I don't mind doing it this way, I just want to keep the query as simple as possible while giving the expected result.
If you can process your original list first to get the counts, you could dynamically construct this kind of query:
UPDATE `Table`
SET `foo` = `foo` - CASE `bar` WHEN 1 THEN 1 WHEN 3 THEN 3 WHEN 5 THEN 1 ELSE 0 END
WHERE `bar` IN (1, 3, 5)
;
Note: the ELSE is just being thorough/paranoid; the WHERE should prevent it from ever getting that far.
There is an example might be beneficial for your purpose:
create table #temp (value int)
create table #mainTable (id int, mainValue int)
insert into #temp (value) values (1),(3),(3),(3),(4)
insert into #mainTable values (1,5),(2,5),(3,5),(4,5)
select value,count(*) as AddValue
into #otherTemp
from #temp t
group by value
update m
set mainValue = m.mainValue+ ot.AddValue
from #otherTemp ot
inner join #mainTable m on m.id=ot.value
select * from #mainTable
This is a little tricky, but you can do it by aggregating first:
update table t join
(select bar, count(*) as factor
from (select 1 as bar union all select 3 as bar union all select 3 as bar union all select 3 as bar union all select 5
) b
) b
on t.bar = b.bar
t.foo = t.foo - bar.factor;

Is there any way to execute a SELECT only if a condition in a different table is met?

Is there any way to do that in a single query? Or do I have to manage it externally? It is not a JOIN of any kind.
SELECT
IF (
(SELECT indicator FROM configuration_table) = 1,
(SELECT series_id FROM series_table LIMIT 1),
''
) as if_exp
FROM
series_table
This executes but returns the first ID over and over, and if I take out the LIMIT 1, it doesn't work as it expects only one result. But what I need is that, if this condition is met:
(SELECT indicator FROM configuration_table) = 1,
Then I need all this data returned:
SELECT series_id, series_code, series_name FROM series_table
Is it possible somehow? Should I be doing two queries and managing the data from php? Thank you very much.
The easiest way would be:
IF ((SELECT indicator FROM configuration_table) = 1) THEN
SELECT series_id, series_code, series_name FROM series_table
END IF
You did not show us what to do, when the condition is false. We do not know the relationship between configuration_table and series_table, so we can't find a way to make it in a single query.
I have copied this answer from IF Condition Perform Query, Else Perform Other Query this answer.
SELECT CASE WHEN ( (SELECT indicator FROM configuration_table) = 1 )
THEN
SELECT series_id, series_code, series_name FROM series_table
ELSE
<QUERY B>
END
Here Query B should replaced by your desired query.

Insert into a different table for each result of a select query

If I have a setup such as:
set #idToIgnore = (select user_id from user_field_value where user_field_id = 82 and value = 'No';
Then I run a select query:
select id from users where account_id = 10 and id != #idToIgnore;
Which returns ~15 different ID values.
I then want to run a query such as:
insert into user_field_value(user_id, user_field_id, value) values (**user_id**, 82, 'Yes');
where user_id in the final insert query is each of the id's from the second query.
I assume there is an easy way to do this but I can't figure it out.
Why not just do that in one INSERT INTO ... SELECT ... query?
INSERT INTO user_field_value(user_id, user_field_id, value)
SELECT id, 82, 'Yes' FROM users
WHERE account_id = 10 and id != #idToIgnore;
You can also do the whole thing in one query using subquery instead of #idToIgnore, but be careful in the matter of performance.

Usage of MySQL's "IF EXISTS"

Here are two statements that I'd like to work, but which return error messages:
IF EXISTS (SELECT * FROM gdata_calendars WHERE `group` = ? AND id = ?) SELECT 1 ELSE SELECT 0
and
IF ((SELECT COUNT(*) FROM gdata_calendars WHERE `group` = ? AND id = ?) > 0) SELECT 1 ELSE SELECT 0;
The question marks are there because I use parametrized, prepared, statements with PHP's PDO. However, I have also tried executing this with data manually, and it really does not work.
While I'd like to know why each of them doesn't work, I would prefer to use the first query if it can be made to work.
You cannot use IF control block OUTSIDE of functions. So that affects both of your queries.
Turn the EXISTS clause into a subquery instead within an IF function
SELECT IF( EXISTS(
SELECT *
FROM gdata_calendars
WHERE `group` = ? AND id = ?), 1, 0)
In fact, booleans are returned as 1 or 0
SELECT EXISTS(
SELECT *
FROM gdata_calendars
WHERE `group` = ? AND id = ?)
I found the example RichardTheKiwi quite informative.
Just to offer another approach if you're looking for something like IF EXISTS (SELECT 1 ..) THEN ...
-- what I might write in MSSQL
IF EXISTS (SELECT 1 FROM Table WHERE FieldValue='')
BEGIN
SELECT TableID FROM Table WHERE FieldValue=''
END
ELSE
BEGIN
INSERT INTO TABLE(FieldValue) VALUES('')
SELECT SCOPE_IDENTITY() AS TableID
END
-- rewritten for MySQL
IF (SELECT 1 = 1 FROM Table WHERE FieldValue='') THEN
BEGIN
SELECT TableID FROM Table WHERE FieldValue='';
END;
ELSE
BEGIN
INSERT INTO Table (FieldValue) VALUES('');
SELECT LAST_INSERT_ID() AS TableID;
END;
END IF;
The accepted answer works well and one can also just use the
If Exists (...) Then ... End If;
syntax in Mysql procedures (if acceptable for circumstance) and it will behave as desired/expected. Here's a link to a more thorough source/description: https://dba.stackexchange.com/questions/99120/if-exists-then-update-else-insert
One problem with the solution by #SnowyR is that it does not really behave like "If Exists" in that the (Select 1 = 1 ...) subquery could return more than one row in some circumstances and so it gives an error. I don't have permissions to respond to that answer directly so I thought I'd mention it here in case it saves someone else the trouble I experienced and so others might know that it is not an equivalent solution to MSSQLServer "if exists"!
If your table has an auto-incrementing primary key, you can use REPLACE INTO ... VALUES
SELECT #id := id FROM tableName WHERE fieldName='criteria value' LIMIT 1;
REPLACE INTO tableName(id, fieldName, col1, col2)
VALUES (#id, 'criteria value', 'value1', 'value2')
If the select statement returns NULL, then a new row is inserted.
Otherwise, if a row is found, it will update the row with key #id.
SELECT IF((
SELECT count(*) FROM gdata_calendars
WHERE `group` = ? AND id = ?)
,1,0);
For Detail explanation you can visit here