get count from multiple tables - mysql

I have 3 tables with a common 'type_id' column. its a foreign key from Table_type
Table_1 id,type_id,date...
Table_2 id,type_id,date...
Table_3 id,type_id,date...
Table_Type id, type_name, description
select type_id, count(*) from Table_1 GROUP BY type_id
gives the count from individual table.
i want to know how many times is a particular type used.
type_id, count(from 3 tables)
1 , 10
2 , 5
3 . , 3

Use union all and group by:
select type_id, count(*)
from ((select type_id from table_1) union all
(select type_id from table_2) union all
(select type_id from table_3)
) t
group by type_id

Get the counts from each table, combine those queries with UNION, and add up the counts.
SELECT type_id, SUM(count)
FROM (
SELECT type_id, COUNT(*) AS count
FROM table_1
UNION ALL
SELECT type_id, COUNT(*) AS count
FROM table_2
UNION ALL
SELECT type_id, COUNT(*) AS count
FROM table_3
) AS x
GROUP BY type_id
If there are indexes on the type_id column, this query should be able to take advantage of them. And the UNION processes smaller tables because it combines after the grouping.

Related

Mysql Join query with count table records with same date

Hello i am having two different table with same field created_date (datetime)
now i want records which counts daywise records with joining table i have done for individual counting as below query :
SELECT DATE(created_date), COUNT(*) FROM table1 GROUP BY DAY(created_date)
SELECT DATE(created_date), COUNT(*) FROM table2 GROUP BY DAY(created_date)
and i am getting results for individuals something like this:
RESULT I NEED :
DATE(created_date) count(table1) count(table2)
2016-12-01 10 3
2016-12-02 1 0
2016-12-05 1 0
2016-11-29 1 0
2016-11-30 4 1
Now i just want to join these result WITH INDIVIDUAL VIEW COUNT ACCORDING TO TABLE can anyone please help me out with this profile....
First take a UNION between your two tables, then use conditional aggregation to determine the counts for each of the two tables. Note that I introduce a field called table_name to keep track of data from each of the two tables.
SELECT t.created_date,
SUM(CASE WHEN t.table_name = 'one' THEN 1 ELSE 0 END) AS count_table_one,
SUM(CASE WHEN t.table_name = 'two' THEN 1 ELSE 0 END) AS count_table_two
FROM
(
SELECT DATE(created_date) AS created_date, 'one' AS table_name
FROM table1
UNION ALL
SELECT DATE(created_date), 'two'
FROM table2
) t
GROUP BY t.created_date
I used DATE consistently everywhere to make the query correct.
Try This:
SELECT created_date, sum(countTable1) countTable1,
sum(countTable2) countTable2
FROM (
SELECT DATE(created_date) created_date, COUNT(*) countTable1, NULL countTable2
FROM table1 GROUP BY DAY(created_date)
UNION ALL
SELECT DATE(created_date) created_date, NULL, COUNT(*) countTable2
FROM table2 GROUP BY DAY(created_date)) t GROUP BY t.created_date
You have a problem in your queries, you are grouping by DAY(date) and showing 'date' so the result will be first date with day(date), yet repeating it to avoid misunderstanding :)
select IFNULL(A.cd, B.cd), A.cnt, B.cnt from
(SELECT DAY(created_date) d, DATE(created_date) cd, COUNT(*) cnt
FROM table1 GROUP BY DAY(created_date)) as A
LEFT JOIN
(SELECT DAY(created_date) d, DATE(created_date) cd , COUNT(*) cnt
FROM table2 GROUP BY DAY(created_date)) B ON B.d = A.d
Its not too hard just use union if no need to allow duplicate row else use union all for all(means allow duplicate as well).
SELECT DATE(created_date), COUNT(*) FROM table1 GROUP BY DAY(created_date)
UNION
SELECT DATE(created_date), COUNT(*) FROM table2 GROUP BY DAY(created_date)
SELECT T.create_date,ISNULL(T.count,0)AS Counttable1,ISNULL(X.count,0)AS Counttable2 FROM(SELECT DATE(created_date) AS create_date,COUNT(*) as count FROM table1 GROUP BY DAY(created_date)) AS T LEFTJOIN(SELECT DATE(created_date) AS create_date, COUNT(*) as count FROM table2 GROUP BY DAY(created_date))AS X ON T.create_date=X.create_date
You actually need a SQL UNION. JOIN natuarually eliminate counts becuase the maytch fields. I.e. if you had 2016-12-01 in both table1 andtable2 then a JOIN on created_date would give you a count of 1 instead of a count of 2.
SELECT DATE(total.created_date), COUNT(*)
FROM (
SELECT created_date FROM table1
UNION ALL
SELECT created_date FROM table2) as total
GROUP BY total.created_date
HERE you simply union the two tables since they have a matching column name. Then you get back every date from both tables. That is in the inner query. The outer query then does the counting.
Hope that makes sense.

