MYSQL REGEXP in "CASE WHEN" - mysql

I would like to use REGEXP in a CASE WHEN context like this:
SELECT
CASE title
WHEN REGEXP '^(The Matrix|Riddick|American Pie)$' THEN (
'Movie'
) ELSE (
'FOOO'
)
END
FROM `movies`
but this is not possible. I would like to match different strings here as you can see.
Regards,
Felix

This is indeed possible, with the correct syntax. REGEXP requires a left and right side operand, so use the other syntax of CASE where the full expression is placed after WHEN.
SELECT
CASE
WHEN `title` REGEXP '^(The Matrix|Riddick|American Pie)$' THEN 'Movie'
ELSE 'FOOO'
END AS column_alias
FROM `movies`
However, if you are not using any variable elements in the regular expression, this is likely to be far less efficient than doing exact matches on an indexed column. In other words, you have no need for a regular expression with the example you gave.
SELECT
CASE
WHEN `title` IN ('The Matrix', 'Riddick') THEN 'Movie'
ELSE 'FOOO'
END AS your_column_alias
FROM `movies`

Related

How can I use an IF or Case function to summarize a GROUP_CONCAT column? AND then apply it to the original data table?

I am quite the novice at MYSQL and would appreciate any pointers - the goal here would be to automate a categorical field using GROUP_CONCAT in a certain way, and then summarize certain patterns in the GROUP_CONCAT field in a new_column. Furthermore, is it possible to add the new_column to the original table in one query? Below is what I've tried and errors to an unknown column "Codes" if this assists:
SELECT
`ID`,
`Code`,
GROUP_CONCAT(DISTINCT `Code` ORDER BY `Code` ASC SEPARATOR ", ") AS `Codes`,
IF(`Codes` LIKE '123%', 'Description1',
IF(`Codes` = '123, R321', 'Description2',
"Logic Needed"))
FROM Table1
GROUP BY `ID`
Instead of nested if statements, I would like to have a CASE statement as a substitute. Reason being is that I already have around 1000 lines of logical already written as "If [column] = "?" Then "?" else if" etc. I feel like using CASE would be an easier transition with the logic. Maybe something like:
SELECT
`ID`,
`Code`,
GROUP_CONCAT(DISTINCT `Code` ORDER BY `Code` ASC SEPARATOR ", ") AS `Codes`,
CASE
WHEN `Codes` LIKE '123%' THEN 'Description1'
WHEN `Codes` = '123, R321' THEN 'Description2'
ELSE "Logic Needed"
END
FROM Table1
GROUP BY `ID`
Table Example:
ID,Code
1,R321
1,123
2,1234
3,1231
4,123
4,R321
Completed Table:
ID,Codes,New_Column
1,"123, R321",Description2
2,1234,Description1
3,1231,Description1
4,"123, R321",Description2
How then can I add back the summarized data to the original table?
Final Table:
ID,Code,New_Column
1,R321,Description2
1,123,Description2
2,1234,Description1
3,1231,Description1
4,123,Description2
4,R321,Description2
Thanks.
You can't refer to a column alias in the same query. You need to do the GROUP_CONCAT() in a subquery, then the main query can refer to Codes to summarize it.
It also doesn't make sense to select Code, since there isn't a single Code value in the group.
SELECT ID, Codes,
CASE
WHEN `Codes` = '123, R321' THEN 'Description2'
WHEN `Codes` LIKE '123%' THEN 'Description1'
ELSE "Logic Needed"
END AS New_Column
FROM (
SELECT
`ID`,
GROUP_CONCAT(DISTINCT `Code` ORDER BY `Code` ASC SEPARATOR ", ") AS `Codes`
FROM Table1
GROUP BY ID
) AS x
As mentioned in a comment, the WHEN clauses are tested in order, so you need to put the more specific cases first. You might want to use FIND_IN_SET() rather than LIKE, since 123% will match 1234, not just 123, something

MySQL- Output an "other" column based on multiple columns

I am using MySQL REGEXP to assign reviews into different topics and output them into separate columns. The problem is- some reviews may not get assigned to any topic, which is why I need an "Other" column. How do I modify the query below to achieve that?
SELECT
text,
text REGEXP 'keywords' AND text REGEXP 'other keywords' AND .... AS Cleanliness,
text REGEXP 'keywords' AND text REGEXP 'other keywords' AND .... AS Restaurant,
text REGEXP 'keywords' AND text REGEXP 'other keywords' AND .... AS Wifi,
FROM review_table;
Note that a review can belong to multiple topics.
The end result should look like this:
One solution would be create anoter REGEXP expression that represents the negation of all other expressions. But that can quickly become tedious to maintain.
Another option is to just wrap the query and analyze the results in the outer query to generate the additional column. This should be as simple as:
SELECT x.*, (Cleanliness + Food + Wifi = 0) AS Other
FROM (
--- original query
) x
Tip: in MySQL, the return value of a condition expression is 1 on success and 0 on failure. This means that this expression:
CASE
WHEN review REGEXP 'relevant keywords'
AND review REGEXP 'additional keywords if necessary'
THEN 1
ELSE 0
END AS 'Cleanliness'
Can also be written:
(
review REGEXP 'relevant keywords'
AND review REGEXP 'additional keywords if necessary'
) AS 'Cleanliness'
I think we can use the NOT(expression) command
CASE
WHEN review NOT (REGEXP 'relevant keywords'
AND review REGEXP 'additional keywords if necessary' )
THEN 1
ELSE 0
END AS 'Irrelevant'
Reference: https://dev.mysql.com/doc/refman/5.7/en/regexp.html
Related: negate regex pattern in mysql

