I need to add a Total at the bottom of my table. Is this possible in my scenario?
select country, count(*) from customer
group by country
Country Count
USA 5
UK 10
Canada 15
Russia 25
55 (Requested from SO community)
Use rollup()
select country, count(*)
from customer
group by rollup (country )
If you want the label "Total" as well, you can use the grouping function:
select case
when grouping(country) = 1 then 'Total'
else country
end as country,
count(*)
from customer
group by rollup (country )
Online example: http://rextester.com/PKFE63954
You can artificially generate a row by using something like
select country
,count(*)
from customer
group by country
UNION ALL
SELECT 'Total'
,COUNT(*)
FROM customer
Although this will affect any future calculations you make on this result set as it is a new row in the data.
something like:
SELECT country
, count(ยด1)
FROM customer
GROUP BY country
UNION
SELECT 'TOTAL'
, count(1)
FROM customer;
You could add another column to the row named Total
DECLARE #Total int = 0;
SET #Total = (SELECT COUNT(*) FROM customer);
SELECT country, COUNT(*), [Total] = #Total
FROM customer
GROUP BY country
Related
I have a table Customers which contains customerID and Country columns. I would like to return the country with the most customers and the count of the customers.
This is what I tried:
SELECT COUNT(CustomerID), Country
FROM Customers
GROUP BY Country
HAVING COUNT(CustomerID) = MAX(COUNT(CustomerID));
How would I correctly implement the code? Thank you in advance.
Just use ORDER BY (to sort) and TOP (1) to get the single top row:
SELECT TOP (1) COUNT(CustomerID), Country
FROM Customers
GROUP BY Country
ORDER BY COUNT(CustomerID) DESC;
Marc_s's solution was my first thought +1
However, if your CustomerID is not unique and/or you want to see ties (edge case)
Example
Declare #YourTable Table ([Country] varchar(50),CustomerID varchar(50)) Insert Into #YourTable Values
('USA','AA')
,('USA','AB')
,('USA','AB') -- USA has 3 CustomerIDs (2 distinct)
,('France','AC')
,('France','AD') -- France has 2 CustomerIDs (2 distinct)
,('Singapore','AE')
;with cte as (
Select country
,CustCnt = count(Distinct CustomerID) -- Distinct may not be necessary if already unique
from #YourTable
Group By Country
)
Select top 1 with ties *
From cte
Order by dense_rank() over (order by CustCnt desc)
Results
country CustCnt
France 2
USA 2
SELECT COUNT (CustomerID),Country FROM Customers
GROUP BY Country
HAVING COUNT (CustomerID) = (SELECT MAX (tt) c FROM ((SELECT count (CustomerID) tt FROM Customers GROUP BY Country)) AS a)
Hello I am trying to group multiple customer orders into buckets in SQL, the output should look something like it does below. Do I have to use a case statement to group them?
Table1 looks like:
CustomerID
Order_date
1
somedate
2
somedate
3
somedate
2
somedate
Edit: # of customers meaning if CustomerID 2 had 2 orders he/she would be of the in the bucket of #of orders of 2.
Output should be something like this?
# of Customers
# of Orders
2
1
1
2
My code so far is:
select count(*) CustomerID
FROM Table1
GROUP BY CustomerID;
Use a double aggregation:
SELECT COUNT(*) AS num_customers, cnt AS num_orders
FROM
(
SELECT CustomerID, COUNT(*) AS cnt
FROM Table1
GROUP BY CustomerID
) t
GROUP BY cnt;
The inner subquery finds the number of orders for each customer. The outer query then aggregates by number of orders and finds out the number of customers having each number of orders.
If you want to sort your tables and your users depending on the number of orders they made, this query should work:
SELECT CustomerID, COUNT(CustomerID) as NbOrder
FROM Table1
GROUP BY(NbOrder)
I believe what you want to do is get the count of orders by customer, first, via aggregation. Then get the count of customers by order count from that query.
SELECT count(*) as count_of_customers, count_of_orders
FROM
(
SELECT customerid, count(*) as count_of_orders
FROM your_table
GROUP BY customerid
) sub
GROUP BY count_of_orders
ORDER BY count_of_orders
I have the table:
table 1 (product_id,purchase_date, city, market, category)
categories = ('bread','soap','vegetables','fruits')
I need result in one table (following columns):
purchase_date, city, market, count of vegetable products, count of all products
grouping is carried out by the first three fields to be able to use the first three fields as filters
Disable where clause if not needed.
-- PostgreSQL
SELECT purchase_date
, city
, market
, SUM(CASE WHEN category = 'vegetables' THEN 1 END) "count of vegetable products"
, COUNT(1) "count of all products"
FROM table1
WHERE market = ? AND city = ? AND purchase_date = ?
GROUP BY purchase_date;
, city
, market
You want conditional aggregation. In Postgres, I recommend filter:
SELECT purchase_date, city, market
COUNT(*) FILTER (WHERE category = 'vegetables') as cnt_vegetables,
COUNT(*) as cnt
FROM table1
WHERE market = ? AND city = ? AND purchase_date = ?
GROUP BY purchase_date, city, market;
SELECT Region ,
flag ,
Name,
COUNT(ID) AS 'CountWithFlag'
FROM Table
GROUP BY flag
this query gives me the following results. I am grouping by flag and I am able to get the counts for English/non-English based on flag. I also want to display Total Counts of English and non-English adjacent to counts
OUTPUT:
Region Flag Name CountWithFlag
a 0 English 100
b 1 Non-English 200
c 0 English 100
d 1 Non-English 200
DESIRED OUTPUT:
Region Flag Name CountWithFlag Total
a 0 English 100 200
b 1 Non-English 200 400
c 0 English 100 200
d 1 Non-English 200 400
How can I do that? I want to apply group by for specific counts with flag. But I also want to get total counts in same query!
Any inputs on how I can do that?
Another way would be something like this:
;
WITH agg1
AS (
SELECT region,
flag,
name,
COUNT(id) AS 'CountWithFlag'
FROM [dbo].[t2]
GROUP BY region,
flag,
name
),
agg2
AS (
SELECT [name],
COUNT(id) AS CountByName
FROM [dbo].[t2]
GROUP BY [name]
)
SELECT [agg1].[region],
[agg1].[flag],
[agg1].[name],
[agg1].[CountWithFlag],
[agg2].[CountByName]
FROM [agg1]
INNER JOIN [agg2]
ON [agg2].[name] = [agg1].[name]
try this
;
WITH cte
AS ( SELECT DISTINCT
Region ,
flag ,
Name ,
COUNT(ID) OVER ( PARTITION BY flag, Region, Name ) AS [CountWithFlag]
FROM [Table]
)
SELECT Region ,
flag ,
Name ,
SUM([CountWithFlag]) OVER ( PARTITION BY Name ) AS Total
FROM cte
If you want to avoid using window functions, you can do that:
SELECT
Region,
flag,
Name,
COUNT(ID) AS CountWithFlag,
(select count(ID) from Table as tbl1 where tbl1.Name=tbl.Name) AS Total
from Table as tbl
group by Region, flag, Name
But my opinion is that window aggregation should work much faster.
If you want use window aggregation then do this:
select
Region,
flag,
Name,
CountWithFlag,
sum(CountWithFlag) over(partition by Name) as Total
from (
SELECT
Region,
flag,
Name,
COUNT(ID) AS CountWithFlag
from Table as tbl
group by Region, flag, Name
) as tbl
I have a table like this:
Column | Type | Modifiers
---------+------+-----------
country | text |
food_id | int |
eaten | date |
And for each country, I want to get the food that is eaten most often. The best I can think of (I'm using postgres) is:
CREATE TEMP TABLE counts AS
SELECT country, food_id, count(*) as count FROM munch GROUP BY country, food_id;
CREATE TEMP TABLE max_counts AS
SELECT country, max(count) as max_count FROM counts GROUP BY country;
SELECT country, max(food_id) FROM counts
WHERE (country, count) IN (SELECT * from max_counts) GROUP BY country;
In that last statement, the GROUP BY and max() are needed to break ties, where two different foods have the same count.
This seems like a lot of work for something conceptually simple. Is there a more straight forward way to do it?
It is now even simpler: PostgreSQL 9.4 introduced the mode() function:
select mode() within group (order by food_id)
from munch
group by country
returns (like user2247323's example):
country | mode
--------------
GB | 3
US | 1
See documentation here:
https://wiki.postgresql.org/wiki/Aggregate_Mode
https://www.postgresql.org/docs/current/static/functions-aggregate.html#FUNCTIONS-ORDEREDSET-TABLE
PostgreSQL introduced support for window functions in 8.4, the year after this question was asked. It's worth noting that it might be solved today as follows:
SELECT country, food_id
FROM (SELECT country, food_id, ROW_NUMBER() OVER (PARTITION BY country ORDER BY freq DESC) AS rn
FROM ( SELECT country, food_id, COUNT('x') AS freq
FROM country_foods
GROUP BY 1, 2) food_freq) ranked_food_req
WHERE rn = 1;
The above will break ties. If you don't want to break ties, you could use DENSE_RANK() instead.
SELECT DISTINCT
"F1"."food",
"F1"."country"
FROM "foo" "F1"
WHERE
"F1"."food" =
(SELECT "food" FROM
(
SELECT "food", COUNT(*) AS "count"
FROM "foo" "F2"
WHERE "F2"."country" = "F1"."country"
GROUP BY "F2"."food"
ORDER BY "count" DESC
) AS "F5"
LIMIT 1
)
Well, I wrote this in a hurry and didn't check it really well. The sub-select might be pretty slow, but this is shortest and most simple SQL statement that I could think of. I'll probably tell more when I'm less drunk.
PS: Oh well, "foo" is the name of my table, "food" contains the name of the food and "country" the name of the country. Sample output:
food | country
-----------+------------
Bratwurst | Germany
Fisch | Frankreich
try this:
Select Country, Food_id
From Munch T1
Where Food_id=
(Select Food_id
from Munch T2
where T1.Country= T2.Country
group by Food_id
order by count(Food_id) desc
limit 1)
group by Country, Food_id
Try something like this
select country, food_id, count(*) cnt
into #tempTbl
from mytable
group by country, food_id
select country, food_id
from #tempTbl as x
where cnt =
(select max(cnt)
from mytable
where country=x.country
and food_id=x.food_id)
This could be put all into a single select, but I don't have time to muck around with it right now.
Good luck.
Here's how to do it without any temp tables:
Edit: simplified
select nf.country, nf.food_id as most_frequent_food_id
from national_foods nf
group by country, food_id
having
(country,count(*)) in (
select country, max(cnt)
from
(
select country, food_id, count(*) as cnt
from national_foods nf1
group by country, food_id
)
group by country
having country = nf.country
)
SELECT country, MAX( food_id )
FROM( SELECT m1.country, m1.food_id
FROM munch m1
INNER JOIN ( SELECT country
, food_id
, COUNT(*) as food_counts
FROM munch m2
GROUP BY country, food_id ) as m3
ON m1.country = m3.country
GROUP BY m1.country, m1.food_id
HAVING COUNT(*) / COUNT(DISTINCT m3.food_id) = MAX(food_counts) ) AS max_foods
GROUP BY country
I don't like the MAX(.) GROUP BY to break ties... There's gotta be a way to incorporate eaten date into the JOIN in some way to arbitrarily select the most recent one...
I'm interested on the query plan for this thing if you run it on your live data!
select country,food_id, count(*) ne
from food f1
group by country,food_id
having count(*) = (select max(count(*))
from food f2
where country = f1.country
group by food_id)
Here is a statement which I believe gives you what you want and is simple and concise:
select distinct on (country) country, food_id
from munch
group by country, food_id
order by country, count(*) desc
Please let me know what you think.
BTW, the distinct on feature is only available in Postgres.
Example, source data:
country | food_id | eaten
US 1 2017-1-1
US 1 2017-1-1
US 2 2017-1-1
US 3 2017-1-1
GB 3 2017-1-1
GB 3 2017-1-1
GB 2 2017-1-1
output:
country | food_id
US 1
GB 3