i've a problem with a query in mysql.
This is what i done:
CREATE TABLE `dar`.`MyTable` (
`MyCol` VARCHAR(100) NOT NULL,
FULLTEXT INDEX `Index_1`(`MyCol`)
)
ENGINE = MyISAM;
INSERT INTO MyTable (MyCol)
VALUES ('6002.C3'),
('6002'),
('6002R1'),
('6003.C4'),
('AA6002.X'),
('BB 6002.X');
This is not necessary, but i've done anyway:
REPAIR TABLE MyTable QUICK;
Now, i execute the next query:
SELECT MyCol FROM MyTable
WHERE MATCH(MyCol) AGAINST ('6002*');
And, it doesn't return any row!!
The parameter ft_min_word_len i've changed to 2, but nothing is changed.
When deleting the row with 'BB 6002.X' the query returns 2 rows!!
6002
6002.C3
That is creepy.
Any idea what is happening here?
I need the query return:
6002.C3
6002
6002R1
Plus if include:
AA6002.X
BB 6002.X
Thanks in advance!!
You are past the 50% threshold in your dataset. Try
SELECT MyCol FROM MyTable
WHERE MATCH(MyCol) AGAINST ('6003');
And see what the result is.
The 50% threshold has a significant implication when you first try full-text searching to see how it works: If you create a table and insert only one or two rows of text into it, every word in the text occurs in at least 50% of the rows. As a result, no search returns any results. Be sure to insert at least three rows, and preferably many more. Users who need to bypass the 50% limitation can use the boolean search mode; see Section 12.9.2, “Boolean Full-Text Searches”.
http://dev.mysql.com/doc/refman/5.0/en/fulltext-natural-language.html
Related
I'm trying to build a keyword search tool based on mysql and I can only get results for full words while I would like to get results for partial matches too.
My db structure looks like this:
My db content looks like this:
This query works:
select * from chromext_keyword where matches (keyword) against ('Redmi')
But this one doesn't work (no result):
select * from chromext_keyword where matches (keyword) against ('red')
I tried with % but it did not solve the problem. I tried the natural language option as well as boolean but it didn't help.
Update with create table query:
CREATE TABLE chromext_keywords (
id int(10) NOT NULL,
keyword text NOT NULL,
blacklist text NOT NULL,
category text NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
and insert:
INSERT INTO chromext_keywords (id, keyword, blacklist, category) VALUES
(1, 'Redmi Note 10', '9,8,pro', '2'),
(2, 'Realme GT', '6,7,8,narzo', '2');
and I added full text:
ALTER TABLE chromext_keywords
ADD UNIQUE KEY id (id);
ALTER TABLE chromext_keywords ADD FULLTEXT KEY keyword (keyword);
I have also tried innoDb and Myisam
Am I missing something?
Thanks
You should check for Minimum word lenght setting ..
in mysql the minimum length for full text search in limited by the param
ft_min_word_len
and the defualt value is for words > 3
take a look at the related docs
https://dev.mysql.com/doc/refman/8.0/en/fulltext-fine-tuning.html
I have finally found the answer.
The following query works:
SELECT * FROM chromext_keywords WHERE match(keyword) against('(re*)') IN BOOLEAN MODE)
With multiple keywords:
SELECT * FROM chromext_keywords WHERE match (keyword) against ('(+red*+not*)') IN BOOLEAN MODE)
I still need to figure out how to cover spelling mistakes. If anyone has an idea, let me know.
In SQL is it possible to nest a SELECT statement in the VALUES clause of the INSERT statement? I'm using MySQL and would like to query the table for the max value of a field plus one when creating a new record, as shown below.
INSERT into attornies (
LawOfficeId, LawOfficeName
) VALUES (
(select max(LawOfficeID)+1 from attornies),
'Wee, Sue Em and Howe'
);
I'm not sure if my syntax is bad, what I'm trying to do is not possible, etc. Of course, If I try this as two separate statements it works but I would like to make it one statement. I know one suggestion is to use auto increment but I don't want to.
If this question has already been answered please point me in that direction. If not .... Help.
Yes you can do it
INSERT into attornies (
LawOfficeId, LawOfficeName
)
select max(LawOfficeID) + 1,'Wee, Sue Em and Howe' from attornies;
However this is not recommended over auto increment since you are likely going to run into duplicate primary key situation if multiple threads are doing the insert
Your query should work. Scalar subqueries are allowed in the values clause of the insert.
In general, it would more commonly be written as:
insert into attornies (LawOfficeId, LawOfficeName)
select max(LawOfficeID)+1, 'Wee, Sue Em and Howe'
from attornies;
However, this is not the right way to do what you seem to want. Instead, create attornies -- which I am renaming to lawOffices because that seems to be the intention -- with an auto-increment column:
create table lawOffices (
lawOfficeId int auto_increment primary key,
lawOfficeName varchar(255)
);
And then do:
insert into lawOffices (lawOfficeName)
values ( 'Wee, Sue Em and Howe' );
The database does the work of incrementing the id.
You can't use the syntax you show.
mysql> INSERT into attornies (
-> LawOfficeId, LawOfficeName
-> ) VALUES (
-> (select max(LawOfficeID)+1 from attornies),
-> 'Wee, Sue Em and Howe'
-> );
ERROR 1093 (HY000): You can't specify target table 'attornies' for update in FROM clause
https://dev.mysql.com/doc/refman/8.0/en/subquery-errors.html says:
You can use a subquery for assignment within an UPDATE statement because subqueries are legal in UPDATE and DELETE statements as well as in SELECT statements. However, you cannot use the same table (in this case, table t1) for both the subquery FROM clause and the update target.
The doc is talking about using a subquery in an UPDATE statement, but the same rule applies in an INSERT or DELETE statement.
However, this works:
mysql> INSERT into attornies (
-> LawOfficeId, LawOfficeName
-> )
-> select max(LawOfficeID) + 1,'Wee, Sue Em and Howe' from attornies;
Query OK, 1 row affected (0.02 sec)
Records: 1 Duplicates: 0 Warnings: 0
https://dev.mysql.com/doc/refman/8.0/en/insert-select.html says:
The target table of the INSERT statement may appear in the FROM clause of the SELECT part of the query. However, you cannot insert into a table and select from the same table in a subquery.
When selecting from and inserting into the same table, MySQL creates an internal temporary table to hold the rows from the SELECT and then inserts those rows into the target table.
I agree with the other answers and comments who warn you against using the MAX()+1 method of getting the next id value. This method is susceptible to race conditions. Use an auto-increment column instead.
Okay, you've all convinced me. In addition, I did a bit of testing of import/export with an auto-increment field in MySQL. My concerns are no longer justified. I'll discard my max()+1 idea as unnecessary and go with auto-increment.
I would also like to thank Steve, Bill Karwin and Gordon Linoff for correcting my SQL and pointing me in the proper direction if I had continued with my original idea.
I just stumbled into a problem and I don't understand why this happens. I have a SELECT query with a WHERE part looking like this using varchar columns: (.,.) IN ((.,.),(.,.),(.,.)). The collation of my columns is latin1_german1_ci and somehow this is relevant when I use german letters like 'ä'. The problem is then that the query returns an empty result but it should select some columns.
I created a minimal SQL Fiddler example: http://sqlfiddle.com/#!9/0c8a0/3/0
CREATE TABLE PairProblem
(`a` varchar(10), `b` varchar(10))
COLLATE = latin1_german1_ci
;
INSERT INTO PairProblem
(a,b) VALUES ('ä','c');
SELECT * FROM PairProblem
WHERE (a,b) IN (('ä','c'),('d','e'));
SELECT * FROM PairProblem
WHERE (a,b) IN (('a','c'),('d','e'));
SELECT * FROM PairProblem
WHERE (a,b) IN (('ä','c'));
SELECT * FROM PairProblem
WHERE a IN ('ä','d');
The first SELECT query there should in my opinion return the same as the second query, but it doesn't.
Since I don't understand why this happens, I cannot really ensure that my query which I need for a much more complex situation selects what I think it should select. So please help me understand this situation or at least how I can prevent such unintended behavior.
I have an insert that uses a GROUP_CONCAT. In certain scenarios, the insert fails with Row XX was cut by GROUP_CONCAT. I understand why it fails but I'm looking for a way to have it not error out since the insert column is already smaller than the group_concat_max_len. I don't want to increase group_concat_max_len.
drop table if exists a;
create table a (x varchar(10), c int);
drop table if exists b;
create table b (x varchar(10));
insert into b values ('abcdefgh');
insert into b values ('ijklmnop');
-- contrived example to show that insert column size varchar(10) < 15
set session group_concat_max_len = 15;
insert into a select group_concat(x separator ', '), count(*) from b;
This insert produces the error Row 2 was cut by GROUP_CONCAT().
I'll try to provide a few clarifications -
The data in table b is unknown. There is no way to say set group_concat_max_len to a value greater than 18.
I do know the insert column size.
Why group_concat 4 GB of data when you want the first x characters?
When the concatenated string is longer than 10 chars, it should insert the first 10 characters.
Thanks.
Your example GROUP_CONCAT is probably cooking up this value:
abcdefgh, ijklmnop
That is 18 characters long, including the separator.
Can you try something like this?
set session group_concat_max_len = 4096;
insert into a
select left(group_concat(x separator ', '),10),
count(*)
from b;
This will trim the GROUP_CONCAT result for you.
You temporarily can set the group_concat_max_len if you need to, then set it back.
I don't know MySQL very well, nor if there is a good reason to do this in the first place, but you could create a running total length, and limit the GROUP_CONCAT() to where that length is under a certain max, you'll still need to set your group_concat_max_len high enough to handle the longest single value (or utilize CASE logic to substring them to be under the max length you desire.
Something like this:
SELECT SUBSTRING(GROUP_CONCAT(col1 separator ', '),1,10)
FROM (SELECT *
FROM (SELECT col1
,#lentot := COALESCE(#lentot,0) + CHAR_LENGTH(col1) AS lentot
FROM Table1
)sub
WHERE lentot < 25
)sub2
Demo: SQL Fiddle
I don't know if it's SQL Fiddle being quirky or if there's a problem with the logic, but sometimes when running I get no output. Not big on MySQL so could definitely be me missing something. It doesn't seem like it should require 2 subqueries but filtering didn't work as expected unless it was nested like that.
Actually, a better way is to use DISTINCT.
I had a situation to add new two fields into existing stored procedure, in a way that a value for that new fields had been obtained by a LEFT JOIN, and because it may have contained a NULL value, a single "concat" value was multiplicated for some cases more than a 100 times.
Because, a group with that new field value contained many NULL values, GROUP_CONCAT exceeded maximum value (in my case 16384).
Using MySQL 5.1.49, I'm trying to implement a tagging system
the problem I have is with a table with two columns: id(autoincrement), tag(unique varchar) (InnoDB)
When using query, INSERT IGNORE INTO tablename SET tag="whatever", the auto increment id value increases even if the insert was ignored.
Normally this wouldn't be a problem, but I expect a lot of possible attempts to insert duplicates for this particular table which means that my next value for id field of a new row will be jumping way too much.
For example I'll end up with a table with say 3 rows but bad id's
1 | test
8 | testtext
678 | testtextt
Also, if I don't do INSERT IGNORE and just do regular INSERT INTO and handle the error, the auto increment field still increases so the next true insert is still a wrong auto increment.
Is there a way to stop auto increment if there's an INSERT duplicate row attempt?
As I understand for MySQL 4.1, this value wouldn't increment, but last thing I want to do is end up either doing a lot of SELECT statements in advance to check if the tags exist, or worse yet, downgrade my MySQL version.
You could modify your INSERT to be something like this:
INSERT INTO tablename (tag)
SELECT $tag
FROM tablename
WHERE NOT EXISTS(
SELECT tag
FROM tablename
WHERE tag = $tag
)
LIMIT 1
Where $tag is the tag (properly quoted or as a placeholder of course) that you want to add if it isn't already there. This approach won't even trigger an INSERT (and the subsequent autoincrement wastage) if the tag is already there. You could probably come up with nicer SQL than that but the above should do the trick.
If your table is properly indexed then the extra SELECT for the existence check will be fast and the database is going to have to perform that check anyway.
This approach won't work for the first tag though. You could seed your tag table with a tag that you think will always end up being used or you could do a separate check for an empty table.
I just found this gem...
http://www.timrosenblatt.com/blog/2008/03/21/insert-where-not-exists/
INSERT INTO [table name] SELECT '[value1]', '[value2]' FROM DUAL
WHERE NOT EXISTS(
SELECT [column1] FROM [same table name]
WHERE [column1]='[value1]'
AND [column2]='[value2]' LIMIT 1
)
If affectedRows = 1 then it inserted; otherwise if affectedRows = 0 there was a duplicate.
The MySQL documentation for v 5.5 says:
"If you use INSERT IGNORE and the row is ignored, the AUTO_INCREMENT counter
is **not** incremented and LAST_INSERT_ID() returns 0,
which reflects that no row was inserted."
Ref: http://dev.mysql.com/doc/refman/5.5/en/information-functions.html#function_last-insert-id
Since version 5.1 InnoDB has configurable Auto-Increment Locking. See also http://dev.mysql.com/doc/refman/5.1/en/innodb-auto-increment-handling.html#innodb-auto-inc...
Workaround: use option innodb_autoinc_lock_mode=0 (traditional).
I found mu is too short's answer helpful, but limiting because it doesn't do inserts on an empty table. I found a simple modification did the trick:
INSERT INTO tablename (tag)
SELECT $tag
FROM (select 1) as a #this line is different from the other answer
WHERE NOT EXISTS(
SELECT tag
FROM tablename
WHERE tag = $tag
)
LIMIT 1
Replacing the table in the from clause with a "fake" table (select 1) as a allowed that part to return a record which allowed the insert to take place. I'm running mysql 5.5.37. Thanks mu for getting me most of the way there ....
The accepted answer was useful, however I ran into a problem while using it that basically if your table had no entries it would not work as the select was using the given table, so instead I came up with the following, which will insert even if the table is blank, it also only needs you to insert the table in 2 places and the inserting variables in 1 place, less to get wrong.
INSERT INTO database_name.table_name (a,b,c,d)
SELECT
i.*
FROM
(SELECT
$a AS a,
$b AS b,
$c AS c,
$d AS d
/*variables (properly escaped) to insert*/
) i
LEFT JOIN
database_name.table_name o ON i.a = o.a AND i.b = o.b /*condition to not insert for*/
WHERE
o.a IS NULL
LIMIT 1 /*Not needed as can only ever be one, just being sure*/
Hope you find it useful
You can always add ON DUPLICATE KEY UPDATE Read here (not exactly, but solves your problem it seems).
From the comments, by #ravi
Whether the increment occurs or not depends on the
innodb_autoinc_lock_mode setting. If set to a non-zero value, the
auto-inc counter will increment even if the ON DUPLICATE KEY fires
I had the same problem but didn't want to use innodb_autoinc_lock_mode = 0 since it felt like I was killing a fly with a howitzer.
To resolve this problem I ended up using a temporary table.
create temporary table mytable_temp like mytable;
Then I inserted the values with:
insert into mytable_temp values (null,'valA'),(null,'valB'),(null,'valC');
After that you simply do another insert but use "not in" to ignore duplicates.
insert into mytable (myRow) select mytable_temp.myRow from mytable_temp
where mytable_temp.myRow not in (select myRow from mytable);
I haven't tested this for performance, but it does the job and is easy to read. Granted this was only important because I was working with data that was constantly being updated so I couldn't ignore the gaps.
modified the answer from mu is too short, (simply remove one line)
as i am newbie and i cannot make comment below his answer. Just post it here
the query below works for the first tag
INSERT INTO tablename (tag)
SELECT $tag
WHERE NOT EXISTS(
SELECT tag
FROM tablename
WHERE tag = $tag
)
I just put an extra statement after the insert/update query:
ALTER TABLE table_name AUTO_INCREMENT = 1
And then he automatically picks up the highest prim key id plus 1.