I have the following query which is returning total number of entries in the requests column in the requests table for each given user, rather than the number of requests marked as played for any given user.
SELECT
t1.status, t1.FirstName
t2.CountPlayed
FROM
RequestsTable t1
INNER JOIN
(SELECT t1.FirstName, Count(t1.status ='played') AS CountPlayed
FROM RequestsTable t1
GROUP BY t1.FirstName)
t2 ON t1.FirstName = t2.FirstName
WHERE t1.status = 'played'
Desired results: eg
Fred: 2 (played out of total 6 requests)
Ginger: 1 (played out of total 4 requests)
Lenny: 2 (played out of total 3 requests)
Actual results:
Fred = 6
Ginger = 4
Lenny = 3
That count isn't working the way you think it is. You need to filter using where first.
...
INNER JOIN
(SELECT t1.FirstName, count(*) AS CountPlayed
FROM RequestsTable t1
WHERE t1.status = 'played'
GROUP BY t1.FirstName)
....
Actually you can further simplify the whole thing to just one query:
SELECT
t1.FirstName, count(*)
FROM
RequestsTable t1
WHERE t1.status = 'played'
GROUP BY t1.FirstName;
Try SUM instead of COUNT. COUNT counts 0/false; it only ignores NULL.
Related
I'm new to MySQL, and I'd like some help in setting up a MySQL query to pull some data from a few tables (~100,000 rows) in a particular output format.
This problem involves three SQL tables:
allusers : This one contains user information. The columns of interest are userid and vip
table1 and table2 contain data, but they also have a userid column, which matches the userid column in allusers.
What I'd like to do:
I'd like to create a query which searches through allusers, finds the userid of those that are VIP, and then count the number of records in each of table1 and table2 grouped by the userid. So, my desired output is:
userid | Count in Table1 | Count in Table2
1 | 5 | 21
5 | 16 | 31
8 | 21 | 12
What I've done so far:
I've created this statement:
SELECT userid, count(1)
FROM table1
WHERE userid IN (SELECT userid FROM allusers WHERE vip IS NOT NULL)
GROUP BY userid
This gets me close to what I want. But now, I want to add another column with the respective counts from table2
I also tried using joins like this:
select A.userid, count(T1.userid), count(T2.userid) from allusers A
left join table1 T1 on T1.userid = A.userid
left join table2 T2 on T2.userid = A.userid
where A.vip is not null
group by A.userid
However, this query took a very long time and I had to kill the query. I'm assuming this is because using Joins for such large tables is very inefficient.
Similar Questions
This one is looking for a similar result as I am, but doesn't need nearly as much filtering with subqueries
This one sums up the counts across tables, while I need the counts separated into columns
Could someone help me set up the query to generate the data I need?
Thanks!
You need to pre-aggregate first, then join, otherwise the results will not be what you expect if a user has several rows in both table1 and table2. Besides, pre-aggregation is usually more efficient than outer aggregation in a situation such as yours.
Consider:
select a.userid, t1.cnt cnt1, t2.cnt cnt2
from allusers a
left join (select userid, count(*) cnt from table1 group by userid) t1
on t1.userid = a.userid
left join (select userid, count(*) cnt from table2 group by userid) t2
on t2.userid = a.userid
where a.vip is not null
This is a case where I would recommend correlated subqueries:
select a.userid,
(select count(*) from table1 t1 where t1.userid = a.userid) as cnt1,
(select count(*) from table2 t2 where t2.userid = a.userid) as cnt2
from allusers a
where a.vip is not null;
The reason that I recommend this approach is because you are filtering the alllusers table. That means that the pre-aggregation approach may be doing additional, unnecessary work.
I have a web page that displays requests received by each user (Firstname) that are separated into 1 of 4 lists based on 4 separate queries which rely on a WHERE statement to check the value of the ‘status’ column (incoming, playlisted, sidelisted, played).
This solution works for the ‘played’ list.
SELECT
t1.FirstName, count(*)
FROM
RequestsTable t1
WHERE t1.status = 'played'
GROUP BY t1.FirstName;
but the WHERE statement doesn’t allow it to work for requests that are in the other 3 lists.
Two counts are required within each of the 4 lists to show
i) the total number of requests made by each user.
ii) the number of requests made by each user that have been ’played’.
All of my attempts to use JOINS and CASE statements have been defeated by the WHERE statement which limits the counts to the records within any 1 of the 4 lists.
Remove the WHERE statement and put the status conditions in the COUNT:
SELECT
t1.FirstName,
count(*) as totalCount,
count(IF(t1.status = 'played',1,null)) as playedCount
FROM
RequestsTable t1
GROUP BY t1.FirstName;
SELECT
t1.FirstName, count(*) cnt ,0 played,0 played2
FROM
RequestsTable t1
GROUP BY t1.FirstName
union
SELECT
t1.FirstName, 0 cnt ,count(*) played,0 played2
FROM
RequestsTable t1
WHERE t1.status = 'played'
GROUP BY t1.FirstName
union
SELECT
t1.FirstName, 0 cnt,0 played ,count(*) played2
FROM
RequestsTable t1
WHERE t1.status = 'played2'
GROUP BY t1.FirstName
Try above query.
Hope this will helps.
I have 2 tables one with inventory and other with prices list on different dates. I need to update table 1 with price on a particular date which may not be available in table 2 so i need to lookback on last available price. How can I do this. Following are my tables:
Table1
SrNo Commodity Date Price
1 Car 20-Aug-2015 <115>
2 Cycle 20-Aug-2015 <78>
Table2
SrNo Commodity Price Date
1 Car 100 1-Jan-2015
2 Car 120 1-Jun-2015
3 Car 115 20-Aug-2015
4 Cycle 80 10-May-2015
5 Cycle 78 10-Jun-2015
I tried using an inner join but I could get it for Car since it has an entry on 20-Aug-2015. I want cycle to be shown as 78 as it was the last available price.
Can someone suggest me how to do this.
Thanks,
Swati
Next code will work on T-SQL - try so
update t1 set
t1.Price = t2.Price
from Table1 as t1
outer apply (
select top 1
t2.Price
from Table2 as t2
where t2.SrNo = t1.SrNo
order by t2.Date desc
) t2
Try this:
UPDATE a
SET a.Price = b.Price
FROM Table1 a
INNER JOIN Table2 b ON a.Commodity = b.Commodity
WHERE b.[Date] = (SELECT MAX([Date])
FROM Table2 c
WHERE b.Commodity = c.Commodity
AND c.[Date] <= a.[Date]
GROUP BY c.Commodity)
For MySql
UPDATE Table1
JOIN ( SELECT Commodity,Price
FROM Table2 JOIN (SELECT Table2.Commodity,MAX(DATE) As LastDate
FROM Table2
GROUP BY Commodity ) AS Tmp1
ON Table2.Date = Tmp1.LastDate
) AS Tmp2
ON Tmp2.Commodity = Table1.Commodity
SET Table1 .Price = Tmp2.Price
MAX(DATE) is calculated in inner query Tmp1 to get last availaible price of commodity
SQLFiddle Demo
I'm trying to get count of duplicate data, but my query doesn't work correctly.
Every user should have one dev_id but when other user will have this same dev_id I want to know this
Table for example:
dev_id user_id
------------------
111 1
111 1
222 2
111 2
333 3
Should result:
user_id qu
------------------
1 1
2 1
3 0
This is my query
SELECT t1.user_id,
(SELECT Count(DISTINCT t2.dev_id)
FROM reports t2
WHERE t2.user_id != t1.user_id
AND t2.dev_id = t1.dev_id
) AS qu
FROM reports t1
GROUP BY t1.user_id
You can get results by doing:
select r.user_id, count(*) - 1
from reports r
group by r.user_id;
Is this the calculation that you want?
Okay. Let start from simple.
First you need get unique user_id/dev id combinations
select distinct dev_id,user_id from reports
Result will be
dev_id user_id
------------------
111 1
222 2
111 2
333 3
After that you should get number of different user_id per dev_id
select dev_id,c from (
SELECT
dev_id,
count(*)-1 AS c
FROM
(select distinct user_id,dev_id from reports) as fixed_reports
GROUP BY dev_id
) as counts
Result of such query will be
dev_id c
-----------------
111 1
222 0
333 0
Now you should show users which have such dev_id. For that you should join such dev_id list with table from step1(which show which one user_id,dev_id pairs exist)
select distinct fixed_reports2.user_id,counts.c from (
SELECT
dev_id,
count(*)-1 AS c
FROM
(select distinct user_id,dev_id from reports) as fixed_reports
GROUP BY dev_id
) as counts
join
(select distinct user_id,dev_id from reports) as fixed_reports2
on fixed_reports2.dev_id=counts.dev_id
where counts.c>0 and counts.c is not null
"Distinct" here need to skip same rows.
Result should be for internal query
dev_id c
-----------------
111 1
For all query
user_id c
------------------
1 1
2 1
If you sure you need also rows with c=0, then you need do "left join" of fixed_reports2 and large query,that way you will get all rows and rows with c=null will be rows with 0(can be changed by case/when statement)
I think following sql query should solve you problem:
SELECT t1.user_id, t1.dev_id, count(t2.user_id) as qu
FROM (Select Distinct * from reports) t1
Left Join (Select Distinct * from reports) t2
on t1.user_id != t2.user_id and t2.dev_id = t1.dev_id
group by t1.user_Id, t1.dev_id
SQL Fiddle Link
SELECT user_id, (COUNT(user_id) -1) as qu
FROM reports
GROUP BY user_id
This would give desired result in your case, however you can improve it a lot more.
Cheers,,
Your query is broken and would not run on many systems. The problem is that the group with user_id of 2 has two different dev_ids. If you run the "broken query" below you can see that the min() and max() are distinct but the subquery only sees one of those values which is randomly chosen. The last query is corrected by adding dev_id to the groupings which shows you where the "missing" row went in the counts.
SELECT -- broken query
t1.user_id, min(t1.dev_id), max(t1.dev_id),
(select distinct t1.dev_id from reports) as should_have_errored,
(SELECT Count(DISTINCT t2.dev_id)
FROM reports t2
WHERE t2.user_id != t1.user_id
AND t2.dev_id = t1.dev_id
) AS qu
FROM reports t1
GROUP BY t1.user_id;
-- On SQL Server that query returns an error
-- Msg 8120, Level 16, State 1, Line 7
-- Column 'reports.dev_id' is invalid in the select list because it is
-- not contained in either an aggregate function or the GROUP BY clause.
SELECT -- query that duplicates your original query
t1.user_id,
(SELECT Count(DISTINCT t2.dev_id)
FROM reports t2
WHERE t2.user_id != t1.user_id
AND t2.dev_id = max(t1.dev_id) /* <-- see here */
) AS qu
FROM reports t1
GROUP BY t1.user_id;
SELECT t1.user_id, t1.dev_id, -- fixed query
(SELECT Count(DISTINCT t2.dev_id)
FROM reports t2
WHERE t2.user_id != t1.user_id
AND t2.dev_id = t1.dev_id
) AS qu
FROM reports t1
GROUP BY t1.user_id, t1.dev_id
http://sqlfiddle.com/#!9/6576e3/20
Here are some queries that might be useful:
Which dev_ids have multiple user_ids associated with them?
select dev_id
from reports
group by dev_id
having count(distinct user_id) > 1
Which other user_ids share a dev_id with this user_id?
select user_id
from reports r1
where exists (
select 1
from reports r2
where r2.dev_id = r1.dev_id and r2.user_id <> ?
)
Or really that's just equivalent to an inner join which also makes it easy to list everybody at once. Note that each pair will be listed twice:
select r1.user_id, r1.dev_id, r2.user_id as common_user_id
from
reports r1 inner join reports r2
on r2.dev_id = r1.dev_id
where
r1.user_id <> r2.user_id
order by
r1.user_id, r1.dev_id, r2.user_id
And since you've got duplicate rows in your table you'd need to make it select distinct to get unique rows.
Try
SELECT
user_id,
SUM(qu) AS qu
FROM (
SELECT
user_id,
count(*)-1 AS qu
FROM
reports
GROUP BY user_id, dev_id
) AS r
GROUP BY user_id
No need to do a join if all the data you need is in one table.
Edit: changed the group by to dev_id instead of user_id
Edit2: I think you need both dev_id and user_id in the group by clause.
Edit3: Added a subquery to get the desired result. This might be a little cumbersome, perhaps someone has a way to improve this?
I have the following table:
A FromA User
1 NULL Bob
2 1 Bob
3 1 Chris
4 2 Chris
User is the name of the person who created item A. FromA is the source that the User grabbed it from.
I want to figure out is Chris' most frequency source.
My query
SELECT count(T1.A GROUP BY T1.User), T1.User
FROM Table T0
INNER JOIN Table T1 ON T0.FromA=T1.A
WHERE T0.User='Chris'
It should return Bob=2. But it doesn't seem to work.
Try this:
select t2.user, count(*) Total from t t1
join t t2 on t1.fromA = t2.a
where t1.user = 'Chris'
group by t2.user
order by Total desc
limit 1
The limit 1 will give you just the most frequently used source.
Edit:
inner join will fail to fetch record=>1 | NULL | Bob as 'fromA' column has null value. so, switch to left join – Angelin Nadar
Nope. Here is a working example
You just have your group by in the wrong place. This should work
SELECT count(T1.A ), T1.User
FROM Table T0
INNER JOIN Table T1 ON T0.FromA=T1.A
WHERE T0.User='Chris'
GROUP BY T1.User
Try with this, I have changed table aliases:
SELECT count(*), t_User.User
FROM
Table t_FromA
LEFT OUTER JOIN
Table t_User
ON t_User.FromA=t_FromA.A
WHERE t_FromA.User='Chris'