REPLACE non-numeric values and MATCH in WHERE clause - mysql

I have a query like so:
SELECT * FROM `mytable` WHERE `code` LIKE 'PR-SM' AND number = '45'
However in some instances the number can be PR45 which will then fail. I have tried the following:
SELECT * FROM `mytable` WHERE `code` LIKE 'PR-SM' AND CAST(number as unsigned) = '45'
SELECT * FROM `mytable` WHERE `code` LIKE 'PR-SM' AND CONVERT(number as unsigned) = '45'
SELECT * FROM `mytable` WHERE `code` LIKE 'PR-SM' AND number LIKE '%45'
LIKE % will not work as it also picks up 145.
REGEXP_REPLACE also does not work as I am on MySQL 5.7
This is needed for my API, because of my setup I need to be able to do it in the where clause.
Sample Table:
+--------------------------+
| code | number |
+--------------------------+
| PR-SM | PR45 |
+--------------------------+
| PR-SM | PR145 |
+--------------------------+
| XYZ | 177 |
+--------------------------+
| XYZ | 81 |
+--------------------------+

Although you are not using MySQL 8+, which means you won't have access to the newer regex functions, on 5.7 REGEXP should still be available:
SELECT *
FROM yourTable
WHERE code = 'PR-SM' AND number REGEXP '(^|[^0-9])45([^0-9]|$)';
Demo
The regex pattern used here says to match:
(^|[^0-9]) match the start of the input OR a non digit
45 match the number 45
([^0-9]|$) match the end of the input OR a non digit

Related

How can I extract a number from string using regex with various formats (MySQL)?

