Show max to min count in SQL group by - sql

I have a table with id, Name columns.
When selecting I want to group by on Name column (but show all records NO summary), and show result count max number of in one grouping to min number of one grouping.
SELECT Table1.id, Table1.name
FROM Table1
GROUP BY Table1.id, Table1.name;
This is table:
My idea:
but I get this result:

One approach uses a join to a subquery which finds the counts for each name:
SELECT a.name, a.ID
FROM Table1 AS a
INNER JOIN
(
SELECT name, COUNT(*) AS cnt
FROM Table1
GROUP BY name
) AS b
ON a.name = b.name
ORDER BY
b.cnt DESC,
a.ID;

When you group by ID you create a separate group for each element, because each element has a unique ID. To get the count of each name group, you will want to create a grouping by name and then join it with your original table so the values are preserved. Something like:
WITH Counts (name, cnt) AS
(SELECT name, COUNT(*)
FROM Table1
GROUP BY name)
SELECT Table1.id, Table1.name
FROM Table1, Counts
INNER JOIN Counts
ON Table1.name = Counts.name
ORDER BY Counts.cnt DESC

Oh, I see. You an use a subquery in the order by:
select t.*
from t
order by (select count(*) from t t2 where t2.name = t.name) desc, name;
Note that name is the second order by key. If two names have the same counts, then this keeps all the rows for a given name together.

Related

Count the Same Columns in Two Differnt Table

I am looking for a way to count for the same column in two different tables.
So I have two tables, table1 and table2. They both have the column "category". I want to find a way to count category for these two tables and show as the result below.
I know how to do this individually by
select category, count(category) as cnt from table1
group by category
order by cnt desc
select category, count(category) as cnt from table2
group by category
order by cnt desc
Not sure how to combine the two into one.
The expected result should be like below. Please note there are some "category" in table1 but not in table2 or vice versa, for example category c and d.
table1 table2
a 4 2
b 4 3
c 3
d 4
One method is full join:
select coalesce(t1c.category, t2c.category) as category,
t1c.t1_cnt, t2c.t2_cnt
from (select category, count(*) as t1_cnt
from table1
group by category
) t1c full join
(select category, count(*) as t2_cnt
from table2
group by category
) t2c
on t1c.category = t2c.category;
You need to be very careful that you aggregate before doing the join.

Joining tables + SUM & GROUP BY function

I'm struggling in joining tables together with SUM and GROUP BY function. The query below works fine:
select ID, sum(amount)
from table1
group by ID
having sum(amount) between 1000 and 10000
As table1 only includes customer ID, I also need to join table CUSTOMERS, which contain customer name (column NAME). Following query will not work for me anymore:
select ID, name, sum(amount)
from table1
left join customers on table1.ID = customers.ID2
group by ID
having sum(amount) between 1000 and 10000
Ditching SUM and GROUP BY functionality does "fix" the issue as also column NAME will be available in the result, however I still need to sum and group the AMOUNT based on ID. How should I join the other table in this case to also present field NAME from table CUSTOMERS?
Column NAME or expression in SELECT list not valid'
is currently given as error message.
It needs to be in the group by:
select t1.ID, c.name, sum(t1.amount)
from table1 t1 left join
customers c
on t1.ID = c.ID2
group by t1.ID, c.name;
Note the use of table aliases.
Add "name" in group by clause
select table1.ID, customers.name, sum(table1.amount) amount
from table1,customers on table1.ID = customers.ID2
group by table1.ID,customers.name
try it
select t.ID, c.name, sum(t.amount)
from table1 t
left join customers c on table1.ID = customers.ID2
group by t.ID, c.name
having sum(t.amount) between 1000 and 10000
or without having depends on your requirement

SQL - Using GROUP BY and MIN COUNT to return the least counted variable

I'm having trouble using GROUP BY, MAX, and COUNT.
I have 3 tables, t1, t2, t3 with nutrition data.
t1 contains userid
t2 contains food and the type of food. (fruit, meat, etc)
t3 records each time userid eats food, so userid, food
How do you write a (Postgres) query that returns only the userid and the least eaten type of food?
I keep getting stuck on GROUP BY because of aggregations that create combinations of each type of food. Any hints on how I should approach this?
select userid, max(c_type) as MaxType
From (Select userid, count(type) as c_type
from t1 inner join t3 on t1.userid = t3.userid
inner join t2 on t2.food = t3.food
group by userid) as T
group by userid
If you want the least often eaten food type for each user, first count occurrences by user AND type, then you need to use a rank function to determine which of those food types has the lowest count. I'm not going to bother writing out all the joins, but this pseudocode should help:
select user_id, type, type_total
from ( select user_id, type, type_total,
rank(type_total) over (partition by user_id, type order by type_total) rn
from ( select user_id, type, count(t3 identifier) type_total
from [insert all the tables and joins here]
group by user_id, type ) x
) y
where y.rn = 1
This method uses the ROW_NUMBER window function with an ascending sort on the count of food items eaten grouped by the type to determine the least eaten. If there is a tie, a random one of the least types will be selected. Using RANK like in #htf's solution posted will return all ties.
select userid, type from (
select t3.userid, t2.type, count(*) as eaten,
row_number() over(partition by t3.userid order by count(t3.food) asc) AS r
from t3 join t2 on t3.food=t2.food
group by 1,2
) least
where r=1
Assuming you want something out of t1 would be like:
select t1.name, least.type from (
select t3.userid, t2.type, count(*) as eaten,
row_number() over(partition by t3.userid order by count(t3.food) asc) AS r
from t3 join t2 on t3.food=t2.food
group by 1,2
) least
join t1 on t1.userid=least.userid
where least.r=1
Here is a way to do it without the window function. This way uses a self join on the counts of types eaten to identify the least eaten and filter the other more frequently eaten foods (added t1 assuming you want some field out of there):
with type_counts as (
select t3.userid, t2.type, count(*) as eaten,
from t3 join t2 on t3.food=t2.food
group by 1,2
)
select t1.username, tc.userid, tc.type
from type_counts tc
inner join (select userid, min(eaten) as eaten from type_counts group by 1) mintc
on tc.userid=mintc.userid and tc.eaten=mintc.eaten
inner join t1 on t1.userid=tc.userid
This version will include ties for least eaten.

