I am running the following query
SELECT t2.lender_name, COUNT(t1.id) as total,
SUM(t1.submit_date IS NULL) AS num_incomplete,
(SELECT AVG(DATEDIFF(due_date,now()))
FROM table_1 WHERE submit_date IS NULL ) as avg_incomplete_due_in,
(SELECT AVG(DATEDIFF(due_date,submit_date))
FROM table_1 WHERE submit_date IS NOT NULL) as avg_complete_turnaround
FROM table_1
INNER JOIN table_2 t2 ON t2.fid = t1.id
WHERE t1.due_date <= '2010-12-31'
GROUP BY t2.lender_name
The total, num_incomplete and the grouping works great. The sub select values are the same for each row. I would like those values grouped by the lender_name also and returned as part of the same recordset. Any suggestions?
Your current code just lacks a relation between the outer query and the subqueries. In theory, you just need to correlate the queries:
SELECT t2.lender_name, COUNT(t1.id) as total,
SUM(t1.submit_date IS NULL) AS num_incomplete,
(SELECT AVG(DATEDIFF(due_date,now()))
FROM table_1 t3
WHERE submit_date IS NULL
AND t3.lender_name = t2.lender_name) as avg_incomplete_due_in,
(SELECT AVG(DATEDIFF(due_date,submit_date))
FROM table_1
WHERE submit_date IS NOT NULL
AND t3.lender_name = t2.lender_name) as avg_complete_turnaround
FROM table_1 t1
INNER JOIN table_2 t2 ON t2.fid = t1.id
WHERE t1.due_date <= '2010-12-31'
GROUP BY t2.lender_name
In practice, the query is not very efficient in MySQL. You can rewrite it in the following way:
SELECT
t2.lender_name,
COUNT(*) as total,
SUM(t1.submit_date IS NULL) AS num_incomplete,
AVG(IF(t1.submit_date IS NULL,
DATEDIFF(t1.due_date, NOW()),
NULL)) AS avg_incomplete_due_in,
AVG(DATEDIFF(due_date,submit_date)) AS avg_complete_turnaround
FROM table_1 t1
INNER JOIN table_2 t2 ON t2.fid = t1.id
WHERE t1.due_date <= '2010-12-31'
GROUP BY t2.lender_name
sum if, and count if do the trick
SELECT t2.lender_name, COUNT(t1.id) as total,
SUM(t1.submit_date IS NULL) AS num_incomplete,
SUM(IF(table_1.submit_date IS NULL,DATEDIFF(table_1.due_date,now()),0)) / COUNT(IF(table_1.submit_date IS NULL,1,NULL)) as avg_incomplete_due_in
SUM(IF(table_1.submit_date IS NOT NULL,DATEDIFF(table_1.due_date,submit_date),0)) / COUNT(IF(table_1.submit_date IS NOT NULL,1,NULL)) as avg_complete_turnaround
FROM table_1
INNER JOIN table_2 t2 ON t2.fid = t1.id
WHERE t1.due_date <= '2010-12-31'
GROUP BY t2.lender_name
Related
In MySQL, how would you re-write a SELECT query which JOIN SELECT subqueries that are doing almost the same thing.
In my case, I am getting performance issues because in the subqueries, I need to join on the same tables for each subqueries which is an heavy operation.
Consider the below (ugly) example:
set #businessdate = '2020-01-24';
Select Daily.*, Monthly.Price, Yearly.Price FROM
# DAILY
(Select #businessdate as BusinessDate, t1.Owner , SUM(t.Price) AS DailyPrice
FROM Table t
INNER JOIN Table2 t2 on ...
INNER JOIN Table1 t1 on ...
where t2.date = #businessdate
GROUP BY t1.Owner) Daily
INNER JOIN
# MONTHLY
(Select SUM(t.Price) AS Price, t1.Owner
FROM Table t
INNER JOIN Table2 t2 on ...
INNER JOIN Table1 t1 on ...
where MONTH(t2.date) = MONTH(#businessdate) and YEAR(t2.date) = YEAR(#businessdate)
GROUP BY t1.Owner) Monthly
INNER JOIN
#YEARLY
(Select SUM(t.Price) AS Price, t1.Owner
FROM Table t
INNER JOIN Table2 t2 on ...
INNER JOIN Table1 t1 on ...
where YEAR(t2.date) = YEAR(#businessdate)
GROUP BY t1.Owner) Yearly
The reason is I need the date in my where clause (coming from t2), and one field in my group by coming from t1. I also need to display some fields from t1.
I only need the SUM(Price) (the Price from Monthly and Yearly...) so to me it sounds like the joins in subqueries is overkill even if it is working fine (very slow...)
You could use conditional aggregation with a single query:
Select
#businessdate as BusinessDate, ... ,
SUM(CASE WHEN t2.date = #businessdate THEN t.Price ELSE 0 END) AS DailyPrice,
SUM(CASE WHEN MONTH(t2.date) = MONTH(#businessdate) AND
YEAR(t2.date) = YEAR(#businessdate)
THEN t.Price ELSE 0 END) AS MonthlyPrice,
SUM(CASE WHEN YEAR(t2.date) = YEAR(#businessdate)
THEN t.Price ELSE 0 END) AS AnnualPrice
FROM Table t
INNER JOIN Table2 t2 on ...
INNER JOIN Table1 t1 on ...
GROUP BY t1.Owner
This at least would allow you to avoid unneeded passes over the joined tables. Note that your GROUP BY clause is invalid as written; the business date is the only valid single column which can be selected, other than the conditional sums.
SELECT t1.name as r_name, t1.values as r_values
FROM table as t1
JOIN (
SELECT SUM(amount) as amount
FROM database2.table
WHERE ids IN (t1.values)
) as t2
WHERE t1.id = 20;
I get an error, that t1.values inside the subquery is unknown column.
You need to rewrite your query and take inne where to join condition:
SELECT t1.name as r_name, t1.values as r_values
FROM table as t1
JOIN (
SELECT SUM(amount) as amount
FROM database2.table
) as t2 ON t2.ids = t1.values
WHERE t1.id = 20;
Also, you don't use amount column, so what is the point of join?
Another issue, you don't have any join condition defined.
I think you need to read about joins in SQL first :)
It seems you are trying to join database2.table to your t1 based on t1.values list.
I added group by IDs in t2 since your using aggregation function. Then, not sure what's the purpose of your sum(amount)
SELECT t1.name as r_name, t1.values as r_values
FROM table as t1
JOIN (
SELECT SUM(amount) as amount, ids
FROM database2.table
GROUP BY ids
) as t2 on t2.ids IN (t1.values)
WHERE t1.id = 20;
I have got this query, which works fine:
SELECT t1.*, t2.ip as ip
FROM table1 t1
INNER JOIN table2 t2 ON ( t2.id = t1.t2id )
ORDER BY t1.timestamp DESC
LIMIT 1000
What I would like to do is to:
1) get only those entries where the same ip occurs at least 3 times
2) group the entries by ip
So the result would look like this example:
IP TIMESTAMP
111.111.111.111 1500000000
111.111.111.111 1300000000
111.111.111.111 1100000000
222.222.222.222 1400000000
222.222.222.222 1300000000
222.222.222.222 1200000000
I have tried many approaches and I believe that this one is the closest,
but the result is 0 rows.
SELECT *, COUNT(DISTINCT ip) FROM (
SELECT t1.*, t2.ip as ip
FROM table1 t1
INNER JOIN table2 t2 ON ( t2.id = t1.t2id )
ORDER BY t1.timestamp DESC
LIMIT 1000
) AS tmp_table
GROUP BY ip
HAVING COUNT(DISTINCT ip) > 2
Please can someone shine some light on this?
Try this:
SELECT t1.*, (SELECT DISTINCT t2.ip FROM t2 WHERE t2.id = t1.t2id)
FROM t1
WHERE
(SELECT COUNT(*)
FROM t2
WHERE t2.id = t1.t2id) >= 3
Bacause in the comments has resulted table t2 with more rows for the same IP I change my query as follow:
SELECT t1.*, t2.ip
FROM t1
JOIN t2
ON t2.id = t1.t2id
WHERE
(SELECT COUNT(*)
FROM t2 tt2
WHERE t2.ip = tt2.ip) >= 3
You can see SqlFiddle
SELECT *, COUNT(ip) FROM (
SELECT t1.*, t2.ip as ip
FROM table1 t1
INNER JOIN table2 t2 ON ( t2.id = t1.t2id )
ORDER BY t1.timestamp DESC
LIMIT 1000
) AS tmp_table
GROUP BY ip
HAVING COUNT(ip) > 2
just remove distinct
You have to have the HAVING in the subquery
SELECT t1.*, t2.ip as ip
FROM table1 t1
INNER JOIN table2 t2 ON ( t2.id = t1.t2id )
INNER JOIN
(
SELECT t2.ip
FROM table1 t1
INNER JOIN table1 t2 ON ( t2.id = t2.t2id )
GROUP BY t2.ip
HAVING count(ip) > 2
) t ON t2.ip = t.ip
Try like this;
SELECT t2.ip as ip
FROM table1 t1
INNER JOIN table2 t2 ON ( t2.id = t1.t2id )
where t2.ip IN (SELECT ip FROM (
SELECT t2.ip as ip
FROM table1 t1
INNER JOIN table2 t2 ON ( t2.id = t1.t2id )
) AS tmp_table
GROUP BY ip
HAVING COUNT(*) > 2)
ORDER BY t1.timestamp DESC
LIMIT 1000
I have a query:
SELECT
t1.name as Name
count ( distinct t2.key ) as Total
SUM ( IF( t2.time = '12:00' , 1 , 0) ) as QttMidDay
FROM t1
LEFT JOIN t2 on t1.key = t2.key
GROUP BY t1.key
The question is, how i do the "Conditional Count" on the 2ยบ parameter SUM for QttMidDay ?
I am guessing that you can solve your problem by aggregating before the join. My best guess is:
SELECT t1.name as Name, t2.Total, t2.QttMidDay
FROM t1 LEFT JOIN
(SELECT COUNT(DISTINCT t2.key) as Total,
SUM(t2.time = '12:00') as QttMidDay
FROM t2
GROUP BY t2.key
) t2
ON t1.key = t2.key;
I am not sure if the COUNT(DISTINCT) is necessary in the subquery.
This is my table structure.
sometime table1 data my repeat (Ex : Actually Id 1 should have only 4 rows but sometime it is 8 due to duplication) so avoid duplication I use GROUP BY command in select query
Table 1
|id| website|time|
-----------------
|01|facebook|20.0|
|01|google |40.0|
|01|youtube |10.0|
|01|ebay |30.0|
|02|facebook|50.0|
|02|ebay |50.0|
Table 2
|id|marks|
-----------
|01| 80|
|02| 90|
|03| 70|
|04| 100|
I want to select (marks),(time on facebook) and (count of time on google & youtube) of specific user
Following select query gives (marks),(time on facebook) of user id '01'
How to receive count of time of both google and youtube of id'1' in same query ?
SELECT table2.id,table2.marks, table1.time
FROM table1
RIGHT JOIN table2 ON table1.id= table2.id
WHERE table1.website LIKE ('%facebook%')
AND table1.id= '01'
GROUP BY table1.id, table1.website
You want to find the time on facebook and then the sum of youtube and google for a particular user you can use the mysql conditional sum to achieve it
select
sum(case when t1.website = 'facebook' then t1.time else 0 end) as `fb_time`,
(
sum(case when t1.website='google' then t1.time else 0 end)+
sum(case when t1.website='youtube' then t1.time else 0 end)
)
as `google_youtube`,
t2.marks
from table1 t1
join table2 t2 on t1.id = t2.id
where t1.id = '01'
If you need to calculate the same for all the users then you can do it as
select
t1.id,
sum(case when t1.website = 'facebook' then t1.time else 0 end) as `fb_time`,
(
sum(case when t1.website='google' then t1.time else 0 end)+
sum(case when t1.website='youtube' then t1.time else 0 end)
)
as `google_youtube`,
t2.marks
from table1 t1
join table2 t2 on t1.id = t2.id
group by t1.id
If I understand your query correctly, I think you will need to use a subquery.
The following subquery returns two counts; time_on_facebook & time_on_google_and_youtube
for all users
SELECT t1.id, t2.marks,
COUNT(t1.time) as time_on_facebook,
(SELECT COUNT(t1_sq.time)
FROM `table1` as t1_sq
WHERE (t1_sq.website = "youtube" OR t1_sq.website = "google")
AND t1_sq.id = t1.id
GROUP BY t1.id) as time_on_google_and_youtube
FROM `table1` as t1
LEFT JOIN table2 t2 ON t2.id = t1.id
WHERE t1.website = "facebook"
GROUP BY t1.id
To restrict it to user id = 01, add in a WHERE clause
SELECT t1.id, t2.marks,
COUNT(t1.time) as time_on_facebook,
(SELECT COUNT(t1_sq.time)
FROM `table1` as t1_sq
WHERE (t1_sq.website = "youtube" OR t1_sq.website = "google")
AND t1_sq.id = t1.id
GROUP BY t1.id) as time_on_google_and_youtube
FROM `table1` as t1
LEFT JOIN table2 t2 ON t2.id = t1.id
WHERE t1.website = "facebook" AND t1.id = 1
GROUP BY t1.id
Are you sure you want COUNT(time) or do you want SUM(time)?
Lastly, consider adding a primary key to both tables and maybe rename the "id" column to "user_id" for clarity.
Its not clear what you want the output to look like. I made a query,
but did not try it. Try it and let me know if it works.
select t1.id, t1.website, sum(t1.time) as total_time, max(t2.marks) as marks
from table1 as t1
left join table2 as t2
on t1.id = t2.id
where t1.website = 'facebook'
and t1.id = '01'
group by t1.id, t1.website
UNION
select t1.id, t1.website, sum(t1.time) as total_time, max(t2.marks) as marks
from table1 as t1
left join table2 as t2
on t1.id = t2.id
where t1.website IN ('youtube', 'google')
and t1.id= '01'
group by t1.id, t1.website