I have a MySQL data table which stores metadata for client transactions. I am writing a query to extract a number out of the metadata column, which is essentially a JSON stored as a string.
I am trying to find 'clients' and extract the first number after clients. The data can be stored in several different ways; see the examples below:
..."type\":\"temp\",\"typeOther\":\"\",\"clients\":\"2\",\"hours\":\"5\",\...
..."id\":31457,\"clients\":2,\"cancel\":false\...
I've tried the following Regexp:
(?<=clients.....)[0-9]+
(?<=clients...)[0-9]*(?=[[^:digit:]])
And I've tried the following json_extract, but it returned a null value:
json_extract(rd.meta, '$.clients')
The regexp functions do work, but the first one only works on the first example, while the second only works on the second example.
What regexp should I use such that it's dynamic and will pull the number nested between two non-word char sets after 'clients'?
clients.*?([0-9]+)
^^^^^^^ -- exact match
^^^ -- non-greedy string of anything
^ ^ -- capture
^^^^^^ -- string of 1 or more digits (greedy)
I did this test on MySQL 8.0.29, but it should work on MySQL 5.x too:
mysql> set #s1 = '..."type\":\"temp\",\"typeOther\":\"\",\"clients\":\"2\",\"hours\":\"5\",\...';
mysql> set #s2 = '..."id\\":31457,\\"clients\\":2,\\"cancel\\":false\\...';
mysql> select trim(leading '\\"' from substring_index(#s1, '\\"clients\\":', -1)) as clients;
+--------------------------+
| clients |
+--------------------------+
| 2\",\"hours\":\"5\",\... |
+--------------------------+
mysql> select trim(leading '\\"' from substring_index(#s2, '\\"clients\\":', -1)) as clients;
+------------------------+
| clients |
+------------------------+
| 2,\"cancel\":false\... |
+------------------------+
Then cast the result as an integer to get rid of the non-numeric part following the number.
mysql> select cast(trim(leading '\\"' from substring_index(#s1, '\\"clients\\":', -1)) as unsigned) as clients;
+---------+
| clients |
+---------+
| 2 |
+---------+
mysql> select cast(trim(leading '\\"' from substring_index(#s2, '\\"clients\\":', -1)) as unsigned) as clients;
+---------+
| clients |
+---------+
| 2 |
+---------+

How to check that a column values has string or digits values in mysql?

I have mysql table with multiple columns, a column has string data type namely code and the values of the column might be digits only or mixed of string and digits e.g: one row value has 57677 and other rows column value like 2cskjf893 or 78732sdjfh.
mysql> select * from testuser;
+------+--------------+
| id | code |
+------+--------------+
| 1 | 232 |
| 2 | adfksa121dfk |
| 3 | 12sdf |
| 4 | dasd231 |
| 5 | 897 |
+------+--------------+
5 rows in set (0.00 sec)
mysql> show create table testuser;
+----------+------------------------------------------------------------------ ---------------------------------------------------------------+
| Table | Create Table |
+----------+------------------------------------------------------------------ ---------------------------------------------------------------+
| testuser | CREATE TABLE `testuser` (
`id` int(11) DEFAULT NULL,
`code` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+----------+------------------------------------------------------------------ ---------------------------------------------------------------+
1 row in set (0.00 sec)
mysql>
I would like to filter out only rows which has numeric value in code column or filter rows which has string values in code column.
try this
Mysql Query to fetch only integer values from a particular column
SELECT column FROM TABLE where column NOT REGEXP '^[0-9]+$' ;
Mysql Query to fetch only string values from a particular column
SELECT column FROM TABLE where column REGEXP '^[0-9]+$' ;
To get digits
SELECT id,code
FROM table_name
WHERE code REGEXP '^[0-9]+$';
To get string values
SELECT *
FROM table_name
WHERE code REGEXP '^[a-zA-Z]+$'
Use regular expressions
SELECT *
FROM myTable
WHERE code REGEXP '^[0-9]+$';
This will filter out column values with all digits.
You can use regular expressions in mysql too.
SELECT * FROM `table` WHERE `code` REGEXP '[0-9]';
Results will be the rows, where any number in the code column.
Try this,
select id,code from table_name where code NOT REGEXP '^[0-9]+$'
Or,
select id,code from table_name where code like '%[^0-9]%'

Get path with specific number of values

I have a SQL table with the following values:
+---------+----------+
| post_id | path |
+---------+----------+
| 1 | 1/ |
| 2 | 1/2/ |
| 3 | 1/2/3/ |
| 4 | 1/2/3/4/ |
| 5 | 1/2/5/ |
+---------+----------+
How can I create a query that would get the path with the exact number of values separated by slashes?
For example, if I wanted all post_ids where the path is exactly 1/%/%/ (where each % represents a single number), meaning return anything of the form 1/2/3/, 1/2/5/, but not 1/2/3/4/.
Here's one option using regexp:
select *
from yourtable
where path regexp '1/[0-9]/[0-9]/$'
SQL Fiddle Demo
There are several ways to do that:
MySQL LIKE operator.
The LIKE operator provides two wildcard characters, the percentage % ( match any string of zero or more characters), and underscore _ ( match any single character ).
SELECT * FROM `table` WHERE `path` LIKE '1/_/_/'
SELECT * FROM `table` WHERE `path` LIKE '1/%/%/'
MySQL Regular Expressions.
SELECT * FROM `table` WHERE `path` regexp '^1/[0-9]/[0-9]/$'
Hierarchical Data in MySQL
Since this structure involves hierarchical data maybe you should consider to change the table structure to something that represents actual hierarchy. http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/ has an excellent tutorial about the subject.

Can't see MySQL BIT field value when using SELECT

my_table contains the enabled field which is defined as: enabled BIT NOT NULL DEFAULT 0.
This table has multiple rows with enabled = b'0', and multiple rows with enabled = b'1'.
However, both this:
SELECT * from my_table WHERE enabled = b'0';
and this:
SELECT * from my_table WHERE enabled = b'1';
show blank in the enabled column:
+----+---------+
| id | enabled |
+----+---------+
| 1 | |
| 2 | |
+----+---------+
Why is that? How could I see the value of the enabled field?
$ mysql --version
mysql Ver 14.14 Distrib 5.1.63, for debian-linux-gnu (x86_64) using readline 6.1
The reason why you can't see it in terminal is because bit values are non printable characters.
Lets insert following values:
INSERT INTO `my_table` (`ID`, `enabled`)
VALUES (1,b'1'),(2,b'0');
Then select them to file:
mysql> SELECT * FROM my_table INTO OUTFILE '/tmp/my_table.txt' FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n';
First lets view our /tmp/my_table.txtfile as plain text:
"1"," "
"2"," "
and then in hex view:
22 31 22 2C 22 01 22 0A 22 32 22 2C 22 00 22 0A
To be able to see those values you can simply CAST them in SELECT:
SELECT id, CAST(enabled AS UNSIGNED) AS enabled FROM my_table
And that will produce the following output:
+----+---------+
| id | enabled |
+----+---------+
| 1 | 1 |
| 2 | 0 |
+----+---------+
2 rows in set (0.00 sec)
Another way you can do it is
SELECT enabled+0 from my_table
the simplest way is ORD function:
SELECT ORD(`enabled`) AS `enabled` FROM `my_table`
Bit values are returned as binary values. To display them in printable form, add 0 or use a conversion function such as BIN().
https://dev.mysql.com/doc/refman/5.7/en/bit-field-literals.html
Use HEX()
Like:
SELECT id, HEX(enabled) AS enabled FROM my_table
You could also try SELECT enabled&1 from my_table.
to convert a bit field value to a human readable string, use the built-in EXPORT_SET function, the simple example to convert a column of type bit(1) to a "Y" or "N" value would be
EXPORT_SET(column, 'Y', 'N')
You could also convert a bit(8) value to binary representation of the byte
EXPORT_SET(column, '1', '0', '', 8)

ORDER BY not working in MySQL 5.1

I have a problem with sql query in php:
select
user, name, outlet, switch, port, vlan, mac, status
from access where
user like '%'
and name like '%'
and outlet like '%'
and switch like '%'
and port like '%'
and vlan like '%'
and mac like '%'
and status like '%'
order by 'user';
When running query on MySQL client version: 5.1.36 query doesn't work totally (ORDER BY won't work), however when running SAME query on MySQL client version: 4.1.13, ORDER BY works!
I have checked nearly all manuals about ORDER BY, WHERE, LIKE commands, but no result. No mention about version differences, etc..
You have to remove the quotes from user in the ORDER BY clause. This is what is causing the ORDER BY not working as expected, because you can use any expression in the ORDER BY clause, and the 'user' in quotes is being considered an expression (constant) instead of a column name.
Test case (MySQL 5.1.45):
CREATE TABLE tb (id int);
INSERT INTO tb VALUES (5);
INSERT INTO tb VALUES (1);
INSERT INTO tb VALUES (4);
INSERT INTO tb VALUES (2);
INSERT INTO tb VALUES (3);
SELECT * FROM tb ORDER BY 'id';
+------+
| id |
+------+
| 5 |
| 1 |
| 4 |
| 2 |
| 3 |
+------+
5 rows in set (0.00 sec)
SELECT * FROM tb ORDER BY id;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+------+
5 rows in set (0.00 sec)
I think what you need is:
SELECT `user`,`name`,`outlet`,`switch`,`port`,`vlan`,`mac`,`status`
FROM `access`
WHERE `user` like '%'
AND `name` like '%'
AND `outlet` like '%'
AND `switch` like '%'
AND `port` like '%'
AND `vlan` like '%'
AND `mac` like '%'
AND `status` like '%'
ORDER BY `user`;
Though I don't understand your WHERE clause. It doesn't filter on any of the fields.
EDIT; some of your column names (user, name, port and status) could be MySQL keywords. Try enclosing them in grave accents (`) (I added them to my post as well).