MySQL correlated subquery SUM() ORDER BY - mysql

Is there anyway to optimize the following query:
SELECT
t1.id,
(SELECT SUM(col1) FROM table_name_two t2 WHERE t2.name LIKE CONCAT('%',t1.name)) AS col1_count
FROM
table_name_one t1
ORDER BY
col1_count DESC
Using ORDER BY col1_count DESC takes a long time.
Thanks.

Just make a normal join with your comparison in the join's on clause:
SELECT
t1.id,
SUM(t2.col1) AS col1_count
FROM table_name_one t1
LEFT JOIN table_name_two t2 on t2.name LIKE CONCAT('%', t1.name)
GROUP BY 1
ORDER BY 2 DESC
It should be way faster this way - it's basically one query instead of "n" queries, although it won't get any help from indexes using the LIKE operator with a leading %

Related

Can I use 1 instead of asterisk for SQL_CALC_FOUND_ROWS?

Here is my query:
SELECT t1.mycol
FROM mytable t1
JOIN mytable t2
ON t1.id = t2.postid
ORDER BY value
LIMIT 10;
It works well.
Now I need to count the number of matched rows without the limitation. So I have've added this SQL_CALC_FOUND_ROWS * to the select statement and my query throws:
value is ambiguous in the order by clause.
Why? And how can I fix it?
Noted that, when I use SQL_CALC_FOUND_ROWS 1 instead of SQL_CALC_FOUND_ROWS * in the select statement, then apperantly all fine. So, is it ok to use SQL_CALC_FOUND_ROWS 1? (I'm asking this because that's SQL_CALC_FOUND_ROWS * in the documentation).
I'm not sure why you are using a self-join, but you say the query does what you want.
Your problem is simply the lack of a qualified column name in the order by. It has nothing to do with SQL_CALC_FOUND_ROWS:
SELECT SQL_CALC_FOUND_ROWS t1.mycol
FROM mytable t1 JOIN
mytable t2
ON t1.id = t2.postid
ORDER BY t1.value
LIMIT 10;
I do not know why your original query would have worked. It has the same ambiguous column name in the ORDER BY.
Give it a try:
SELECT SQL_CALC_FOUND_ROWS * from mytable t1
JOIN mytable t2
ON t1.id = t2.postid
ORDER BY t1.value
LIMIT 10;
SELECT FOUND_ROWS();
The reason why you got the error was that, you are joining table with itself, so obviously, every column would occur twice. That's why the name is ambiguous. I added quelifier t1.
Try this
SELECT SQL_CALC_FOUND_ROWS t1.* from mytable t1
JOIN mytable t2
ON t1.id = t2.postid
ORDER BY t1.value
LIMIT 10;
SELECT FOUND_ROWS();

How to use CONCAT_WS/GROUP_CONCAT in LIKE Mysql?

I am trying to execute below query which says
SELECT t1.name from table t1, t2 WHERE t2.data LIKE(CONCAT_WS(',' DISTINCT(t1.name)))
OR
SELECT t1.name from table t1, t2 WHERE t2.data LIKE(GROUP_CONCAT(DISTINCT(t1.name) SEPARATOR ','))
Both ways say
#1111 - Invalid use of group function
Well not totally sure what trying to do, but suspect will need a subquery to join on an aggregate function.
SELECT names
FROM t2
INNER JOIN (SELECT GROUP_CONCAT(DISTINCT name SEPARATOR ',') as names
FROM t1
GROUP BY user_id) t1 USING t2.data = names
That query still doesnt really make sence, but might show roughly how to construct it.
As comments say, really need more context to under WHAT you trying to do.

avoid subquery by using "join" and "group by"

