Two select statements on same table and get Count(*) - mysql

Im trying to do two queries on the same table to get the Count(*) value.
I have this
SELECT `a`.`name`, `a`.`points` FROM `rank` AS a WHERE `id` = 1
And in the same query I want to do this
SELECT `b`.`Count(*)` FROM `rank` as b WHERE `b`.`points` >= `a`.`points`
I tried searching but did not find how to do a Count(*) in the same query.

Typically you would not intermingle a non aggregate and aggregate query together in MySQL. You might do this in databases which support analytic functions, such as SQL Server, but not in (the current version of) MySQL. That being said, your second query can be handled using a correlated subquery in the select clause the first query. So you may try the following:
SELECT
a.name,
a.points,
(SELECT COUNT(*) FROM rank b WHERE b.points >= a.points) AS cnt
FROM rank a
WHERE a.id = 1;

As I understand from the question, you want to find out in a table for a given id how many rows have the points greater than this row. This can be achieved using full join.
select count(*) from rank a join rank b on(a.id != b.id) where a.id=1 and b.points >= a.points;

Related

MySql Join tables using aggregate(min) in where condition, without subquery

I am trying to get one table, along with the lowest value of a column of another table by LEFT JOIN. I am using subquery to do this.
Sample Snippet:
SELECT *
FROM A
JOIN
(select A_id,
MIN(id) AS complete_date
from C
group by A_id) B ON (A.id=B.A_id)
WHERE A.status="complete";
Is there any possible and efficient way to achieve this without subquery and group by.
A correlated subquery -- with the right indexes -- is often the fastest approach:
SELECT A.*,
(SELECT MIN(C.id)
FROM C
WHERE A.id = C.A_id
) as complete_date
FROM A
WHERE A.status = 'complete;
This avoids the aggregation on an entire table, which is why there is a performance gain.
The index you need is on C(A_Id, id) (the second column is not as important as the first). You may also want an index on A(status).

Combining simple selects in mysql (join or union?)

I have two queries that are both very quick (20ms) - when i combine them with a join, i get a 30 second query and the data is wrong... What's wrong?
SELECT
count(profile.id),
date(profile.createdAt)
FROM profile
GROUP BY date(profile.createdAt)
ORDER BY date(profile.createdAt) DESC;
and
SELECT
count(product.id),
date(product.createdAt)
FROM product
GROUP BY date(product.createdAt)
ORDER BY date(product.createdAt) desc;
Joining them i get a very slow query:
SELECT
count(profile._id),
date(profile.createdAt),
count(product._id),
date(product.createdAt)
FROM profile
INNER JOIN product
ON date(product.createdAt) = date(profile.createdAt)
GROUP BY
date(product.createdAt),
date(profile.createdAt)
ORDER BY date(product.createdAt) desc;
The logical error with your current approach is that you are double counting one or both of the counts due to the join. You may try doing the aggregations in separate subqueries, and then join those subqueries:
SELECT
t1.createdAt,
COALESCE(t1.profile_cnt, 0) AS profile_cnt,
COALESCE(t2.product_cnt, 0) AS product_cnt
FROM
(
SELECT DATE(createdAt) AS createdAt, COUNT(id) AS profile_cnt
FROM profile
GROUP BY DATE(createdAt)
) t1
INNER JOIN
(
SELECT DATE(createdAt) AS createdAt, COUNT(id) AS product_cnt
FROM product
GROUP BY DATE(createdAt)
) t2
ON t1.createdAt = t2.createdAt;
If the two tables don't both contain the same dates, then the above query might drop certain dates. To avoid this, we could join with a calendar table which includes all dates we want to appear in the output.
Regarding performance, you are doing a join of two aggregation queries, so it is not expected to be that performant. Also, calling DATE to cast createdAt to a pure date is expensive, and maybe could be avoided by maintaining a dedicated date column.
I think the problem is that you are joining on the result of the date function, which is likely doing a lot under the hood. That function has to execute for every record in each table.
If you can, join with the primary keys/foreign keys of the tables to take advantage of indexes.

MySQL CROSS JOIN FROM syntax

