SQL - Group by group property? - sql

I've got a table of consignments (simplified of course)
CONSIGNMENT_NR CUSTOMER
1 1
2 1
3 2
4 2
5 2
I can easily select, for each customer, how many consignments they have:
SELECT CUSTOMER, COUNT(*) AS 'Count'
FROM CONSIGNMENT
GROUP BY CUSTOMER
Which will give me (with that example data):
CUSTOMER Count
1 2
2 3
But what I want is to get how many customers made x amount of consignments.
The data I want would look like this:
Amount No of Customers
2 1
3 1
I can't quite figure out how.

Wrap your query up as a derived table. GROUP BY its result:
select Amount, count(*) as No_of_Customers
from
(
SELECT COUNT(*) AS Amount
FROM CONSIGNMENT
GROUP BY CUSTOMER
) dt
group by Amount

you can try below - using subquery
select count(distinct customer) as noofcustomer, 'Count'
from
(
SELECT CUSTOMER, COUNT(*) AS 'Count'
FROM CONSIGNMENT
GROUP BY CUSTOMER
)A group by 'Count'

Related

Grouping in SQL using CASE Statements

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

Get number of customers having 1,2 and more than 3 products

Trying to figure out a query which shows the number of customer having 1,2 and more than 3 products. Here are the table name and fields:
Product(prod_no, prod_cust_id)
Customer(cust_id)
Product
prod_no
prod_cust_id
Cheetos1
WR123
Cheetos2
WR123
Lay1
WP232
Prings
WP678
Customer
cust_id
WN999
WR123
WP232
WP678
Example of correct query I want to get is:
1 Product - 100 customer
2 Product - 52 customer
3 Products and above - 10 customer
Product
Customers
1
100
2
52
>=3
10
I tried with the following query
SELECT COUNT (DISTINCT PROD_NO)"Product", CUST_ID"Customers"
FROM PRODUCT, CUSTOMER
WHERE PROD_CUST_ID = CUST_ID
HAVING COUNT(PROD_NO) >= 3 --for 3 products and above
GROUP BY CUST_ID
But the result is not what I wanted, so close yet so far. I tried only for 3 products and above, but how to add together with 1 product and 2 products.
Please help me out thanks
One option would be starting with distinctly counting by each column ( prod_no,prod_cust_id ), and evaluating the three or more products as an individual case within the conditional such as
WITH prod_cust AS
(
SELECT COUNT(DISTINCT prod_no) AS prod_no,
DECODE( SIGN(COUNT(DISTINCT prod_cust_id)-2),1,'>=3',
COUNT(DISTINCT prod_cust_id) ) AS prod_cust_id
FROM product
GROUP BY prod_no
)
SELECT prod_cust_id AS "Product", SUM(prod_no) AS "Customers"
FROM prod_cust
GROUP BY prod_cust_id
ORDER BY 1
Demo
You can first count the no of customers in the product table and then can count them separately. You can try the below query -
WITH DATA AS (SELECT P.*, COUNT(*) OVER(PARTITION BY prod_cust_id) CNT
FROM Product P)
SELECT '1' Product, COUNT(CASE WHEN CNT = 1 THEN CNT ELSE NULL END) Customers
FROM DATA
UNION ALL
SELECT '2', COUNT(CASE WHEN CNT = 2 THEN CNT ELSE NULL END)
FROM DATA
UNION ALL
SELECT '>=3', COUNT(CASE WHEN CNT >= 3 THEN CNT ELSE NULL END)
FROM DATA;
Demo.

Query 2 sum in 1 table

table a
column id : a a b b
column total : 1 2 1 3
how can i show? in one table without use compute
a 3 7
b 4 7
Do group by to sum each id's total. Do a sub-select to count total:
select id,
sum(total) as total,
(select sum(total) from a) as totalall
from a
group by id
Using window functions with a distinct, it can be simply expressed like this:
select distinct id,
sum(Total) over(partition by id) total,
Sum(Total) over () total_all
from mytable
SQL Fiddle
One way is to use OUTER APPLY. You could also set a variable to the sum of the table and call that variable.
select a.id, sum(a.total) as total, b.Grand as GrandTotal
from tablea a
outer apply
(select sum(total) as Grand from tablea) b
group by a.id

