Calculated column in where-clause - performance - mysql

Since you can't use a calculated column in a where-clause in MySQL like this:
SELECT a,b,c,(a*b+c) AS d FROM table
WHERE d > n
ORDER by d
you have to use
SELECT a,b,c,(a*b+c) AS d FROM table
WHERE (a*b+c) > n
ORDER by d
Is the calculation (in that example "(a*b+c)" executed once per row or twice? Is there a way to make it faster? I find it strange it's possible to ORDER on the column but not to have a WHERE-clause.

You can use HAVING to filter on a computed column:
SELECT a,b,c,(a*b+c) AS d, n FROM table
HAVING d > n
ORDER by d
Note that you need to include n in the SELECT clause for this to work.

You could do this:
SELECT a,b,c,d FROM
(SELECT a,b,c,(a*b+c) AS d) AS tmp
WHERE d > n
ORDER BY d
But I am not sure what performance implications it could have.

Related

How to speed up the sql query?

I have an SQL query as follows:
SELECT p.Id1,p.Id2,p.Id3
FROM dataset1 p
WHERE p.Id2 IN (
SELECT r.Id4
FROM dataset1 r
WHERE r.Id5=125 AND r.Id6>=100000000000000 AND r.Id6<1000000000000000
)
ORDER BY p.Id1 DESC, p.Id2 DESC
However there appears to be huge amounts of data with Id6 in this range and thus, it takes a quite long time to compute. But I only have one hour to compute the query. I thus, am wondering if someone could help me to improve the performance of this query.
Thanks.
Since the filtering seems to be done on r, arrange for it to be looked at first:
SELECT p.Id1, p.Id2, p.Id3
FROM ( SELECT id4
FROM dataset1 AS r
WHERE r.id5 = 125
AND r.Id6 >= 100000000000000
AND r.Id6 < 100000000000000 ) AS x
JOIN dataset1 AS p ON p.id2 = x.id4
ORDER BY p.Id1 DESC, p.Id2 DESC;
For that, these indexes should be beneficial:
INDEX(id5, id6, id4) -- covering
INDEX(id2, id1, id3) -- covering
You have a "range" test on id6, yet the range is empty. I assume that was a mistake. Please don't simplify a query too much; we might give you advice that does not apply. I am assuming that the range is really a range.
IN tend to optimize poorly when the subquery returns a lot of data. You can try using EXISTS instead:
SELECT p.Id1, p.Id2, p.Id3
FROM dataset1 p
WHERE EXISTS (
SELECT 1
FROM dataset1 r
WHERE
r.Id4 = p.Id2
AND r.Id5 = 125
AND r.Id6 >= 100000000000000
AND r.Id6 < 100000000000000
)
ORDER BY p.Id1 DESC, p.Id2 DESC
Then, consider a multi-column index on (Id4, Id5, Id6) to speed up the subquery. The idea is to put the more restrictive criteria first - so obviously you want Id6 last, but you might want to try inverting the first two columns to see if any combination performs better than the other.
Side note: both the lower and upper bound for Id6 have the same value in your query. I take this as a typo (otherwise your query would always return no row).
To improve performance don't use an inner query. You can get you desired result by using an inner join too:
SELECT
p.Id1, p.Id2, p.Id3
FROM
dataset1 p
INNER JOIN
dataset1 r ON p.Id2 = r.Id4
AND r.Id5 = 125
AND r.Id6 >= 100000000000000
AND r.Id6 < 100000000000000
ORDER BY
p.Id1 DESC, p.Id2 DESC

Multiple SELECT statements in MySQL Query

If I have the schemas:
Type(a,b,c,d)
Name(e, b, g)
I am trying to find all the resulting Name's 'E' where the 'D' of the Type is greater than a number that we access using the shared 'B'.
I am trying to understand how to have multiple SELECT statements such as:
SELECT e FROM Name WHERE b = (SELECT b FROM Type WHERE d > 1);
Can someone explain the syntax error and how to do nested SELECT statements or do I have to join the two tables.
Thanks
This can be accomplished using a simple INNER JOIN operation:
SELECT DISTINCT n.e
FROM Name AS n
INNER JOIN Type AS t ON n.b = t.b
WHERE t.d > 1
You can also use EXISTS:
SELECT n.e
FROM Name AS n
WHERE EXISTS (SELECT 1
FROM Type AS t
WHERE n.b = t.b AND t.d > 1)
I think you want to use IN instead of =
SELECT e FROM Name WHERE b IN (SELECT b FROM Type WHERE d > 1);
= to compare one value to another value.
IN to see if a value exist whiten a list of multiple values.

Correlated value from min query

I'm trying to get the correlated value in a table from a mysql query which looks like:
select min(c), d
from example
table example looks like:
c | d
----------------
'1,99', '30,99'
'5,99', '8,46'
'9,99', '14,99'
'11,79', '17,24'
'12,99', '19,44'
'15,99', '22,44'
'22,49', '34,48'
Given result:
1,99 & 34,48
Expected result:
1,99 & 30,99
What I want is the correlated value from the min(c) in this case '30,99'. How to do that?
You can do it with a sub query:
SELECT * FROM example
WHERE c = (SELECT min(c) from example)
EDIT: if there's more then 1 records the answer the condition, then you need to decide which one you wanna pick.
SELECT * FROM example
WHERE c = (SELECT min(c) from example)
ORDER BY d
LIMIT 1
This will take the one with the smallest d value.
To take the biggest, add DESC after the order by d in the query.
You need to use subquery:
select e.*
from (select min(c) as c from example) x
join example e
on x.c = e.c;

Mysql where condition on columns

Minimal example
select a.order_id as X from orders as a
WHERE
X > 8000
query will fail as X is not a column, any solution?
other example
select (if (E.size > 0, E.Size, (B.height x B.width)) as sizeX from
orders as a, report as E, size as B
where
(E.id = a.id and B.id = a.id)
and
sizeX > 100
my query may contain typos, but I hope my question is clear
You have 2 options:
1) Use HAVING (not very efficient since the conditions from having clause are applied AFTER the results are returned and thus NO indexes are used)
select a.order_id as X from orders as a
HAVING
X > 8000
2) Use the column name (efficient if you have a index an the column used in where clause)
select a.order_id as X from orders as a
WHERE
a.order_id > 8000
Standard SQL disallows references to column aliases in a WHERE clause see the doc here