MYSQL - Group By / Order By not working

I have the following data inside a table:
id person_id item_id price
1 1 1 10
2 1 1 20
3 1 3 50
Now what I want to do is group by the item ID, select the id that has the highest value and take the price.
E.g. the sum would be: (20 + 50) and ignore the 10.
I am using the following:
SELECT SUM(`price`)
FROM
(SELECT id, person_id, item_id, price
FROM `table` tbl
INNER JOIN person p USING (person_id)
WHERE p.person_id = 1
ORDER BY id DESC) x
GROUP BY item_id
However, this query is still adding (10 + 20 + 50), which is obviously not what I need to have.
Any ideas to where I am going wrong?
Here is what you are trying to achieve. First you need grouping in a subquery and not in outer query. In outer query you need only sum:
SELECT SUM(`price`)
FROM
(SELECT MAX(price) as price
FROM `table` tbl
INNER JOIN person p USING (person_id)
WHERE p.person_id = 1
GROUP BY item_id) x
http://sqlfiddle.com/#!9/40803/5
SELECT SUM(t1.price)
FROM tbl t1
LEFT JOIN tbl t2
ON t1.person_id= t2.person_id
AND t1.item_id = t2.item_id
AND t1.id<t2.id
WHERE t1.person_id = 1
AND t2.id IS NULL;
I'm not sure if this is the only requirement you have. If so, try this.
SELECT SUM(price)
FROM
(SELECT MAX(price)
FROM table
WHERE person_id = 1
GROUP BY item_id)
First of all - you don't need the person table, because the other table already contains the person_id. So i removed it from the examples.
Your query returns a sum of prices for each item.
If you replace SELECT SUM(price) with SELECT item_id, SUM(price) you wil get
item_id SUM(`price`)
1 30
3 50
But that is not what you want. Neither is it what you wrote in the question " (10 + 20 + 50)".
Now replacing the first line with SELECT id, item_id, SUM(price) you will get one row for each item with the highest id.
id item_id price
2 1 20
3 3 50
This works because of the "undocumented feature" of MySQL, wich allows you to select columns that are not listed in the GROUP BY clause and get the first row from the subselect each group (each item in this case).
Now you only need to sum the price column in an additional outer select
SELECT SUM(price)
FROM (
SELECT id, item_id ,price
FROM (
SELECT id, person_id, item_id, price
FROM `table` tbl
WHERE tbl.person_id = 1
ORDER BY id DESC ) x
GROUP BY item_id
) y
However i do not recomend to use that "feature". While it still works on MySQL 5.6, you never know if that will work with newer versions. It already doesn't work on MariaDB.
Instead you can determite the MAX(id) for each item in an subselect, select only the rows with the determined ids and get the summed price of them.
SELECT SUM(`price`)
FROM `table` tbl
WHERE tbl.id IN (
SELECT MAX(tbl2.id)
FROM `table` tbl2
WHERE tbl2.person_id = 1
GROUP BY tbl2.item_id
)
Another solution (wich internaly does the same) is
SELECT SUM(`price`)
FROM `table` tbl
JOIN (
SELECT MAX(tbl2.id) as id
FROM `table` tbl2
WHERE tbl2.person_id = 1
GROUP BY tbl2.item_id
) x ON x.id = tbl.id
Alex's solution also works fine, if the groups (number of rows per person and item) are rather small.
You have used group by in main query, but it is on subquery like
SELECT id, person_id, item_id, SUM(`price`) FROM ( SELECT MAX(price) FROM `table` tbl WHERE p.person_id = 1 GROUP BY item_id ) AS x

MySQL: check that a set of queries returns the same row count : : but I don't know what the count is

