MySQL view count and sum and other operations from multiple tables - mysql

Here is my situation:
I have 4 tables that all contains a column called score in all of these tables my goal for a view to create operations to the result of the 4 tables getting the following values:
Total score
Total number of rows
average (total score / number of rows)
Now i know that i would be able to create the view as:
(SELECT * FROM table1 where condition) + (SELECT * FROM table2 where condition)
So on and so forth.
but for each of the three goals i have i would have to nested select all tables atleast 2 times.
So my question is how do you handle a case like this? is there any operation in sql that makes this an easy task or am i bound to do something redundant?
Update
So my full case is that every use in my system has something called a division_id now i want to use this ID to find out what the score is for each division:
(PLEASE IGNORE THE _COPY)

You could use a UNION to join the 4 tables, since there is no join condition. There are a couple of ways that you could do this with the division field. Probably the most concise is:
select division_id, count(*), avg(scores.score), sum(scores.score) from
user join
(select id as user_id, score from user
UNION ALL
select user_id, score from test_score
UNION ALL
select user_id, score from task_score
UNION ALL
select user_id, score from offline_score) as scores
on user.id = scores.user_id
group by division_id
Link to SQLFiddle

Related

return the same record more than once in a query result

The following query:
SELECT * FROM table WHERE id IN (1,2,3);
will return three records.
SELECT * FROM table WHERE id IN (1,2,1);
will return just two records (for Ids 1 and 2)
Is there a way for the result set to contain two records for Id 1 (and three in total)?
You could try creating a table for the ids you want to filter by. This would get you your desired results. I'm not sure if mysql supports CTE, but hopefully this is enough for you to get the idea.
WITH IDS
AS
(
SELECT 1 AS id
UNION ALL
SELECT 2 AS id
UNION ALL
SELECT 1 AS id
)
SELECT T.*
FROM T
JOIN IDS
ON T.id = IDS.id

Count Distinct on multiple values within same column in SQL Aggregation

Objective:
I wanted to show the number of distinct IDs for any combination selected.
In the below example, I have data at a granular level: ID level data.
I wanted to show the number of distinct IDs for each combination.
For this, I use count distinct which will give me '1' for the below combinations.
But let's say if I wanted to find the number of IDs who made both E-commerce and Face to face transactions, in that case, if I just use this data, I would be showing the sum of E-comm and Face to face and the result would be '2' instead of '1'.
And this is not limited to Ecom/Face to face. I wanted to apply the same logic for all columns.
Please let me know if you have any other alternative approach to address this issue.
First aggregate in your table to get the distinct ids for each TranType:
SELECT TranType, COUNT(DISTINCT id) counter_distinct
FROM tablename
GROUP BY TranType
and then join to the table:
SELECT t.*, g.counter_distinct
FROM tablename t
INNER JOIN (
SELECT TranType, COUNT(DISTINCT id) counter_distinct
FROM tablename
GROUP BY TranType
) g ON g.TranType = t.TranType
Or use a correlated subquery:
SELECT t1.*,
(SELECT COUNT(DISTINCT t2.id) FROM tablename t2 WHERE t2.TranType = t1.TranType) counter_distinct
FROM tablename t1
But let's say if I wanted to find the number of IDs who made both E-commerce and Face to face transactions, in
You can get the list of ids using:
select id
from t
where tran_type in ('Ecomm', 'Face to face')
group by id
having count(distinct tran_type) = 2;
You can get the count using a subquery:
select count(*)
from (select id
from t
where tran_type in ('Ecomm', 'Face to face')
group by id
having count(distinct tran_type) = 2
) i;

How to get rows even if count is 0? Only 1 table

