MySQL search comma separated value syntax - mysql

I am using MySQL. In one of my table attributes, I have a serial number description like "SM,ST,SK" for one device.
When users enter SM or ST or SK, I want my query to return a result
My current query looks like that:
SELECT CONCAT(lvl1_id,',',lvl2_id)
FROM hier_menus
LEFT JOIN labels ON (hier_menus.id=label_id AND tbl=65 AND fld=2 AND lang_id=5)
WHERE
hm_type=13 AND lvl1_id=141 AND lvl2_id=id AND label='".addslashes($serial)."'";
It is only able to look at the first comma part of serial number column. When users enter ST, it will not return anything.
Is it possible to search the whole of the long string "SM,ST,SK" to return a matching row?

mysql> select find_in_set('SK', 'SM,ST,SK');
+-------------------------------+
| find_in_set('SK', 'SM,ST,SK') |
+-------------------------------+
| 3 |
+-------------------------------+
1 row in set (0.00 sec)
mysql> select find_in_set('SP', 'SM,ST,SK');
+-------------------------------+
| find_in_set('SP', 'SM,ST,SK') |
+-------------------------------+
| 0 |
+-------------------------------+
You are looking for find_in_set,
however, this is not an optimize solution
you should seek to normalize your serial number into another table,
where each SM,ST, and SK is stored as one row
another way is to convert the data type to set

Try FIND_IN_SET():
SELECT ... WHERE FIND_IN_SET($serial, label)
and as ajreal's pointed out, don't use addslashes. use mysql_real_escape_string (or whatever your DB abstraction library provides). addslashes is hopelessly broken and WILL allow someone to attack your database with ease.

Related

MySQL - efficient regexp (or like) query

I have two tables, a performer table and a redirect table. The performer table has a column called slug. The redirect table has a column called source.
Both the source and slug columns have unique key indexes.
An example of a slug column data is something like:
this-is-a-slug
An example of a source column data is something like:
this-is-a-slug.s12345
I want an efficient query that gives me all the rows in redirect that have a source column that starts with a slug and the ".s" characters, followed by a number digits.
I tried this:
select source from redirect
join performer on
source regexp concat('^', slug, '.s[0-9]+$');
It was extremely slow. So I decided to be less restrictive and tried this:
select source from redirect
join performer on
source like concat(slug, ".s%");
It was still slow.
Is there a way I can do this efficiently?
Abandon the current plans.
Add a column to redirect that has the slug. This is a one-time change to the table, plus changing your code to insert it.
If you are running 5.7 or MariaDB, use a virtual column, possibly with a materialized index.
BTW, here's another way to split the string:
mysql> SELECT SUBSTRING_INDEX('this-is-a-slug.s12345', '.', 1);
+--------------------------------------------------+
| SUBSTRING_INDEX('this-is-a-slug.s12345', '.', 1) |
+--------------------------------------------------+
| this-is-a-slug |
+--------------------------------------------------+
If the 's' is critical, then study these:
mysql> SELECT SUBSTRING_INDEX('this-is-a-slug.s12345', '.s', 1);
+---------------------------------------------------+
| SUBSTRING_INDEX('this-is-a-slug.s12345', '.s', 1) |
+---------------------------------------------------+
| this-is-a-slug |
+---------------------------------------------------+
mysql> SELECT SUBSTRING_INDEX('this-is-a-slug.invalid', '.s', 1);
+----------------------------------------------------+
| SUBSTRING_INDEX('this-is-a-slug.invalid', '.s', 1) |
+----------------------------------------------------+
| this-is-a-slug.invalid |
+----------------------------------------------------+
Maybe
join performer on left(source,length(slug)+2)=concat(slug, ".s")
But it seems to me it is the same

Sorting order behaviour between Postgres and Mysql