SQL Query with Join, Count and Where

I have 2 tables and am trying to do one query to save myself some work.
Table 1: id, category id, colour
Table 2: category id, category name
I want to join them so that I get id, category id, category name, colour
Then I want to limit it so that no "red" items are selected (WHERE colour != "red")
Then I want to count the number of records in each category (COUNT(id) GROUP BY (category id).
I have been trying:
SELECT COUNT(table1.id), table1.category_id, table2.category_name
FROM table1
INNER JOIN table2 ON table1.category_id=table2.category_id
WHERE table1.colour != "red"
But it just doesn't work. I've tried lots of variations and just get no results when I try the above query.
You have to use GROUP BY so you will have multiple records returned,
SELECT COUNT(*) TotalCount,
b.category_id,
b.category_name
FROM table1 a
INNER JOIN table2 b
ON a.category_id = b.category_id
WHERE a.colour <> 'red'
GROUP BY b.category_id, b.category_name
SELECT COUNT(*), table1.category_id, table2.category_name
FROM table1
INNER JOIN table2 ON table1.category_id=table2.category_id
WHERE table1.colour <> 'red'
GROUP BY table1.category_id, table2.category_name
I have used sub-query and it worked great!
SELECT *,(SELECT count(*) FROM $this->tbl_news WHERE
$this->tbl_news.cat_id=$this->tbl_categories.cat_id) as total_news FROM
$this->tbl_categories

SQL Select Distinct with Conditional

Table1 has columns (id, a, b, c, group). There are several rows that have the same group, but id is always unique. I would like to SELECT group,a,b FROM Table1 WHERE the group is distinct. However, I would like the returned data to be from the row with the greatest id for that group.
Thus, if we have the rows
(id=10, a=6, b=40, c=3, group=14)
(id=5, a=21, b=45, c=31, group=230)
(id=4, a=42, b=65, c=2, group=230)
I would like to return these 2 rows:
[group=14, a=6,b=40] and
[group=230, a=21,b=45] (because id=5 > id=4)
Is there a simple SELECT statement to do this?
Try:
select grp, a, b
from table1 where id in
(select max(id) from table1 group by grp)
You can do it using a self join or an inner-select. Here's inner select:
select `group`, a, b from Table1 AS T1
where id=(select max(id) from Table1 AS T2 where T1.`group` = T2.`group`)
And self-join method:
select T1.`group`, T2.a, T2.b from
(select max(id) as id,`group` from Table1 group by `group`) T1
join Table1 as T2 on T1.id=T2.id
2 selects, your inner select gets:
SELECT MAX(id) FROM YourTable GROUP BY [GROUP]
Your outer select joins to this table.
Think about it logically, the inner select gets a sub set of the data you need.
The outer select inner joins to this subset and can get further data.
SELECT [group], a, b FROM YourTable INNER JOIN
(SELECT MAX(id) FROM YourTable GROUP BY [GROUP]) t
ON t.id = YourTable.id
SELECT mi.*
FROM (
SELECT DISTINCT grouper
FROM mytable
) md
JOIN mytable mi
ON mi.id =
(
SELECT id
FROM mytable mo
WHERE mo.grouper = md.grouper
ORDER BY
id DESC
LIMIT 1
)
If your table is MyISAM or id is not a PRIMARY KEY, then make sure you have a composite index on (grouper, id).
If your table is InnoDB and id is a PRIMARY KEY, then a simple index on grouper will suffice (id, being a PRIMARY KEY, will be implictly included).
This will use an INDEX FOR GROUP-BY to build the list of distinct groupers, and for each grouper it will use the index access to find the maximal id.
Don't know how to do it in mysql. But the following code will work for MsSQL...
SELECT Y.* FROM
(
SELECT DISTINCT [group], MAX(id) ID
FROM Table1
GROUP BY [group]
) X
INNER JOIN Table1 Y ON X.ID=Table1.ID