We read values from a set of sensors, occasionally a reading or two is lost for a particular sensor , so now and again I run a query to see if all sensors have the same record count.
GROUP BY sensor_id HAVING COUNT(*) != xxx;
So I run a query once to visually get a value of xxx and then run it again to see if any vary.
But is there any clever way of doing this automatically in a single query?
You could do:
HAVING COUNT(*) != (SELECT MAX(count) FROM (
SELECT COUNT(*) AS count FROM my_table GROUP BY sensor_id
) t)
Or else group again by the count in each group (and ignore the first result):
SELECT count, GROUP_CONCAT(sensor_id) AS sensors
FROM (
SELECT sensor_id, COUNT(*) AS count FROM my_table GROUP BY sensor_id
) t
GROUP BY count
ORDER BY count DESC
LIMIT 1, 18446744073709551615
SELECT sensor_id,COUNT(*) AS count
FROM table
GROUP BY sensor_id
ORDER BY count
Will show a list of the sensor_id along with a count of all the records it has, you can then manually check to see if any vary.
SELECT * FROM (
SELECT sensor_id,COUNT(*) AS count
FROM table
GROUP BY sensor_id
) AS t1
GROUP BY count
Will show all the counts that vary, but the group by will lose information about which sensor_ids have which counts.
---EDIT---
Taken a bit from both mine and eggyal's answer and created this, for the count that is most frequent I call the id default, and then for any values that stand out I have given them separate rows. This way you maintain the readability of a table if you have many results Multi Row, but also have a simple one row column if all counts are the same One Row. If however you are happy with the concocted strings then go with eggyal's answer.
Might be a bit over the top but here goes:
select 'default' as id,t5.c1 as count from(
select id,count(*) as c1 from your_table group by id having count(*)=
(select t4.count from
(
select max(t3.count2) as max,t3.count as count from
(
select count(*) as count2,t2.count from
(
SELECT id,COUNT(*) AS count
FROM your_table
GROUP BY id
) as t2
GROUP BY count
) as t3
) as t4)) as t5 group by count
union all
select t5.id as id,t5.c1 as count from(
select id,count(*) as c1 from your_table group by id having count(*)<>
(select t4.count from
(
select max(t3.count2) as max,t3.count as count from
(
select count(*) as count2,t2.count from
(
SELECT id,COUNT(*) AS count
FROM your_table
GROUP BY id
) as t2
GROUP BY count
) as t3
) as t4)) as t5

Selecting the frequency of a result that could appear in multiple columns (SQL)

I have a table with a list of names spread across five different columns. I'm trying to get the 6 most frequent distinct names. Each name will only appear in each record once. The five columns are name_1, name_2...name_5. And just for names sake call the table 'mytable'.
Any help would be much appreciated.
Here's one approach:
SELECT name, COUNT(1)
FROM ( SELECT name_1 AS name FROM mytable
UNION ALL SELECT name_2 AS name FROM mytable
UNION ALL SELECT name_3 AS name FROM mytable
UNION ALL SELECT name_4 AS name FROM mytable
UNION ALL SELECT name_5 AS name FROM mytable
) AS myunion
GROUP BY name
ORDER BY COUNT(1) DESC LIMIT 6
;
How many rows are there in the table?
try this:
SELECT iTable.iName, Count(iTable.iName) as TotalCount
FROM
(
SELECT DISTINCT name_1 as iName FROM myTable
UNION
SELECT DISTINCT name_2 as iName FROM myTable
UNION
SELECT DISTINCT name_3 as iName FROM myTable
UNION
SELECT DISTINCT name_4 as iName FROM myTable
UNION
SELECT DISTINCT name_5 as iName FROM myTable
) as iTable
GROUP BY iTable.iName
ORDER BY TotalCount DESC
LIMIT 6
You should be able to select all the names from each table and union the results together. Then you can count the number of times each name occurs.
select *
from
(
select name, count(*)
from (
select name from table1
union all
select name from table2
union all
select name from table3
union all
select name from table4
union all
select name from table5
)
group by name
order by count(*) desc
)
where rownum <= 6
UNION + subselect should work for you in this case.
SELECT name_1, COUNT(*) FROM (
SELECT name_1 FROM mytable
UNION ALL SELECT name_2 FROM mytable
UNION ALL SELECT name_3 FROM mytable
UNION ALL SELECT name_4 FROM mytable
UNION ALL SELECT name_5 FROM mytable
) AS names GROUP BY name_1 ORDER BY 2 DESC LIMIT 6;

Search in two tables and order by occurrence of term

I have this query to search in two SQL tables. I am looking for a way to sort the result by occurrence. This is my query:
SELECT `parent_id`
FROM wp_forum_posts
WHERE text LIKE '%{$term1}%'
UNION
SELECT `id`
FROM wp_forum_threads
WHERE subject LIKE '%{$term1}%
Which is the best way, to get the results ordered?
The trick is first to use UNION ALL, which preserves duplicates (ordinary UNION removes duplicates), then select from that result. This query should do it:
select * from (
select parent_id as mID, count(*) as cnt
from wp_forum_posts
where text like '%{$term1}%'
group by 1
UNION ALL
select id, count(*)
FROM wp_forum_threads
where subject like '%{$term1}%
group by 1) x
order by 2, 1
Assumes ID and parent_ID are not duplicates in tables otherwise you can get 2 rows per an id... and would you want them summed together if so then are parent_ID and ID related?
Select mID, cnt
FROM
(SELECT `parent_id` as mID, count(`parent_ID`) as cnt
FROM wp_forum_posts
WHERE text LIKE '%{$term1}%'
Group by `parent_ID`
UNION
SELECT `id`, count(`id`) as cnt
FROM wp_forum_threads
WHERE subject LIKE '%{$term1}%
GROUP BY `id`)
Order by cnt ASC, mID