Best way to find a line in MySQL by piece of value - mysql

Database:
+----+------------+
| id | somevalue |
+----+------------+
| 1 | 1000 |
+----+------------+
| 2 | 1001 |
+----+------------+
| 3 | 1002 |
+----+------------+
| 4 | 10021 |
+----+------------+
Question:
What is the best way to find a row by a string which contains piece of "somevalue"?
1. Let's say string is 1002123456. So in this case I must find row with ID 4.
2. Let's say string is 1002345678. So in this case I must find row with ID 3.
Would "MySQL LIKE" work in this scenario?
UPDATE:
Database has 60k rows and "somevalue" should be matched from the front. Because piece of "somevalue" might contain different rows, for example:
+----+------------+
| id | somevalue |
+----+------------+
| 1 | 1000 |
+----+------------+
| 27 | 371000 |
+----+------------+
I am looking for a way to make the process as fast as possible.

SELECT * FROM `db`.`table` WHERE 'someval' LIKE CONCAT('%',`field` , '%') ;
The RLIKE allowes you to match regular expressions in the fields

SELECT * FROM 'table' WHERE 'searchNumber' LIKE CONCAT('%', somevalue, '%')

Related

how to convert table columns into a table in mysql?

I know it's a bad title, but I don't know how to describe my question in a line.
I want to store following information in my database.
+----+----------+-----------+-----------+
| id | name | cluster_1 | cluster_2 |
+----+----------+-----------+-----------+
| 1 | content_1| true| false |
| 2 | content_2| false| true |
| 3 | content_3| true| true |
+----+----------+-----------+-----------+
cluster_1=true means that the content exists on the cluster_1.
As some clusters may added or deleted, I want to store my cluster information in a new table "clusters", and indicate the relation between contents and clusters with a "content_cluster" table.
table contents
+----+----------+
| id | name |
+----+----------+
| 1 | content_1|
| 2 | content_2|
| 3 | content_3|
+----+----------+
table clusters
+----+----------+
| id | name |
+----+----------+
| 1 | cluster_1|
| 2 | cluster_2|
+----+----------+
table content_cluster
+----------+----------+
|content_id|cluster_id|
+----------+----------+
| 1 | 1 |
| 2 | 2 |
| 3 | 1 |
| 3 | 2 |
+----------+----------+
But, writing in this way, I don't know how to get a content which is on cluster_1 but isn't on cluster_2, or vice versa. I have to do this query frequently. So what is the efficient way to do this?
how to get a content which is on cluster_1 but isn't on cluster_2
in general
SELECT contents.name
FROM contents
JOIN content_cluster ON contents.id = content_cluster.content_id
LEFT JOIN clusters ON clusters.id = content_cluster.cluster_id
GROUP BY contents.name
HAVING SUM(clusters.name = 'cluster_1') -- not zero, may add ">0"
AND !SUM(clusters.name = 'cluster_2') -- zero, may replace NOT ("!") with "=0"
The following should work:
-- For cluster 1
INSERT INTO new_table (content_id, cluster_id)
SELECT old_table.content_id, 1
FROM old_table
WHERE old_table.cluster_1 = TRUE;
-- For cluster 2
INSERT INTO new_table (content_id, cluster_id)
SELECT old_table.content_id, 2
FROM old_table
WHERE old_table.cluster_2 = TRUE;

SQL - Select column with certain value in it and other random values

Let me say i have a table called test with the following data
+---------+-----------------+
| id | t_number |
+---------+-----------------+
| 1 | 864291100247345 |
| 2 | 355488020906457 |
| 3 | 864296100098739 |
| 4 | 864296100098325 |
| 5 | 864296100119956 |
What i want to do is to be able to write a select statement that returns a 3 rows with two random values and one mandatory value from the t_number column
for example if the mandatory value is 864291100247345 the output should something like below
+---------+-----------------+
| id | t_number |
+---------+-----------------+
| 1 | 864291100247345 |
| 2 | 355488020906457 |
| 4 | 864296100098325 |
OR
+---------+-----------------+
| id | t_number |
+---------+-----------------+
| 1 | 864291100247345 |
| 3 | 864296100098739 |
| 4 | 864296100098325 |
I have tried the below query but it's not yielding the output i expect, in a sense that it does return a result but without the mandatory value
SELECT * FROM test WHERE t_number = 864291100247345 OR id LIMIT 3;
What is the best way to go about this?
Thank you.
You can use order by:
SELECT t.*
FROM test
ORDER BY (t_number = 864291100247345) DESC,
rand()
LIMIT 3;
This returns the mandatory number first and then random numbers after that.
MySQL treats boolean values (the result of the = expression) as numbers in a numeric context, with "1" for true and "0" for false. So the first expression in the order by sorts the result set with the "true" conditions first, followed by the others.

Optimize SQL-Query that is using REGEXP in a JOIN

