Combine results of two unrelated queries into single view - mysql

Is it possible to combine the results of two separate (unrelated) sql queries into a single view. I am trying to total some figures for users and count the views for videos this month to display on a dashboard.
i.e.,
select count(*) from video where monthname(views) = 'May';
and
select sum(sessions) from user where user_id = 6;
I would like to create a view that combines that contains these two results.
Is this possible?

If you want the results next to each other in separate columns you can simply SELECT a list of queries:
SELECT ( select count(*) from video where monthname(views) = 'May') AS May_CT
,( select sum(sessions) from user where user_id = 6) AS User_Sum
If you want the results stacked in one column:
select count(*) from video where monthname(views) = 'May'
UNION ALL
select sum(sessions) from user where user_id = 6
The latter may require datatype conversion

SELECT t2.total_session,
t1.watch_count
FROM
(SELECT 1 AS common_key,
count(*) AS watch_count
FROM video
WHERE monthname(views) = 'May') AS t1
JOIN
(SELECT 1 AS common_key,
sum(sessions) AS total_session
FROM USER
WHERE user_id = 6) AS t2 ON t1.common_key = t2.common_key;
Ofcourse, this will be very efficient only when the output in both t1 and t2 is one row.

Related

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 view count and sum and other operations from multiple tables

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

MySQL query join, select on two columns, not equal on another column

My working query is below. However, the results from that query will produce duplicates AND non duplicates on name column. I want to be able to only show results where name columns from the two select queries are different
select t.*
from tbl_user_tmp t JOIN
(select activity, class, count(*) as NumDuplicates
from tbl_user_tmp
where user = 'bignadad2'
group by activity, class
having NumDuplicates > 1)
tsum ON t.activity = tsum.activity and t.class = tsum.class
columns are in this order
id, name, activity, class, activity_id
I only want to show these results where activity, class match and name does not.
2059 lg_lmk com.lge.lmk com.lge.lmk.activities.LmkMainActivity 48255
3668 task_manager com.lge.lmk com.lge.lmk.activities.LmkMainActivity 48255
These are the other results i do not want to see
2690 phone com.modoohut.dialer com.modoohut.dialer.DialActivity 54700
2694 phone com.modoohut.dialer com.modoohut.dialer.DialActivity 54700
I forgot that you needs only some results
SELECT * FROM tbl_user_tmp AS t1
INNER JOIN (
SELECT activity, class, COUNT(1) AS cnt FROM tbl_user_tmp
WHERE user = 'first'
GROUP BY activity, class
HAVING cnt > 1
) AS t2
ON t1.activity = t2.activity AND t1.class = t2.class
WHERE user = 'first' -- remove records of the other users
GROUP BY t1.name, t1.activity, t1.class -- select distinct records
SQLFiddle
If class is unique in the activity then you can remove activity from the GROUP BY-statement.

Obtain a list with the items found the minimum amount of times in a table

I have a MySQL table where I have a certain id as a foreign key coming from another table. This id is not unique to this table so I can have many records holding the same id.
I need to find out which ids are seen the least amount of times in this table and pull up a list containing them.
For example, if I have 5 records with id=1, 3 records with id=2 and 3 records with id=3, I want to pull up only ids 2 & 3. However, the data in the table changes quite often so I don't know what that minimum value is going to be at any given moment. The task is quite trivial if I use two queries but I'm trying to do it with just one. Here's what I have:
SELECT id
FROM table
GROUP BY id
HAVING COUNT(*) = MIN(SELECT COUNT(*) FROM table GROUP BY id)
If I substitute COUNT(*) = 3, then the results come up but using the query above gives me an error that MIN is not used properly. Any tips?
I would try with:
SELECT id
FROM table
GROUP BY id
HAVING COUNT(*) = (SELECT COUNT(*) FROM table GROUP BY id ORDER BY COUNT(*) LIMIT 1);
This gets the minimum selecting the first row from the set of counts in ascendent order.
You need a double select in the having clause:
SELECT id
FROM table
GROUP BY id
HAVING COUNT(*) = (SELECT MIN(cnt) FROM (SELECT COUNT(*) as cnt FROM table GROUP BY id) t);
The MIN() aggregate function is suposed to take a column, not a query. So, I see two ways to solve this:
To properly write the subquery, or
To use temp variables
First alternative:
select id
from yourTable
group by id
having count(id) = (
select min(c) from (
select count(*) as c from yourTable group by id
) as a
)
Second alternative:
set #minCount = (
select min(c) from (
select count(*) as c from yourTable group by id
) as a
);
select id
from yourTable
group by id
having count(*) = #minCount;
You need to GROUP BY to produce a set of grouped values and additional select to get the MIN value from that group, only then you can match it against having
SELECT * FROM table GROUP BY id
HAVING COUNT(*) =
(SELECT MIN(X.CNT) AS M FROM(SELECT COUNT(*) CNT FROM table GROUP BY id) AS X)