How to find entries matching a specific string - mysql

I have more than 50000 records in my table with two columns (id and basic) looks like this
ID
BASIC
1
XXX111XXX111
2
XXXX22221111
3
111XXXXX2212
4
2X1X212X1X1X
5
X21X12X1X12X
What I need is to display only records that consist of 5 "X" that are not adjacent. for example, from the above records i need to get data like this
ID
BASIC
4
2X1X212X1X1X
5
X21X12X1X12X
What query will suite to retrieve such record from my database.

I interpret this as meaning that you want 5 Xs that are not adjacent. I think this does what you want:
where concat(' ', col, ' ') regexp '([^X]+[X]){5}[^X]'
The concat() just takes care of the situation where the first or last character is an "X".

Related

MySQL - Convert single column into an array

I have a column of data, e.g. as follows:
select league_id from leagues
This gives me a single column (league_id) and 100+ rows for that column.
I want to convert it into a single cell (1 row, 1 column) with the following structure:
[1001, 1002, 42022, 203412, 24252, etc..]
Essentially converting the rows into one big array.
There must be a way of doing it but can't see how.
I'm using MariaDB 10.2.
You can use the GROUP_CONCAT() function for that.
Usage is straightforward:
id
val
1
1001
2
1002
3
42022
4
203412
5
24252
SELECT group_concat(val)
FROM tab
gives you
group_concat(val)
1001,1002,42022,203412,24252
See db<>fiddle.
(Note: Before MariaDB 10.3.3 you cannot use the LIMIT clause with GROUP_CONCAT, in case you should need that).

Update a row if a field is a subsequence of a string

I have a string S = "1-2-3-4-5-6-7-8"
This is how my database table rows look like:
id
SubSequence
1
1-2-4-5
2
1-3-4-5
3
2-5-7-8
4
5-8-9-10
5
6-7-10-11
and so on ...
I want to write a query that would update (in this example) only the first 3 rows because they're a subsequence of string S.
The current solution I have is to programmatically go thru each row, check if it's a subsequence, and update. But I'm wondering if there's a way to do it at the MySQL level for performance.
Update: I don't mind changing the way data is stored. For example, String S could be an array holding those numbers, and the "SubSequence" column can hold those numbers as an array.
No, there is not a way to do the query you describe with good performance in SQL when you store the subsequences as strings like you have done. The reason is that doing substring comparisons cannot be optimized with indexes, so your query will be forced to do the comparisons row by row.
In general, when you try to store sets of values as a string, but you want to use SQL to treat them as discrete values, it's bound to be awkward, difficult to code, and ultimately have bad performance.
In this case, what I would do is make a two tables, one that numbers your entities, and a second table in which each value in your subsequence is stored on a row by itself.
SubSequences:
id
1
2
SubSequenceElements:
id
SubSequenceElement
1
1
1
2
1
4
1
5
2
1
2
3
2
4
2
5
And so on.
Then you can use relational-division techniques to find cases where every element of this set exists in the set you want to compare it to.
Here's an example:
SELECT s.id
FROM SubSequences AS s
LEFT OUTER JOIN (
SELECT id
FROM SubSequenceElements
WHERE SubSequenceElement NOT IN (1,2,3,4,5,6,7,8)
) AS invalid USING (id)
WHERE invalid.id IS NULL;
In other words, you want to return rows from SubSequences such that no match is found in SubSequenceElements with an element value that is not in the set you're trying to match.
It's a bit confusing, because you have to think about the problem is a double-don't-match-this-set problem. But once you get relational division, it can be very powerful.
If the set can be represented by the numbers 0 through 63 (or some subset of that), then...
Using a column like this
elements BIGINT UNSIGNED NOT NULL DEFAULT '0'
Then "2-5-7-8" could be put into it thus:
UPDATE ...
SET elements = (1<<2) | (1<<5) | (1<<7) | (1<<8);
Then various operations can be done in a single expression:
WHERE elements = (1<<2) | (1<<5) | (1<<7) | (1<<8) -- Test for exactly that set
WHERE (elements ^ ~ ( (1<<2) | (1<<5) | (1<<7) | (1<<8) )) != 0
-- checks to see if any other bits are turned on
This last example is close to what you need. One side of the "and not" would have the 1..8 of your example, the other would have
Your example has S represented as 0x1FE;
WHERE subsequence & ~0x1FE
will be 0 (false) for ids 1,2,3; non-zero (true) for ids 4 and 5.

Searching Letter In Database Records / Mysql

I want to make a search within a varchar column that return the rows which has letters in its last three part. Like:
id name
--- -----
1 06jesq12g
2 06jesq123
3 06jesq126
4 06jesq12f
i want the records with id 1 and 4 because they have "letter" in the last three part. Not all of them are numeric. I hope i made my point, sorry for my english :)
Using SQL:
SELECT *
FROM ...
WHERE name REGEXP ('([a-z]..$|[a-z].$|[a-z]$)')

Getting Last Value in Group Concat

I have a table
course chapter lessons
2 Chapter1 3,4
2 Chapter2 5,10,9,6,8
2 Chapter3 11,15,16,18
I need the last value in lessons column like
In the 1st row of lessons i need the last digit 4
In the 2nd row of lessons i need the last digit 8
In the 3rd row of lessons i need the last digit 18
Is storing a comma separated list in a database column really that bad? Short answer: Yes, it is.
But until you normalize the table, you could use this:
SELECT course
, chapter
, SUBSTRING_INDEX(lessons, ',', -1) AS last_lesson
FROM tableX

Multiple LIKE in SQL

I wanted to search through multiple rows and obtain the row that contains a particular item.
The table in mySQL is setup so each id has a unique list (comma-delimited) of values per row.
Ex:
id | order
1 | 1,3,8,19,34,2,38
2 | 4,7,2,190,38
Now if I wanted to pull the row that contained just the number 19 how would I go about doing this? The possibilities I could figure in the list with a LIKE condition would be:
19, <-- 19 at the start of the list
,19 <-- 19 at the end of the list
,19, <-- 19 inside the list
I tried the following and I cannot obtain any results, Thank you for your help!
SELECT *
FROM categories
WHERE order LIKE '19,%' OR '%,19%' OR '%,19%'
LIMIT 0 , 30
First of all, you should not store values like this, you should use a child table with one row per item, this would make your current query that much easier to handle, and would allow for indexes to be used as well.
Having said that, what you want is this:
WHERE ',' + order + ',' LIKE '%,19,%'
By adding a comma in front of and after the list of values in the order field, you can query that field for the value you want with a comma on each side, and not have to deal with the special case of the value being the first or last value in the list.
With the query you listed, you could've made it work by realizing that OR doesn't give more arguments to the LIKE clause, it separates entirely different clauses, and thus rewritten the SQL like this:
WHERE order LIKE '19,%' OR order LIKE '%,19,%' OR order LIKE '%,19'
---+------ ^ ----+----- ^
| | | |
+- add this -+---------+ +- removed
percent
Note the missing comma in the second pattern there, which would match strings containing the value 19, and note the removed percentage character in the last ,which would allow it to match lists that ended with 19.
You can use FIND_IN_SET to solve your problem in a simpler way:
SELECT *
FROM categories
WHERE FIND_IN_SET('19', `order`)
LIMIT 0, 30
In general though you should try to design your database so that this type of operation is not necessary.