SQL regex works the wrong way

I'm trying to build a SQL statement to retrieve user names in the following order
at first, return the names that start with Arabic letter, then the names that start with English letters, then the names that start with special characters.
then sort each of the three groups in ascending order.
This is my code:
SELECT `name` FROM `user`
order by case when substring(name,1,1) like 'N[أ-ي]' then 1
when substring(name,1,1) like '[a-zA-Z]' then 2
else 3
end
,name
The problem is that the case part always returns 3, and so the statement sorts the names in the default order(special chars first, then English letters then Arabic letters). What is the problem in my query?
You need to use regex, not like... (because you use regular expression)
SELECT `name` FROM `user`
order by case when substring(name,1,1) regexp 'N[أ-ي]' then 1
when substring(name,1,1) regexp '[a-zA-Z]' then 2
else 3
end
,name
Reference: MySQL CASE statement and REGEXP

How to say not an empty string in MYSQL with Regular Expression

I am wondering how could i say not an empty string in MYSQL with Regular Expression.
My thought :
SELECT * FROM `table` WHERE `column` <> '^$'
I am totally newby as far as Regular Expressions are concerned. And not a pro at all in MySQL.
Use LENGTH():
SELECT * FROM table
WHERE LENGTH(column) > 0
This (correctly) returns rows that are one or more spaces, and doesn't return nulls.
Note that
WHERE column <> ''
behaves differently. <> ignores trailing spaces, so a column that contains (only) spaces will be considered the same as '', so such rows will be excluded from the selection. If that is what you want, then you can either do:
SELECT * FROM table
WHERE column <> ''
OR
SELECT * FROM table
WHERE LENGTH(TRIM(column)) > 0
Either way, a column containing NULL will evaluate the WHERE expression to NULL, which will exclude the column from the selection. (It is not necessary to also do "AND column IS NOT NULL")
The solution depends on whether you want columns containing only blanks to be considered "empty".
To consider blanks to be empty, and exclude them from the selection, do:
SELECT * FROM `table` WHERE `column` <> '' AND `column` IS NOT NULL
NOTE: TRIM(column) is not needed here, because <> ignores trailing blanks. However, if you feel that TRIM(column) makes the intent clearer, there is no harm in including it:
SELECT * FROM `table` WHERE TRIM(`column`) <> '' AND `column` IS NOT NULL
This has exactly the same result as the first version.
To consider blanks to not be empty, and include them in the selection, use Bohemian's accepted answer.
If you really want use REGEX you should check this
SELECT * FROM `table` WHERE `column` REGEX '^$' AND `column` IS NOT NULL
But I don't recommend using REGEX for checking if string is empty.
UPDATE:
In all of the above answers, "AND column IS NOT NULL" could be omitted. A column containing NULL will evaluate the WHERE expression to NULL, which will exclude the column from the selection.
So the same result can be obtained with the simpler:
SELECT * FROM `table` WHERE `column` <> ''
This is not a comparison to regular expression:
SELECT * FROM `table` WHERE `column` <> '^$'
This is:
SELECT * FROM `table` WHERE `column` REGEX '^$'
or
SELECT * FROM `table` WHERE `column` RLIKE '^$'
One of the first things in learning about regular expressions is when to use them and when not to. This is a case not to. You should just do:
SELECT * FROM `table` WHERE `column` <> ''
By the way, all of these comparisons automatically fail when the value is NULL. If you want to allow NULL values, you would have to do that explicitly.
fieldname REGEXP '^$|^[[:blank:]]+$|^[[:space:]]+$' OR fieldname IS NULL

How to select from Varchar where where `Value` is not part of a group

I'm trying to do this
SELECT `Name`,`Value` FROM `Constants`
WHERE `Name` NOT IN ('Do not get this one'|'or this one');
But it doesn't seem to work.
How do I get all the values, except for a select few, without doing this:
SELECT `Name`,`Value` FROM `Constants`
WHERE `Name` != 'Do not get this one'
AND `Name` != 'or this one'
The first one works with int values, but doesn't work with varchar, is there a syntax like the first one, that performs like the second query?
You should put the constants in a table and then do a select statement from that table. If you absolutely don't want a permanent table you can use a temp table. And if don't want to do that, you can use the IN syntax:
NOT IN ('one', 'two')
It's IN('foo', 'bar'), with a comma, not a pipe.
The IN syntax uses comma-seperated lists
SELECT `Name`,`Value` FROM `Constants` WHERE `Name` NOT IN ('Do not get this one','or this one');