I have faced some strange sort order behaviour between Postgres & mysql.
For example, i have created simple table with varchar column and inserted two records as below in both Postgres and Mysql.
create table mytable(name varchar(100));
insert into mytable values ('aaaa'), ('aa_a');
Now, i have executed simple select query with order by column.
Postgres sort order:
test=# select * from mytable order by (name) asc;
name
------
aa_a
aaaa
(2 rows)
Mysql sort order:
mysql> select * from mytable order by name asc;
+------+
| name |
+------+
| aaaa |
| aa_a |
+------+
2 rows in set (0.00 sec)
Postgres and mysql both returning same records with different order.
My question is which one correct?
How to get results in same order in both database?
Edited:
I tried with query with ORDER BY COLLATE, it solved my problem.
Tried like this
mysql> select * from t order by name COLLATE utf8_bin;
+------+
| name |
+------+
| aa_a |
| aaaa |
+------+
3 rows in set (0.00 sec)
Thanks.
There is no "correct" way to sort data.
You need to read up on "locales".
Different locales will provide (among other things) different sort orders. You might have a database using ISO-8859-1 or UTF-8 which can represent several different languages. Rules for sorting English will be different for those from French or German.
PostgreSQL uses the underlying operating-system's support for locales, and not all locales are available on all platforms. The alternative is to provide your own support, but then you can have incompatibilities within one machine.
I believe MySQL takes the second option, but I'm no expert on MySQL.

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%'

Iterating through MySQL rows

I have a simple MySQL table made up of words and an associated number. The numbers are unique for each word. I want to find the first word whose index is larger than a given number. As an example:
-----------------------
| WORD: | F_INDEX: |
|---------------------|
| a | 5 |
| cat | 12 |
| bat | 4002 |
-----------------------
If I was given the number "9" I would want "cat" returned, as it is the first word whose index is larger than 9.
I know that I can get a full list of sorted rows by querying:
SELECT * FROM table_name ORDER BY f_index;
But would, instead, like to make a MySQL query that does this. (The confusion lies in the fact that I'm unsure as to how to keep track of the current row in my query). I know can loop with something like this:
CREATE PROCEDURE looper(desired_index INT)
BEGIN
DECLARE current_index int DEFAULT 0
// Loop here, setting current_index to whatever the next rows index is,
// then do a comparison to check it to our desired_index, breaking out
// if it is greater.
END;
Any help would be greatly appreciated.
Try this:
SELECT t.word
, t.f_index
FROM table_name t
WHERE t.f_index > 9
ORDER
BY t.f_index
LIMIT 1
It is much more efficient to have the database return the row you need, than it is to pull a whole bunch of rows and figure out which one you need.
For best performance of this query, you will want an index ON table_name (f_index,word).
Why don't you just use MYSQL statement to retrieve the first item you found from f_index where the f_index is greater than the value your pass in.
For example :
select word from table_name
where f_index > desired_index
order by f_index
limit 1

About mysql regex,how do I search and return string use mysql regex

My table filed's value is "<script type="text/javascript"src="http://localhost:8080/db/widget/10217EN/F"></script>",
I want to analyse this string and fetch the id 10217,how to do use mysql regex?
I know python regex group function can return the id 10217,but i'm not familiar with mysql regex.
Please help me,Thank you very much.
MySQL regular expressions do not support subpattern extraction. You will probably have better luck iterating over all of the rows in your database and storing the results in a new column.
As far as I know, you can't use MySQL's REGEXP for substring retrieval; it is designed for use in WHERE clauses and is limited to returning 0 or 1 to indicate failure or success at a match.
Since your pattern is pretty well defined, you can probably retrieve the id with a query that uses SUBSTR and LOCATE. It will be a bit of a mess since SUBSTR wants the start index and the length of the substring (it would be easier if it took the end index). Perhaps you could use TRIM to chop off the unwanted trailing part.
This query get the Id from the field
SELECT substring_index(SUBSTRING_INDEX(testvar,'/',-3),'EN',1) from testtab;
where as testtab - is table name , testvar - is field name
inner substring get string starts with last 3 / which is
mysql> SELECT SUBSTRING_INDEX(testvar,'/',-3) from testtab;
+----------------------------+
| SUBSTRING_INDEX(testvar,'/',-3) |
+----------------------------+
| 10217EN/F"> |
| 10222EN/F"> |
+----------------------------+
2 rows in set (0.00 sec)
outer substring get
mysql> SELECT substring_index(SUBSTRING_INDEX(testvar,'/',-3),'EN',1) from testtab;
+----------------------------------------------------+
| substring_index(SUBSTRING_INDEX(testvar,'/',-3),'EN',1) |
+----------------------------------------------------+
| 10217 |
| 10222 |
+----------------------------------------------------+
2 rows in set (0.00 sec)