I'm trying to avoid a subquery but I'm not able to get the right result:
This is the original query:
SELECT T1.IdL, T1.REG, T1.YearIn, T1.URL,
(SELECT Count(*) FROM T2 WHERE T1.IdL = T2.IdL) AS IdL_Count
FROM T1
The following is an attempt to avoid subquery but doesn't works becouse the rows where there aren't records in T2 are missing
SELECT T1.IdL, T1.REG, T1.YearIn, T1.URL, Count(*) AS IdL_Count
FROM T1 INNER JOIN T2 USING(IdL)
GROUP BY IdL
So I tryed LEFT JOIN but I get wrong IdL_Count: 1 instead of 0
Is there a way to avoid subquery or not?
There is no way to avoid sub query, at least without specified tables structure (indexes etc).
But this query should perform much better
SELECT T1.IdL, T1.REG, T1.YearIn, T1.URL, coalesce(T3.count, 0) AS IdL_Count
FROM T1
LEFT JOIN (SELECT IdL, count(*) as count FROM T2 GROUP BY IdL) T3 on T3.IdL = T1.IdL
I think if you make the COUNT(T2.[somefield]), instead of COUNT(*), it will return 0 when expected. If that does not work, you can do SUM(IF(T2.IdL IS NULL, 0, 1)) AS IdL_Count instead.

MySQL referencing nested query result in the SELECT?

Say you have two tables with columns:
table1: id, data
table2: id, t1_ref (which is a FK to table1), some_other_column
Now I can write something like (I know that this can be written differently, more efficient, etc, not looking for those):
SELECT t1.data,
(SELECT count(*)
FROM table2 t2
WHERE t2.t1_ref = t1.id) AS nested_result
FROM table1 t1;
My question is, where can I use 'nested_result' in the rest of the main query? Can I use it in the FROM (in another nested select for instance)? Or in the WHERE? Or in a GROUP BY? Or on a ORDER BY? Anywhere else?
For example MySQL doesn't seem to like:
SELECT t1.data,
(SELECT count(*)
FROM table2 t2
WHERE t2.t1_ref = t1.id) AS nested_result
FROM table1 t1
WHERE nested_result > 100;
but what are the general rules here?
nested_result is a column alias.
You can use it in the group by, having, and order by clauses.
You can put this whole statement in a subquery, and use it in the outer query.
Here is the reference in the documentation:
The following list provides additional information about other SELECT
clauses:
A select_expr can be given an alias using AS alias_name. The alias is
used as the expression's column name and can be used in GROUP BY,
ORDER BY, or HAVING clauses. For example:
SELECT CONCAT(last_name,', ',first_name) AS full_name
FROM mytable
ORDER BY full_name;
EDIT:
For your particular example, you can change the where to having:
SELECT t1.data,
(SELECT count(*)
FROM table2 t2
WHERE t2.t1_ref = t1.id
) AS nested_result
FROM table1 t1
HAVING nested_result > 100;
This is a MySQL extensions and doesn't work in other databases. As much as I don't like it, I have to admit that it is convenient.

Join statement...how do do ORDER BY?

I have the following LEFT JOIN statement (though probably also applies to even a simpler SELECT statement):
SELECT * FROM t1 LEFT JOIN t2 ON t2.c = t1.c WHERE t1.m LIKE 'captain%' GROUP BY
t1.c ORDER BY t2.date DESC LIMIT 0,10
The results get returned but they are not ordered by t2.date DESC...I imagine this is due to having the GROUP BY statement in there. How can I group the results AND order them?
thx
Put your query in a subquery and then use ORDER BY.
SELECT *
FROM
(SELECT *
FROM t1 LEFT JOIN t2 ON t2.c = t1.c
WHERE t1.m LIKE 'captain%'
GROUP BY t1.c DESC LIMIT 0,10) l1
ORDER BY date
In normal SQL it would not even be allowed to ORDER BY t2.date because you aren't grouping on it and you are not using an aggregate function on it, so you can't select it.
Anyway, as MySQL just picks values from the rows in an undefined manner and afterwards sorts them, the t2.date column in your results should be sorted. Please show some actual output.