I'm having trouble finding a better way to search MySQL for a pair of values in a table. I have the value pairs in an array, and would like to duplicate the IN() function, but for more than 1 value.
For example purposed; I have the following 3 pairs:
foo,1
boo,2
goo,3
The current solution puts me at:
SELECT * FROM [table] WHERE
(column1 = 'foo' AND column2 = 1) OR
(column1 = 'boo' AND column2 = 2) OR
(column1 = 'goo' AND column2 = 3);
I'd like to think there's a more "sexy" solution seeing that I could have as many as a hundred pairs and having that may ORs kind of makes me nauseous. Thanks!!!
SELECT *
FROM foo
WHERE (column1, column2) IN (('foo', 1), ('bar', 2))
This syntax may be confusing, and it may be more readable to replace it with:
SELECT *
FROM foo
WHERE ROW(column1, column2) IN (ROW('foo', 1), ROW('bar', 2))
I'm used to the former one, though :)
If you can get your values into a temp table (you only need the two columns) easily and quickly, you can just INNER JOIN your way there. If not, you'll have to use #Quassnoi version.
Great answers from #Quassnoi and #KM !!!
Also, you can get pairs duplicates and select them for post-processing:
SELECT *
FROM `foo`
WHERE (`id_obj` , `Foo_obj`)
IN (
SELECT `id_obj` , `Foo_obj`
FROM `foo`
GROUP BY `id_obj` , `Foo_obj`
HAVING count(*) > 1
)
Related
(MySQL)
I have a query to check if 'phone_number' or 'fax_number' startsWith a value from a given array,
lets say const possibleValues = [123,432,645,234]
currently my query runs with the 'or' condition, to check if -
'phone_number' or 'fax_number' that starts with 123
or
'phone_number' or 'fax_number' that starts with 432
or
'phone_number' or 'fax_number' that starts with 645
or
'phone_number' or 'fax_number' that starts with 234
it runs extremely slow on a big database, and I wish to make it faster,
is there a way to make it run faster?
I'm kinda new to sql queries,
any help would be highly appreciated!
You can try something like:
SELECT * FROM table_1
WHERE CONCAT(',', `phone_number`, ',') REGEXP ',(123|432|645|234),'
OR CONCAT(',', `fax_number`, ',') REGEXP ',(123|432|645|234),';
Demo
Try creating an in-line table and join with it.
WITH telnostart(telnostart) AS (
SELECT '123'
UNION ALL SELECT '432'
UNION ALL SELECT '645'
UNION ALL SELECT '234'
)
SELECT
*
FROM your_search_table
JOIN telnostart ON (
LEFT(tel_number,3) = telnostart
OR LEFT(fax_number,3) = telnostart
you can use a case statement to add a flag column
select *
,case when left(phone_number,3) in (123,432,645,234) or left(fax_number,3) in (123,432,645,234) then 1 else 0 end as contact_check_flag
from table_name
As per your requirement, you can filter it or use it elsewhere.
SELECT * FROM table_1
WHERE `phone_number` REGEXP '^(123|432|645|234)'
OR `fax_number` REGEXP '^(123|432|645|234)';
But it won't be fast. (And no regular INDEX will help.)
If there phone numbers are spelled out like in the US: "123-456-7890", then you could use a FULLTEXT(phone_number, fax_number) index and
SELECT * FROM table_1
WHERE MATCH(phone_number, fax_number)
AGAINST('123 432 645 234');
This is likely to be much faster, but not as "general".
How to make a select from a table excluding rows with N duplicate characters in a row in a certain column? Let's say N=5
'0000011114BR13471' // Exclude
'554XXXXXXXXXXXXXX' // Exclude
'000111114BR134716' // Exclude
'000011114BR134716' // Include
'11880000000000000' // Exclude
'12345678901200000' // Exclude
'12345678901200001' // Include
I tried many combinations but none of them worked. For example:
SELECT * FROM mytable WHERE not (mycolumn regexp '(.)\1{5,}');
Thank you!
You can use the LIKE to match regular Expression and EXCEPT clause to exclude unwanted Results. A query like this might work
In SQL SERVER
Select * from myTable
EXCEPT
Select * from myTable WHERE ColumnName like '(.)\1{4,}'
In MySQl
Select * from myTable
where ColumnName Not In(
Select ColumnName from myTable WHERE ColumnName RLIKE '(.)\1{4,}')
Here N=5. the 4 in regular expration represents 5 duplicates.
I don't think MySQL supports back-references in regular expressions -- which is a shame for your problem. One method is brute force:
select t.*
from t
where col not regexp '0{5}|1{5}|2{5}|3{5}|4{5}|5{5}|6{5}|7{5}|8{5}|9{5}|X{5}';
Another method is a recursive CTE, which breaks up the string into individual characters and then uses window functions to determine if there are 5 in a row:
with recursive cte as (
select col,left(col, 1) as chr, substr(col, 2) as rest, 1 as lev
from t
union all
select col, left(rest, 1), substr(rest, 2), lev + 1
from cte
where rest <> ''
)
select col
from (select cte.*,
lead(lev, 4) over (partition by col, chr order by lev) as chr_4
from cte
) x
group by col
having max(chr_4 = lev + 4) = 0
Here is a db<>fiddle.
In MySQL 8.0:
mycolumn regexp '(.)\\1{4}'
Notes:
Two backslashes are needed.
Since there is 1 selected (.), you need to check for only 4 more, not 5.
The , (meaning "or more") is unnecessary.
I am looking to compare the results of 2 cells in the same row. the way the data is structured is essentially this:
Col_A: table,row,cell
Col_B: row
What I want to do is compare when Col_A 'row' is the same as Col_B 'row'
SELECT COUNT(*) FROM MyTable WHERE Col_A CONTAINS Col_B;
sample data:
Col_A: a=befd-47a8021a6522,b=7750195008,c=prof
Col_B: b=7750195008
Col_A: a=bokl-e5ac10085202,b=4478542348,c=pedf
Col_B: b=7750195008
I am looking to return the number of times the comparison between Col_A 'b' and Col_B 'b' is true.
This does what I was looking for:
SELECT COUNT(*) FROM MyTable WHERE Col_A LIKE CONCAT('%',Col_B,'%');
I see You answered Your own question.
SELECT COUNT(*) FROM MyTable WHERE Col_A LIKE CONCAT('%',Col_B,'%');
is good from performance perspective. While normalization is very good idea, it would not improve speed much in this particular case. We must simply scan all strings from table. Question is, if the query is always correct. It accepts for example
Col_A: a=befd-47a8021a6522,ab=7750195008,c=prof
Col_B: b=7750195008
or
Col_A: a=befd-47a8021a6522,b=775019500877777777,c=prof
Col_B: b=7750195008
this may be a problem depending on the data format. Solution is quite simple
SELECT COUNT(*) FROM MyTable WHERE CONCAT(',',Col_A,',') LIKE CONCAT('%,',Col_B,',%');
But this is not the end. String in LIKE is interpreted and if You can have things like % in You data You have a problem. This should work on mysql:
SELECT COUNT(*) FROM MyTable WHERE LOCATE(CONCAT(',',Col_B,','), CONCAT(',',Col_A,','))>0;
SELECT * FROM MyTable WHERE Col_A = Col_B (AND Col_A = 'cell')
^^ Maybe you are looking for this statement. The part in brackets is optional.
If this is not the solution, please supply us with further information.
The easiest way would be to use the IN operator.
SELECT COUNT(*) FROM MyTable WHERE Col_A IN (Col_B);
More info on the IN operator: http://www.w3schools.com/sql/sql_in.asp
There's also the SUBSTRING() or MID() (depending on what you're using) function if you know that the substring will be in the same position everytime.
MID()/SUBSTRING() function: http://www.w3schools.com/sql/sql_func_mid.asp
You can use SUBSTRING_INDEX to extract a delimited field from a column.
SELECT COUNT(*)
FROM MyTable
WHERE Col_B = SUBSTRING_INDEX(SUBSTRING_INDEX(Col_A, ',', 2), ',', -1)
You need to call it twice to get a single field. The inner call gets the first two fields, the outer call gets the last field of that.
Note that this will be very slow if the table is large, because it's not possible to index substrings in MySQL. It would be much better if you normalized your schema so each field is in a separate column.
If column Col_a has data with format table,row,cell then search expression will be next:
SELECT COUNT(*) FROM MyTable AS MT
WHERE SUBSTRING(Col_A,
INSTR(Col_A, ',b=') + 3,
INSTR(Col_A, ',c=') - INSTR(Col_A, ',b=') + 3) = Col_B
I am wanting to move items from one table into another using MySQL.
This is what I currently use:
INSERT INTO items_rooms (item_id, room_id,x,y,n)
SELECT id, room_id,x,y,z
FROM `items_phoenix`
This works, however I am wanting to insert multiple values into one column instead of each values in different columns.
For example:
In table items_rooms, I would like values x and y from items_phoenix to be placed into one column in items_rooms.
If x = 5 and y = 2, can I save it into items_rooms like this: one column: 5.2 instead of different columns for each values?
Sorry if this is confusing!
You can use expressions in your SELECT column-list. As long as the columns in the select-list and the columns in the destination table match in number and data type, you can do something like this:
INSERT INTO items_rooms (item_id, room_id, x_dot_y, n)
SELECT id, room_id, CONCAT(x,'.',y), z
FROM `items_phoenix`
You definitely can do this. See the helpful answers on this. However, you should consider whether this is a good idea. Once you denormalize distinct columns into some kind of string expression in one column, you've created something that is very difficult to maintain and also to query against. You are making your data less usable to yourself in doing this.
You can use a concatenation for a simple case, e.g:
INSERT INTO items_rooms (
item_id,
room_id,
x_and_y,
n)
SELECT
id,
room_id,
CONCAT(x, '.', y),
z
FROM `items_phoenix`
Yes, if the column can store text information
Just CONCAT or CONCAT_WS the values
INSERT INTO items_rooms ( item_id, room_id, my_value, n )
SELECT id, room_id, CONCAT_WS( '.', x, y ), z
FROM `items_phoenix`
SQL Fiddle DEMO
$table_To_Get_From = mysql_query("SELECT * FROM items_phoenix (id, room_id,x,y,z)");
if($table_To_Get_From){
$table = mysql_fetch_assoc($table_To_Get_From);
$values = array($table['id'],$table['room_id'],$table['x'],$table['y'],$table['z']);
mysql_query("INSERT INTO items_rooms (item_id, room_id,x,y,n)
VALUES ($values[0],$values[1],$values[2],$values[3],$value[4])");
}
I didn't make them strings, so you may need to use '$values[num]'
This will insert it like you wanted, if there is any values.
I'd like to select rows from the database where the last character in the mov_id column equals to 1 and 2.
How would the query look like?
SELECT * FROM `myTable` WHERE `mov_id` LIKE '%1' OR `mov_id` LIKE '%2'
the % character is a wildcard which matches anything (like * in many other places)
If mov_id is a numeric value (TINYINT, INT, etc...) then you should use a numeric operator. For instance, use the modulo operator to keep the last digit
SELECT * FROM mytable
WHERE (mov_id MOD 10) IN (1, 2)
If mov_id is a string, you can use LIKE or SUBSTRING(). SUBSTRING() will be slightly faster.
SELECT * FROM mytable
WHERE SUBSTRING(mov_id, -1) IN ('1', '2')
If your table is big or that query is frequently run, you should definitely consider adding a column to your table, in which you would store mov_id's last digit/character, and index that column.
Try this way too:
SELECT field1
FROM table
WHERE RIGHT(field1, 1) = 'x'
it displays the fields that has last a value of x.
SELECT *
FROM Table
WHERE RIGHT(Column_name, 1) IN ('x')
if you want to match two character just replace 1 by 2.
In general:
RIGHT(COLUMN_NAME, NO_OF_CHARACTER_YOU WANT_TO_MATCH_FROM_LAST)
And if you want to match the starting char just use LEFT instead of RIGHT
You could also do something like:
select
your, fields, go, here
from table
where
substring(mov_id, (char_length(move_id) - 1)) = x
SELECT * FROM table WHERE mov_id REGEXP '1$' OR mov_id REGEXP '2$'