Mysql use of index in case when syntax - mysql

I'm writing a query that updates with the following syntax:
UPDATE foo SET col1 = CASE col2
WHEN 1 THEN 3
WHEN 2 THEN 9
...
ELSE col1 END
WHERE col2 IN (1,2...)
Note that there can be thousands of WHEN THEN cases. EXPLAIN shows that PK will be used for IN clause, but how does the database compute the CASE/WHEN after it filters based on IN clause - does it scan all them or use a hash? I don't think this would be explicit in an EXPLAIN (for example without the IN clause).

Instead of thousands of case when statements, create another table in your database (let's name it keyValueTable) and let one column be the when (key) and the other one the then (value):
id colkey value
1 1 3
2 2 9
make colkey unique and set an index on it, then query the database like
UPDATE foo SET col1 = (
SELECT value from keyValueTable
INNER JOIN foo ON keyValueTable.colkey = foo.col1
LIMIT 1
)
WHERE ...

The CASE expression will be tediously walked through for each row not filtered by the WHERE. There is no optimization, since the WHEN values could be arbitrary expressions, not simple constants like in your case.
This might be faster, assuming you have an index on col2:
UPDATE foo SET col1 = 3 WHERE col2 = 1;
UPDATE foo SET col1 = 9 WHERE col2 = 2;
...

Related

How to build a sequence of values by combining two columns?

I am looking to get a sequence of values by combining two columns that are linked using some random ids:
Table (col2 and col3 are linked)
col1 col2 col3
aa a144 d653
bb z567 a144
cc d653 h999
dd y678 z567
The two columns (col2 and col3), this is like a chain that is forming up.
The result I am looking for is a sequence from start to end:
sequence
y678
z567
a144
d653
h999
Explanation:
The sequence starts at row 4 (dd,y678,z567), followed by row 2 (bb,z567,a144) and so on.
Col3 id is the reference for the Col2 id, to decide the next element.
What you're looking for is a recursive query.
Assuming your table is called data, you do it like this:
WITH RECURSIVE query(id) AS (
SELECT col2
FROM data
WHERE col1 = 'dd' -- Select the initial row here
UNION ALL
SELECT data.col3
FROM data
INNER JOIN query on query.id = data.col2
)
SELECT *
FROM query;
Tested snippet available here: https://onecompiler.com/mysql/3xvj2a47v.
This syntax works in MySQL version 8 and up. If your version is lower, first thing I would recommend is to update it, if possible. If not possible, consult this answer for a workaround using MySQL 5: https://stackoverflow.com/a/33737203/2979473.
you are going to have to use a cursor..
https://www.mysqltutorial.org/mysql-cursor/
first step will be to select the value from col2 that doesn't exist in col3
then insert the value from col3 where the current variable is in col2
return the results set when the value in col3 is not found in col2
This will only work if there is one start and end value and one distinct path through the chain.
It will also be slow, because this is not how RDBMS databases are designed to work.
I think this query will work for you.
SELECT DISTINCT SEQ
FROM
(
SELECT COL2 SEQ FROM TABLE1
UNION
SELECT COL3 SEQ FROM TABLE1
) ORDER BY 1

Generate MQsql query to get records

I am having the following table say "A"
"column1" "column2"
1 arafath#gmail.com
2 ram#gmail.com;arafath#gmail.com
3 tom#gmail.com
I want to get the records with the following condition.
Condition1:
If the column value exist in the any of the row, it will retrieve the matched rows
Condition2:
If the column value doesn't match with any of the row, it wants to retrieve all the rows
Eg: column2 = "ram#gmail.com"
Output should be "row 2"
Eg: column2 = "arafath#gmail.com"
Output should be "row 1, row 2"
Eg: column2 = "xxx#gmail.com" (Unmatched column)
Output should be all the rows (row 1, row 2, row 3)
Please help me out to solve the problem.
Thanks in advance.
Please try the below one.
SELECT col1, col2
FROM yourTable
where ( not exists (Select col2
FROM yourTable where col2 like 'xxx#gmail.com')
or col2 like 'xxx#gmail.com');
We can try using a union here:
SELECT col1, col2
FROM yourTable
WHERE col2 REGEXP '[[:<:]]ram#gmail.com[[:>:]]'
UNION ALL
SELECT col1, col2
FROM yourTable
WHERE col2 NOT REGEXP '[[:<:]]ram#gmail.com[[:>:]]' AND
NOT EXISTS (SELECT 1 FROM yourTable WHERE col2 REGEXP '[[:<:]]ram#gmail.com[[:>:]]');
Demo
The above strategy is that the first half of the union returns the matching record, if it exists. The second half of the union then returns all other records, but only if on match were found in the first half of the union. If a match were found, then the WHERE clause in the second half of the union would fail, and would return nothing.
Also, please note that storing comma separated (or semicolon separated) data in your MySQL tables is generally bad practice. I had to use REGEXP to get around this problem, but ideally if each email had a separate row, we would only need to use = equality.

MySQL select statement access part of hex value in column

I have a table like so:
Type Col1
0 ff
1 9f
3 92
and I want to access just a part of the col1 values
i.e. I want to query the table with a value such as Col1=92 where all the rows return
and if I queried with Col1=94 then row 0 and 1 would return and if I queried with Col1=12 only row 0 would return. Obviously some operation would need to happen on the above assignment statements for this to work.
so something like this:
SELECT * FROM TABLE1 WHERE Col1(1)=9;except I understand that sintax does not work...
hope this makes sense
You have at least 3 options
first being
where `col1` like '9%'
second
where substr(`col1`,1,1) = "9"
Third
where left(`col1`, 1) = "9"
Assuming that col1 is a text field, you could do:
SELECT * FROM table1 WHERE col1 LIKE '9%';
returns any row where col1 starts with a 9.
See http://dev.mysql.com/doc/refman/5.0/en/pattern-matching.html for more "LIKE" patterns
Alternatively, you could use substr(string, start, length), so it would be:
SELECT * FROM table1 WHERE substr(col1,1,1)='9'

In mysql, can I count how many rows satisfy some condition, if not then exit the count?

Basically I store data in MySql 5.5. I use qt to connect to mysql. I want to compare two columns, if col1 is greater than col2, the count continues, but when col1 is less than col2, count finishes and exits. So this is to count how many rows under some condition at the beginning of column. Is it possible in mysql?
An example:
Col1 Col2
2 1
2 3
2 1
The count I need should return 1, because the first row meets the condition of Col1 > Col2, but the second row doesn't. Whenever the condition is not meet, counting exits no matter if following rows meet the condition or not.
SELECT COUNT(*)
FROM table
WHERE col1 > col2
It's a little difficult to understand what you're after, but COUNT(*) will return the number of rows matched by your condition, if that's your desire. If it's not, can you maybe be more specific or show example(s) of what you're going for? I will do my best to correct my answer depending on additional details.
You should not be using SQL for this; any answer you get will be chock full of comprimise and if (for example) the result set from your intial query comes back in a different order (due to an index being created or changed), then they will fail.
SQL is designed for "set based" logic - and you really are after procedural logic. If you have to do this, then
1) Use a cursor
2) Use an order by statement
3) Cross fingers
This is a bit ugly, but will do the job. It'll need adjusting depending on any ORDER etc you would like to apply to someTable but the principle is sound.
SELECT COUNT(*)
FROM (
SELECT
#multiplier:=#multiplier*IF(t.`col1`<t.`col2`,0,1) AS counter
FROM `someTable` t, (SELECT #multiplier := 1) v
HAVING counter = 1
) scanQuery
The #multiplier variable will keep multiplying itself by 1. When it encounters a row where col1 < col2 it multiplies by 0. It will then continue multiplying 0 x 1. The outer query then just sums them up.
It's not ideal, but would suffice. This could be expanded to allow you to get those rows before the break by doing the following
SELECT
`someTable`.*
FROM `someTable`
INNER JOIN (
SELECT
`someTable`.`PrimaryKeyField`
#multiplier:=#multiplier*IF(`col1`<`col2`,0,1) AS counter
FROM `someTable` t, (SELECT #multiplier := 1) v
HAVING counter = 1
) t
ON scanQuery.`PrimaryKeyField` = `someTable`.`PrimaryKeyField`
Or possibly simply
SELECT
`someTable`.*
#multiplier:=#multiplier*IF(`col1`<`col2`,0,1) AS counter
FROM `someTable` t, (SELECT #multiplier := 1) v
HAVING counter = 1

Mysql SELECT and return multiple rows, but prefer one column value over another when present

So i'm looking to write a MySQL query that will return a result set that, when a particular column has a particular row value, it will return that row instead of another near duplicate row but otherwise return results like normal.
Okay, here is my table
id name value another
1 name1 value1
2 name1 value1 foo
3 name2 value2
4 name3 value3
and results should be (if foo is present):
id name value another
2 name1 value1 foo
3 name2 value2
4 name3 value3
I did find this example: MySQL get rows but prefer one column value over another but couldn't figure out how to adapt it to my needs...
I hope I'm making sense! No sleep in two days ain't good for attempts at elucidation! Also I'm very sorry if this has already been asked, i searched for a good long time but just didn't have the vocabulary to find any results...
Thanks in advance!
SELECT
a.*
FROM atable a
LEFT JOIN atable b ON a.name = b.name AND a.another = 'foo'
This will filter out rows with an empty another, for which an entry with the same name and value exists that does have another.
select *
from YourTable yt1
where not exists
(
select *
from YourTable yt2
where yt1.id <> yt2.id
and yt1.name = yt2.pname
and yt1.value = yt2.value
and yt1.another = ''
and yt2.another <> ''
)
This sounds like a situation where the mysql coalesce function would be handy.
Coalesce returns the first non-null parameter it's given. So you can use,
SELECT id, COALESCE(another, value) FROM MyTable;
this will return two columns, the id field and either the contents of the "another" column (if it is not null) or the contents of the "value" column.