looking for a slight variant of GROUP BY

I have a table like so:
id attr
1 A
2 A
3 C
4 C
5 D
6 F
I want a count of all the A's B's (but not the C's D's, etc..) Note that my table has zero B's.
So I want a command like this:
SELECT count(attr=A, attr=B) FROM table;
or this:
SELECT count(*) FROM table GROUP_BY attr IN (A, B);
and get:
attr count
A 2
B 0
My actual table has about a thousand attrs. I want to do a group_by-ish thing on maybe a hundred or so of them. It's important that i get the count of zero for certain attrs and that i can correlate the attr to the count.
I know this is a basic question and I'm not surprised if this has been asked before. I searched.. But my apologies anyway..
SELECT T.attr,
COUNT(Y.id)
FROM (SELECT 'A' AS attr
UNION ALL
SELECT 'B') AS T
LEFT JOIN YourTable Y
ON Y.attr = T.attr
GROUP BY T.attr
This should work for you.
SELECT T.Attr,Count(A.ID)
FROM (
SELECT CONVERT('A',char) AS Attr
UNION
SELECT CONVERT('B',char) AS Attr
) AS T
LEFT JOIN MyTable AS A
ON T.Attr=MyTable.Attr
GROUP BY T.Attr
ORDER BY T.Attr;
The Convert part may not be necessary but was necessary in my testing.