I have the following query working
SELECT newTable.Score, COUNT(1) AS Total, COUNT(1) / t.count * 100 AS `Frequency`
FROM mytable newTable
CROSS JOIN (SELECT COUNT(1) AS count FROM mytable) t
GROUP BY newTable.Score
ORDER BY Frequency DESC
However, two things I don't understand from the MySQL docs:
1) I don't understand why there isn't a comma, or a join type, specified in the from clause.
Reading the MySQL docs, this seems necessary.
2) What does the 't' represent in the CROSS JOIN clause?
Any advice appreciated.
The t is the same as the newTable - it is an alias name for the table and the temporary table that the subquery builds.
It is easier to read when the optional as keyword is used
SELECT newTable.Score, COUNT(1) AS Total, COUNT(1) / t.count * 100 AS `Frequency`
FROM mytable as newTable
CROSS JOIN (SELECT COUNT(1) AS count FROM mytable) as t
GROUP BY newTable.Score
ORDER BY Frequency DESC
An alias name replaces the original name of the table with a new one to be used in your query. And you need to give subqueries a name to refer to them in your query too.

Alter and Optimize sql query

I need to please change this SQL query to NOT use sub-query with IN, I need for this query to work faster.
here is the query i am working on. About 7 million rows.
SELECT `MovieID`, COUNT(*) AS `Count`
FROM `download`
WHERE `UserID` IN (
SELECT `UserID` FROM `download`
WHERE `MovieID` = 995
)
GROUP BY `MovieID`
ORDER BY `Count` DESC
Thanks
Something like this - but (in the event that you switch to an OUTER JOIN) make sure you're counting the right thing...
SELECT MovieID
, COUNT(*) ttl
FROM download x
JOIN download y
ON y.userid = x.userid
AND y.movieid = 995
GROUP
BY x.MovieID
ORDER
BY ttl DESC;
Use Exists instead, see Optimizing Subqueries with EXISTS Strategy:
Consider the following subquery comparison:
outer_expr IN (SELECT inner_expr FROM ... WHERE subquery_where) MySQL
evaluates queries “from outside to inside.” That is, it first obtains
the value of the outer expression outer_expr, and then runs the
subquery and captures the rows that it produces.
A very useful optimization is to “inform” the subquery that the only
rows of interest are those where the inner expression inner_expr is
equal to outer_expr. This is done by pushing down an appropriate
equality into the subquery's WHERE clause. That is, the comparison is
converted to this:
EXISTS (SELECT 1 FROM ... WHERE subquery_where AND
outer_expr=inner_expr) After the conversion, MySQL can use the
pushed-down equality to limit the number of rows that it must examine
when evaluating the subquery.
filter direct on movieId..you does not need to add sub query. it can be done by using movieID =995 in where clause.
SELECT `MovieID`, COUNT(*) AS `Count`
FROM `download`
WHERE `MovieID` = 995
GROUP BY `MovieID`
ORDER BY `Count` DESC

MySQL efficient and correct linking of GROUP BY results

is there some efficient way how to write queries that join various results of GROUP BYs on a common table? How MySQL handles merging results of aggreagate functions ona a subGROUP with full fields from original table?
i am using this and its slow (and i need also other condition than CONDITION=1)
SELECT a.CID,a.AS_ALL,b.AS_ACTIVE FROM
(SELECT CID,COUNT(DISTINCT RAID) AS AS_ALL FROM MYTABLE GROUP BY CID) a
LEFT JOIN
(SELECT CID,COUNT(DISTINCT RAID) AS AS_ACTIVE FROM MYTABLE WHERE CONDITION=1 GROUP BY CID ) b ON a.CID=b.CID;
also is it save to use something like?? will MySQL always correctly merge COLUMN_A with results of aggregation?
SELECT COLUMN_A COUNT(DISTINCT COLUMN_A), SUM(COLUMN_A),SUM(COLUMN_B) FROM ATABLE WHERE CONDITION=1 GROUP BY COLUMN_C
Thank you for advice
Try this:
SELECT CID,COUNT(DISTINCT RAID) AS AS_ALL,SUM(IF(CONDITION=1, 1, 0)) AS AS_ACTIVE
FROM MYTABLE GROUP BY CID