I have the following situation:
Table Words:
| ID | WORD |
|----|--------|
| 1 | us |
| 2 | to |
| 3 | belong |
| 4 | are |
| 5 | base |
| 6 | your |
| 7 | all |
| 8 | is |
| 9 | yours |
Table Sentence:
| ID | SENTENCE |
|----|-------------------------------------------|
| 1 | <<7>> <<6>> <<5>> <<4>> <<3>> <<2>> <<1>> |
| 2 | <<7>> <<8>> <<9>> |
And i want to replace the <<(\d)>> with the equivalent word from the Word-Table.
So the result should be
| ID | SENTENCE |
|----|--------------------------------|
| 1 | all your base are belong to us |
| 2 | all is yours |
What i came up with is the following SQL-Code:
SELECT id, GROUP_CONCAT(word ORDER BY pos SEPARATOR ' ') AS sentence FROM (
SELECT sentence.id, words.word, LOCATE(words.id, sentence.sentence) AS pos
FROM sentence
LEFT JOIN words
ON (sentence.sentence REGEXP CONCAT('<<',words.id,'>>'))
) AS TEMP
GROUP BY id
I made a sqlfiddle for this:
http://sqlfiddle.com/#!2/634b8/4
The code basically is working, but i'd like to ask you pros if there is a way without a derived table or without filesort in the execution plan.
You should make a table with one entry per word, so your sentense (sic) can be made by joining on that table. It would look something like this
SentenceId, wordId, location
2, 7, 1
2, 8, 2
2, 9, 3
They way you have it set up, you are not taking advantage of your database, basically putting several points of data in 1 table-field.
The location field (it is tempting to call it "order", but as this is an SQL keyword, don't do it, you'll hate yourself) can be used to 'sort' the sentence.
(and you might want to rename sentense to sentence?)

Constructing SQL query for retrieving tagged items

In the following example, I have three MySQL (InnoDB) tables that contain the information about beverages and their characteristics.
The first table: "beverages" contains a number of different beverages.
Next table is "tags" which contains a characteristic that a beverage can have.
A beverage can have multiple tags, which is defined in the table "tagged".
Table: beverages
+------------------------+
|INT id | VARCHAR name |
+------------------------+
| 1 | coca-cola |
+------------------------+
| 2 | water |
+------------------------+
| 3 | mineral-water |
+------------------------+
Table: tags
+-------------------------+
|INT id | VARCHAR tagName |
+-------------------------+
| 1 | clear |
+-------------------------+
| 2 | carbonated |
+-------------------------+
| 3 | flavoured |
+-------------------------+
Table: tagged
+------------------------------------+
|INT id | INT beverageId | INT tagId |
+------------------------------------+
| 1 | 1 | 2 | (coca-cola is carbonated)
+------------------------------------+
| 2 | 1 | 3 | (coca-cola is flavoured)
+------------------------------------+
| 3 | 2 | 1 | (water is clear)
+------------------------------------+
| 4 | 3 | 1 | (mineral-water is clear)
+------------------------------------+
| 5 | 3 | 2 | (mineral-water is carbonated)
+------------------------------------+
The fields "beverageId" and "tagId" are foreign keys to the table "beverages".
I would like to construct a query that allows me to supply any number of tags, and the result would be all beverage id's that have all of these tags.
A query will include an arbitrary number of tags.
If I supply tag id "2" (carbonated) and tag id "3" (flavoured), I will get back beverage id "1" (coca-cola).
If I supply tag id "1" (clear), I will get back beverage id "2" (water) and id "3" (mineral water).
If I supply tag "2" (carbonated), I will get back beverage id "1" (coca-cola) and beverage id "3" (mineral-water).
So the questions are;
For this purpose, is the table design appropriate?
How should this SQL query effectively be constructed?
Thank you
THe following structure provides some guidance on what you can do. Here is one approach where the tag ids are provided as separate variables:
select beverageid
from tagged t
group by beverageid
having sum(tagid = TAGID1) > 0 and
sum(tagid = TAGID2) > 0 and
. . . ;
Such a query could be a wee bit challenging to produce, because the number of clauses in the having clause varies.
Here is another approach, that assumes that the tagids are in a comma delimited list:
select beverageid
from tagged t
where find_in_set(tagid, TAGLIST) > 0
group by beverageid
having count(distinct tagid) =
(length(TAGLIST) - length(replace(TAGLIST, ',', '')) + 1;
The only slight confusion here is calculating the number of tags.
If you are constructing the query dynamically, then the following should perform the best when there is an index on tagid:
select beverageid
from tagged t
where tagid in (TAGLIST)
group by beverageid
having count(distinct tagid) = LENGTH OF TAGLIST;

"SELECT" selects wrong rows when umlauts are present in table

The structure of table 'textconstraint' (collation utf8_general_ci) is as follows:
+-----+---------+
| id | pattern |
+-----+---------+
| 11 | Ä |
| 27 | A |
+-----+---------+
When I query
SELECT * FROM textconstraint WHERE pattern = 'A' LIMIT 1;
The following rows are selected
+----+---------+
| id | pattern |
+----+---------+
| 11 | Ä |
+----+---------+
Why A-umlaut is selected instead of A?
P.S. I do SET NAMES UTF8
You can try this:
SELECT *
FROM textconstraint
WHERE pattern = BINARY 'A'
See this fiddle.