I want the count even if the count is 0. My current query is
SELECT `id`,count(0) as `fetchpc` FROM `user` WHERE pid in('4,6,7,8') GROUP BY `id`
But it returns only those id where count is greater than 0
Edit:
the values used for in('4,6,7,8') are first fetched from database in another query. And then using a script rows are converted to 4,6,7,8.
So all the values are present in the database.
Also it is possible that the values returned can go upto 100+ values.
You could left join this query on a "fictive" query that queries these IDs as literals:
SELECT ids.id, COALESCE(cnt, 0)
FROM (SELECT 4 AS id
UNION ALL
SELECT 6 AS id
UNION ALL
SELECT 7 AS id
UNION ALL
SELECT 8 AS id) ids
LEFT JOIN (SELECT id, COUNT(*) AS cnt
FROM fetchpc
GROUP BY id) t ON t.id = ids.id
You can use a derived table. I would recommend:
SELECT i.id, COUNT(u.id) as fetchpc
FROM (SELECT 4 as id UNION ALL
SELECT 6 as id UNION ALL
SELECT 7 as id UNION ALL
SELECT 8 as id
) i LEFT JOIN
`user` u
ON u.id = i.id
GROUP BY i.id;
From a performance perspective, this is much better than aggregating first (in a subquery) and then joining. Basically, the aggregation (in that case) has to aggregate all the data and afterwards filter out the unnecessary rows.
This formulation filters the rows first, which should speed the aggregation.

MySQL Getting most occurring Member from a table

Say I have a table that stores each and every time someone does something (let's say jumps)
The table has a JumpNumber (auto-increments each time there's an insert, so there's one for every jump rather than this being a total). It also records the member who jumped as MemberID, and the time they jumped at.
I would like to make a query that finds the most occurring member then gives their ID and every time at which they've ever jumped.
However, if there's 2 or more members with the most jumps (so a tie) it should still display each of them, with their jump times.
So I couldn't just do a descending order and limit to 1. I'm also confused as to how I should find the most reoccurring member, I'm guessing a COUNT but not 100% sure how.
Well it would be something like:
SELECT USER_ID
FROM YOURTABLE A
WHERE JUMPS = (SELECT MAX(JUMPS)
FROM YOURTABLE B)
This will return all USER_ID with the most Jumps, then you can select all records where the selectes user(s) made something
If you store jumps, use variant by Xavjer
If you not store jumps, first you have find max count
select user_id, count(*) as c from TABLE group by user_id order by c desc limit 1
After that you have do same grouping again and select all user_id with that count and left join original table for other fields.
select A.* from (
select user_id from
(select user_id, count(*) as c from TABLE group by user_id) as tempB
) as tempC where tempC.c=(
select count(*) as c from TABLE group by user_id order by c desc limit 1
)
) as join_table1
LEFT JOIN TABLE as A on A.user_id=join_table1;

mysql get all records when looking for duplicates

I want to make a report of all the entries in a table where one column has duplicate entries. Let's assume we have a table like this:
customer_name | some_number
Tom 1
Steve 3
Chris 4
Tim 3
...
I want to show all the records that have some_number as a duplicate. I have used a query like this to show all the duplicate records:
select customer_name, some_number from table where some_number in (select some_number from table group by some_number having count(*) > 1) order by some_number;
This works for a small table, but the one I actually need to operate on is fairly large. 30,000 + rows and it is taking FOREVER! Does someone have a better way to do this?
Thanks!
Try this query:
SELECT t1.*
FROM (SELECT some_number, COUNT(*) AS nb
FROM your_table
GROUP BY some_number
HAVING nb>1
) t2, your_table t1
WHERE t1.some_number=t2.some_number
The query first uses GROUP BY to find duplicate records, then joins with the table to retrieve all fields.
Since HAVING is used, it will return only the records you are interested in, then do the join with your_table.
Be sure your table has an index on some_number if you want the query to be fast.
Does this perform better? It joins on a table of some_number counts and then filters to include only those with a count > 1.
SELECT t.customer_name, t.some_number
FROM my_table t
INNER JOIN (
SELECT some_number, COUNT(*) AS ct
FROM my_table
GROUP BY some_number ) dup ON t.some_number = dup.some_number
WHERE dup.ct > 1