How to use LIKE operator in MYSQL? - mysql

Write an SQL query to report the patient_id, patient_name all conditions of patients who have Type I Diabetes. Type I Diabetes always starts with DIAB1 prefix.
+--------------+---------+
| Column Name | Type |
+--------------+---------+
| patient_id | int |
| patient_name | varchar |
| conditions | varchar |
+--------------+---------+
This table contains information of the patients in the hospital.
patient_id is the primary key for this table. conditions contains 0 or more code separated by spaces.
So this was my solution:
SELECT *
FROM Patients
WHERE conditions LIKE 'DIAB1%' OR conditions LIKE '%DIAB1%' ;
It worked correctly for all these conditions
patient_id
patient_name
conditions
1
Daniel
YFEV COUGH
2
Alice
3
Bob
DIAB100 MYOP
4
George
ACNE DIAB100
except for this condition
patient_id
patient_name
conditions
1
Daniel
SADIAB100
And in the solution it was shown that there is a space after 1st % which would give you the correct answer:
correct query:
SELECT *
FROM Patients
WHERE conditions LIKE 'DIAB1%' OR conditions LIKE '% DIAB1%' ;
So, can someone please explain why this query works for that particular condition (SADIAB100) and not the 1st query

WHERE conditions LIKE 'DIAB1%' OR conditions LIKE '% DIAB1%'
The problem this is trying to address is when a condition contains the keyword (DIAB1) - while you only want to match on the beginning of the keyword.
The naive approach fails, because it matches on "SADIAB100":
WHERE conditions LIKE '%DIAB1%'
So the workaround is to search for the keyword:
either at the beginning of the whole string (ie at the beginning of the first condition) ; that's what LIKE 'DIAB1%' does
or after another condition, in which case it is preceded by a space, so ' DIAB1%'
Hence:
WHERE conditions LIKE 'DIAB1%' OR conditions LIKE '% DIAB1%'
A slightly neater expression is:
WHERE CONCAT(' ', conditions) LIKE '% DIAB1%'
Bottom line: if you are using a relational database, you should not be storing multiple values in a single row.
Instead of a CSV-like format, you should have a separate table to store the conditions, with each value on a separate row, allowing you to leverage the powerful set-based features that your product offers.

creating a regex pattern to find the keyword 'DIAB1'
filtering on cases where it matches the above
with main as (
select
*, REGEXP_LIKE(conditions,'DIAB1') as is_relevant_patient
from <table_name>
)
select * from main where is_relevant_patient
fiddle test

Related

Is it possible to search a column of IDs for 1 if other rows include IDs with 1 in them?

I have a MySQL database with a varchar column (although the column type can be changed if needed).
The column stores some ids separated with underscores like so:
Row 1: 1
Row 2: 1_2_3
Row 3: 10_2
Row 4: 4_5_1
Is there anyway in this structure to query that column for 1 and return all rows with 1 (but not Row 3 which contains 1 but the ID is 10).
To get the current results I am attempting to search the column LIKE %1%.
Or do I need to change the structure to achieve the result I want?
Maybe you can try:
select *
from t
where c like '1\_%'
or c like '%\_1'
or c like '%\_1\_%'
or c = '1'
You need to escape the underscore as \_, since SQL defines it as a wildcard and will match any character.
If we had a comma separator, then we could use MySQL FIND_IN_SET function.
We can use MySQL REPLACE function to change the underscores to commas,
e.g.
SELECT t.*
FROM t
WHERE FIND_IN_SET('1',REPLACE( t.id ,'_',','))
Reference:
https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_find-in-set
https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_replace
NOTE:
Storing underscore separated lists is an antipattern. See Chapter 2 of Bill Karwin's book "SQL Antipatterns: Avoiding the Pitfalls of Database Programming"
https://www.amazon.com/SQL-Antipatterns-Programming-Pragmatic-Programmers/dp/1934356557
With the operator like:
select * from tablename
where concat('_', id, '_') like '%#_1#_%' escape '#'
See the demo.
Results:
| id |
| ----- |
| 1 |
| 1_2_3 |
| 4_5_1 |