Select first purchase for each customer

We are trying to select the first purchase for each customer in a table similar to this:
transaction_no customer_id operator_id purchase_date
20503 1 5 2012-08-24
20504 1 7 2013-10-15
20505 2 5 2013-09-05
20506 3 7 2010-09-06
20507 3 7 2012-07-30
The expected result from the query that we are trying to achieve is:
transaction_no customer_id operator_id first_occurence
20503 1 5 2012-08-24
20505 2 5 2013-09-05
20506 3 7 2010-09-06
The closest we've got is the following query:
SELECT customer_id, MIN(purchase_date) As first_occurence
FROM Sales_Transactions_Header
GROUP BY customer_id;
With the following result:
customer_id first_occurence
1 2012-08-24
2 2013-09-05
3 2010-09-06
But when we select the rest of the needed fields we obviously have to add them to the GROUP BY clause which will make the result from MIN different. We have also tried to joining it on itself, but haven't made any progress.
How do we get the rest of the correlated values without making the aggregate function confused?
You can simply treat the query you have come up with as an inner query. This will work on older version of SQL Server as well (you didn't specify version of SQL Server).
SELECT H.transaction_no, H.customer_id, H.operator_id, H.purchase_date
FROM Sales_Transactions_Header H
INNER JOIN
(SELECT customer_id, MIN(purchase_date) As first_occurence
FROM Sales_Transactions_Header
GROUP BY customer_id) X
ON H.customer_id = X.customer_id AND H.purchase_date = X.first_occurence
You can use the ROW_NUMBER function to help you with that.
This is how to do it for your case.
WITH Occurences AS
(
SELECT
*,
ROW_NUMBER () OVER (PARTITION BY customer_id order by purchase_date ) AS "Occurence"
FROM Sales_Transactions_Header
)
SELECT
transaction_no,
customer_id,
operator_id,
purchase_date
FROM Occurences
WHERE Occurence = 1
Sounds like a job for a CTE!
Clicky!
The CTE will allow you to get the earliest purchase date for each customer. Then you join that back to your original table on customer_id and the date, getting the rest of the information for that transaction.
Like so:
with first_date as(
select customer_id,
min(purchase_date) as first_purchase
from
table1
group by
customer_id
)
select
t1.transaction_no,
t1.customer_id,
t1.operator_id,
t1.purchase_date
from
table1 t1
inner join first_date
on
purchase_date = first_purchase
and t1.customer_id = first_date.customer_id
Below query will also provide the solution
select * from customer_sale_details
where purchase_date in (select min(purchase_date)
from customer_sale_details c1 group by c1.customer_id);

SUM of grouped COUNT in SQL Query

I have a table with 2 fields:
ID Name
-- -------
1 Alpha
2 Beta
3 Beta
4 Beta
5 Charlie
6 Charlie
I want to group them by name, with 'count', and a row 'SUM'
Name Count
------- -----
Alpha 1
Beta 3
Charlie 2
SUM 6
How would I write a query to add SUM row below the table?
SELECT name, COUNT(name) AS count
FROM table
GROUP BY name
UNION ALL
SELECT 'SUM' name, COUNT(name)
FROM table
OUTPUT:
name count
-------------------------------------------------- -----------
alpha 1
beta 3
Charlie 2
SUM 6
SELECT name, COUNT(name) AS count, SUM(COUNT(name)) OVER() AS total_count
FROM Table GROUP BY name
Without specifying which rdbms you are using
Have a look at this demo
SQL Fiddle DEMO
SELECT Name, COUNT(1) as Cnt
FROM Table1
GROUP BY Name
UNION ALL
SELECT 'SUM' Name, COUNT(1)
FROM Table1
That said, I would recomend that the total be added by your presentation layer, and not by the database.
This is a bit more of a SQL SERVER Version using Summarizing Data Using ROLLUP
SQL Fiddle DEMO
SELECT CASE WHEN (GROUPING(NAME) = 1) THEN 'SUM'
ELSE ISNULL(NAME, 'UNKNOWN')
END Name,
COUNT(1) as Cnt
FROM Table1
GROUP BY NAME
WITH ROLLUP
Try this:
SELECT ISNULL(Name,'SUM'), count(*) as Count
FROM table_name
Group By Name
WITH ROLLUP
all of the solution here are great but not necessarily can be implemented for old mysql servers (at least at my case). so you can use sub-queries (i think it is less complicated).
select sum(t1.cnt) from
(SELECT column, COUNT(column) as cnt
FROM
table
GROUP BY
column
HAVING
COUNT(column) > 1) as t1 ;
Please run as below :
Select sum(count)
from (select Name,
count(Name) as Count
from YourTable
group by Name); -- 6
The way I interpreted this question is needing the subtotal value of each group of answers. Subtotaling turns out to be very easy, using PARTITION:
SUM(COUNT(0)) OVER (PARTITION BY [Grouping]) AS [MY_TOTAL]
This is what my full SQL call looks like:
SELECT MAX(GroupName) [name], MAX(AUX2)[type],
COUNT(0) [count], SUM(COUNT(0)) OVER(PARTITION BY GroupId) AS [total]
FROM [MyView]
WHERE Active=1 AND Type='APP' AND Completed=1
AND [Date] BETWEEN '01/01/2014' AND GETDATE()
AND Id = '5b9xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' AND GroupId IS NOT NULL
GROUP BY AUX2, GroupId
The data returned from this looks like:
name type count total
Training Group 2 Cancelation 1 52
Training Group 2 Completed 41 52
Training Group 2 No Show 6 52
Training Group 2 Rescheduled 4 52
Training Group 3 NULL 4 10535
Training Group 3 Cancelation 857 10535
Training Group 3 Completed 7923 10535
Training Group 3 No Show 292 10535
Training Group 3 Rescheduled 1459 10535
Training Group 4 Cancelation 2 27
Training Group 4 Completed 24 27
Training Group 4 Rescheduled 1 27
You can use union to joining rows.
select Name, count(*) as Count from yourTable group by Name
union all
select "SUM" as Name, count(*) as Count from yourTable
For Sql server you can try this one.
SELECT ISNULL([NAME],'SUM'),Count([NAME]) AS COUNT
FROM TABLENAME
GROUP BY [NAME] WITH CUBE
with cttmp
as
(
select Col_Name, count(*) as ctn from tab_name group by Col_Name having count(Col_Name)>1
)
select sum(ctn) from c
You can use ROLLUP
select nvl(name, 'SUM'), count(*)
from table
group by rollup(name)
Use it as
select Name, count(Name) as Count from YourTable
group by Name
union
Select 'SUM' , COUNT(Name) from YourTable
I am using SQL server and the following should work for you:
select cast(name as varchar(16)) as 'Name', count(name) as 'Count'
from Table1
group by Name
union all
select 'Sum:', count(name)
from Table1
I required having count(*) > 1 also. So, I wrote my own query after referring some the above queries
SYNTAX:
select sum(count) from (select count(`table_name`.`id`) as `count` from `table_name` where {some condition} group by {some_column} having count(`table_name`.`id`) > 1) as `tmp`;
Example:
select sum(count) from (select count(`table_name`.`id`) as `count` from `table_name` where `table_name`.`name` IS NOT NULL and `table_name`.`name` != '' group by `table_name`.`name` having count(`table_name`.`id`) > 1) as `tmp`;
You can try group by on name and count the ids in that group.
SELECT name, count(id) as COUNT FROM table group by name
After the query, run below to get the total row count
select ##ROWCOUNT
select sum(s) from
(select count(Col_name) as s from Tab_name group by Col_name having count(*)>1)c