SQL query to select columns with exact like?

Consider this SQL table
id | name | numbers
------------------------
1 | bob | 1 3 5
2 | joe | 7 2 15
This query returns the whole table as its result:
SELECT * FROM table WHERE numbers LIKE '%5%'
Is there an SQL operator so that it only returns row 1 (only columns with the number 5)?
Use regexp with word boundaries. (But you should ideally follow Gordon's comment)
where numbers REGEXP '[[:<:]]5[[:>:]]'
It's a pity that you are not using the comma as a separator in your numbers column, because it would be possible to use the FIND_IN_SET function, but you can use it together with REPLACE, like this:
SELECT * FROM table WHERE FIND_IN_SET(5, REPLACE(numbers, ' ', ','));

Select two first characters and ignore duplicates

I'm currently working on a MySQL database that stores lots of unique postcodes. This is how it looks like:
postcode_id | postcode
------ | ------
1 | BA10EJ
2 | TR96PY
3 | TA64RD
4 | EX54NA
5 | EX167DT
I'd like to select the first couple characters and only list the unique ones, so if there are two EXs I just need to display EX once.
This is what I'm trying to get:
postcode
------
BA
TR
TA
EX
Select distinct substr(postcode,1,2)
from my_table;
Managed to solve my problem by using this query:
SELECT DISTINCT LEFT(postcode, 2) FROM cc_postcodes
Thank you all for your help!
This can be achieved by MySql left(str, len) function. This function returns the leftmost len characters from the string str, or NULL if any argument is NULL.
select distinct left(<mycolumn>, <no_of_chars>) as <myColumn> from <mytable>
To know more about MySql Left()
Use left() with SELECT DISTINCT to get the unique entries.
SELECT DISTINCT LEFT(postcode,2) FROM postcodes;
See this working SQL Fiddle

Distinct number of specific items in list

I rarely do stuff in MySQL, so for me this is rocket science ...
I want to know how many times distinct values starting with "abc-" are present in a list.
So for example how many times "abc-table" and "abc-sofa" are present.
The table:
| object
-----------
| abc-table
| def-table
| ghi-chair
| abc-sofa
| abc-table
The result should be like:
| name number
-------------------
| abc-table 2
| abc-sofa 1
(Excuse me for the badly formatted tables.)
I tried the following, but that turns out to be incorrect:
SELECT object, COUNT(DISTINCT object) WHERE object LIKE abc-% FROM table GROUP BY object
Any help is appreciated.
WHERE clause should be after FROM.
Use single quote ' for the LIKE operator.
No need of DISTINCT in your case.
Try the below query:
SELECT `object` AS `name`, COUNT(`object`) AS `number`
FROM table
WHERE `object` LIKE 'abc-%'
GROUP BY `object`
ORDER BY COUNT(`object`) DESC; -- add order by if you need to sort by count
Result:
name number
----------------
abc-table 2
abc-sofa 1
DEMO
Use count(*), groupt by , like 'abc-%' and having
SELECT object, COUNT(*)
FROM table
WHERE object LIKE 'abc-%'
group by object
having count(*) >=1

Store multiple values in a single cell instead of in different rows

Is there a way I can store multiple values in a single cell instead of different rows, and search for them?
Can I do:
pId | available
1 | US,UK,CA,SE
2 | US,SE
Instead of:
pId | available
1 | US
1 | UK
1 | CA
1 | SE
Then do:
select pId from table where available = 'US'
You can do that, but it makes the query inefficient. You can look for a substring in the field, but that means that the query can't make use of any index, which is a big performance issue when you have many rows in your table.
This is how you would use it in your special case with two character codes:
select pId from table where find_in_set('US', available)
Keeping the values in separate records makes every operation where you use the values, like filtering and joining, more efficient.
you can use the like operator to get the result
Select pid from table where available like '%US%'