How to use distinct and count with partition by - sql

I want rows with distinct agt_id along with the count. Following is the query i am currently using but need help to get distinct rows.
with cust as
(
SELECT customer_id, cnic
FROM customer
where customer_id
not in
(select agent_id from agent
where to_date(created_on) BETWEEN '2020-06-01' AND '2020-06-30')
)
select agt.agent_id, c.customer_id, c.cnic, agt.transaction_type_id,
agt.transaction_type_name , row_number() OVER(PARTITION BY c.customer_id) AS agent_count
from cust as c
INNER JOIN konnect_ag_transaction_vw agt ON c.cnic= agt.receiver_cnic
where
agt.status ='PROCESSED'
AND agt.transaction_type_id IN (1,2,3)
Current Output using above query:
agt_id cus_id Count
1 89563 93587 7
2 89563 93587 7
3 89563 93587 7
4 89563 93587 7
5 89563 93587 7
6 56139 93587 7
7 56139 93587 7
Count in the above output is the total count of rows with same cus_id where as i want count of agt_id link with same cus_id
Desired output:
agt_id cus_id Count
1 89563 93587 2
2 56139 93587 2

If I understand correctly you need a simple group by with count()
with cust as
(
SELECT customer_id, cnic
FROM konnect_bb_customer_vw
where customer_id
not in
(select agent_id from konnect_bb_agent_h_vw
where to_date(created_on) BETWEEN '2020-06-01' AND '2020-06-30')
)
select agt.agent_id, c.customer_id, count(*)
from cust as c
INNER JOIN konnect_ag_transaction_vw agt ON c.cnic= agt.receiver_cnic
where agt.status ='PROCESSED' AND agt.transaction_type_id IN (1,2,3)
group by agt.agent_id, c.customer_id

I suspect that you want aggregation:
select agt.agent_id, c.customer_id, count(*)
from cust c join
konnect_ag_transaction_vw agt
on c.cnic = agt.receiver_cnic
where agt.status = 'PROCESSED' and
agt.transaction_type_id in (1, 2, 3)
group by agt.agent_id, c.customer_id;

using DISTINCT keyword as such
select DISTINCT agt.agent_id, c.customer_id, c.cnic, agt.transaction_type_id,
agt.transaction_type_name , row_number() OVER(PARTITION BY c.customer_id) AS agent_count
from cust as c
INNER JOIN konnect_ag_transaction_vw agt ON c.cnic= agt.receiver_cnic
where
agt.status ='PROCESSED'
AND agt.transaction_type_id IN (1,2,3)

Related

How to get the most sold Product in PostgreSQL?

Given a table products
pid
name
123
Milk
456
Tea
789
Cake
...
...
and a table sales
stamp
pid
units
14:54
123
3
15:02
123
9
15:09
456
1
15:14
456
1
15:39
456
2
15:48
789
12
...
...
...
How would I be able to get the product(s) with the most sold units?
My goal is to run a SELECT statement that results in, for this example,
pid
name
123
Milk
789
Cake
because the sum of sold units of both those products is 12, the maximum value (greater than 4 for Tea, despite there being more sales for Tea).
I have the following query:
SELECT DISTINCT products.pid, products.name
FROM sales
INNER JOIN products ON sale.pid = products.pid
INNER JOIN (
SELECT pid, SUM(units) as sum_units
FROM sales
GROUP BY pid
) AS total_units ON total_units.pid = sales.pid
WHERE total_units.sum_units IN (
SELECT MAX(sum_units) as max_units
FROM (
SELECT pid, SUM(units) as sum_units
FROM sales
GROUP BY pid
) AS total_units
);
However, this seems very long, confusing, and inefficient, even repeating the sub-query to obtain total_units, so I was wondering if there was a better way to accomplish this.
How can I simplify this? Note that I can't use ORDER BY SUM(units) LIMIT 1 in case there are multiple (i.e., >1) products with the most units sold.
Thank you in advance.
Since Postgres 13 it has supported with ties so your query can be simply this:
select p.pId, p.name
from sales s
join products p on p.pid = s.pid
group by p.pId, p.name
order by Sum(units) desc
fetch first 1 rows with ties;
See demo Fiddle
Solution for your problem:
WITH cte1 AS
(
SELECT s.pid, p.name,
SUM(units) as total_units
FROM sales s
INNER JOIN products p
ON s.pid = p.pid
GROUP BY s.pid, p.name
),
cte2 AS
(
SELECT *,
DENSE_RANK() OVER(ORDER BY total_units DESC) as rn
FROM cte1
)
SELECT pid,name
FROM cte2
WHERE rn = 1
ORDER BY pid;
Working example: db_fiddle link

SQL Group By most recent date and sales value

I have the following sales table that displays the customer ID, their name, the order amount, and the order date.
ID
Name
Order
Date
1
A
25
11/10/2006
1
A
10
5/25/2010
1
A
10
6/18/2018
2
B
20
3/31/2008
2
B
15
11/15/2010
3
C
35
1/1/2019
3
C
20
4/12/2007
3
C
10
3/20/2010
3
C
5
10/19/2012
4
D
15
12/12/2013
4
D
15
2/18/2010
5
E
25
12/11/2006
6
F
10
5/1/2016
I am trying to group the data so that for each customer it would only show me their most recent order and the amount, as per below:
ID
Name
Order
Date
1
A
10
6/18/2018
2
B
15
11/15/2010
3
C
35
1/1/2019
4
D
15
12/12/2013
5
E
25
12/11/2006
6
F
10
5/1/2016
So far I've only been able to group by ID and Name, because adding the Order column would also group by that column as well.
SELECT
ID,
Name,
MAX(Date) 'Most recent date'
FROM Table
GROUP BY Customer, Customer
How can I also add the order amount for each Customer?
SELECT ID, Name, Order, Date FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Date DESC) AS sn
FROM your_table_name
) A WHERE sn = 1;
You could use a subqoery for max date
SELECT
ID,
Name,
MAX(Date) 'Most recent date'
FROM Table
GROUP BY Customer, Customer
select a.ID, a.Name, b.max_date
from Table a
inner join (
select name, max(Date) max_date
from Table
group by name
) b on a. name = b.name and a.date = b.max_date
You can use this query to get the expected result:
SELECT S.*
FROM Sales S
CROSS APPLY
(
SELECT ID, Max(Date) MaxDate
FROM Sales
GROUP BY ID
)T
WHERE S.ID = T.ID
AND S.Date = T.MaxDate
ORDER BY S.ID

How to select varying count of items per colum value?

I work with Postgresql.
I have a sql code
SELECT lp."RegionId", COUNT(w."Id") FROM public.workplace w
GROUP BY lp."RegionId"
that returns to me
RegionId | Count
1 | 3
2 | 12
3 | 5
I have table 'person'. Each person have RegionId.
So i for region 1 i want to select first 3 persons, for region 2 select first 12 persons, for region 3 select first 5 persons.
So how can i use it as subquery to table 'person'?
WITH (SELECT lp."RegionId", COUNT(w."Id") FROM public.workplace w
GROUP BY lp."RegionId") AS pc
SELECT * FROM public.person p
???????
limit pc."Count"
???
Something like:
SELECT p.*
FROM (SELECT *, row_number() OVER (PARTITION BY RegionId ORDER BY PersonId) AS rn
FROM person) AS p
JOIN (SELECT RegionId, count(*) AS cnt
FROM workplace
GROUP BY RegionId) AS r ON p.RegionId = r.RegionId
WHERE p.rn <= r.cnt
ORDER BY p.RegionId, p.PersonId;

SQL - Finding Customer's largest Location by Order $

I have a table with customer IDs, location IDs, and their order values. I need to select the location ID for each customer with the largest spend
Customer | Location | Order $
1 | 1A | 100
1 | 1A | 20
1 | 1B | 100
2 | 2A | 50
2 | 2B | 20
2 | 2B | 50
So I would get
Customer | Location | Order $
1 | 1A | 120
2 | 2B | 70
I tried something like this:
SELECT
a.CUST
,a.LOC
,c.BOOKINGS
FROM (SELECT DISTINCT TOP 1 b.CUST, b.LOC, sum(b.ORDER_VAL) as BOOKINGS
FROM ORDER_TABLE b
GROUP BY b.CUST, b.LOC
ORDER BY BOOKINGS DESC) as c
INNER JOIN ORDER_TABLE a
ON a.CUST = c.CUST
But that just returns the top order.
Just use variables to emulate ROW_NUM()
DEMO
SELECT *
FROM ( SELECT `Customer`, `Location`, SUM(`Order`) as `Order`,
#rn := IF(#customer = `Customer`,
#rn + 1,
IF(#customer := `Customer`, 1, 1)
) as rn
FROM Table1
CROSS JOIN (SELECT #rn := 0, #customer := '') as par
GROUP BY `Customer`, `Location`
ORDER BY `Customer`, SUM(`Order`) DESC
) t
WHERE t.rn = 1
Firs you have to sum the values for each location:
select Customer, Location, Sum(Order) as tot_order
from order_table
group by Customer, Location
then you can get the maximum order with MAX, and the top location with a combination of group_concat that will return all locations, ordered by total desc, and substring_index in order to get only the top one:
select
Customer,
substring_index(
group_concat(Location order by tot_order desc),
',', 1
) as location,
Max(tot_order) as max_order
from (
select Customer, Location, Sum(Order) as tot_order
from order_table
group by Customer, Location
) s
group by Customer
(if there's a tie, two locations with the same top order, this query will return just one)
This seems like an order by using aggregate function problem. Here is my stab at it;
SELECT
c.customer,
c.location,
SUM(`order`) as `order_total`,
(
SELECT
SUM(`order`) as `order_total`
FROM customer cm
WHERE cm.customer = c.customer
GROUP BY location
ORDER BY `order_total` DESC LIMIT 1
) as max_order_amount
FROM customer c
GROUP BY location
HAVING max_order_amount = order_total
Here is the SQL fiddle. http://sqlfiddle.com/#!9/2ac0d1/1
This is how I'd handle it (maybe not the best method?) - I wrote it using a CTE first, only to see that MySQL doesn't support CTEs, then switched to writing the same subquery twice:
SELECT B.Customer, C.Location, B.MaxOrderTotal
FROM
(
SELECT A.Customer, MAX(A.OrderTotal) AS MaxOrderTotal
FROM
(
SELECT Customer, Location, SUM(`Order`) AS OrderTotal
FROM Table1
GROUP BY Customer, Location
) AS A
GROUP BY A.Customer
) AS B INNER JOIN
(
SELECT Customer, Location, SUM(`Order`) AS OrderTotal
FROM Table1
GROUP BY Customer, Location
) AS C ON B.Customer = C.Customer AND B.MaxOrderTotal = C.OrderTotal;
Edit: used the table structure provided
This solution will provide multiple rows in the event of a tie.
SQL fiddle for this solution
How about:
select a.*
from (
select customer, location, SUM(val) as s
from orders
group by customer, location
) as a
left join
(
select customer, MAX(b.tot) as t
from (
select customer, location, SUM(val) as tot
from orders
group by customer, location
) as b
group by customer
) as c
on a.customer = c.customer where a.s = c.t;
with
Q_1 as
(
select customer,location, sum(order_$) as order_sum
from cust_order
group by customer,location
order by customer, order_sum desc
),
Q_2 as
(
select customer,max(order_sum) as order_max
from Q_1
group by customer
),
Q_3 as
(
select Q_1.customer,Q_1.location,Q_1.order_sum
from Q_1 inner join Q_2 on Q_1.customer = Q_2.customer and Q_1.order_sum = Q_2.order_max
)
select * from Q_3
Q_1 - selects normal aggregate, Q_2 - selects max(aggregate) out of Q_1 and Q_3 selects customer,location, sum(order) from Q_1 which matches with Q_2

sql query to get data group by customer type and need to add default value if customer type not found

I have a table "Customers" with columns CustomerID, MainCountry and CustomerTypeID.
I have 5 customer types 1,2,3,4,5 .
I want to count number of customers of each country according to customer type. I am using the following query:
select count(CustomerID) as CustomerCount,MainCountry,CustomerTypeID
from Customers
group by CustomerTypeID,MainCountry
But some countries not have any customers, under type 1,2,3,4 or 5.
So I want to put a default value 0 for if customer type is not exist for that country.
Currently it is giving data as follows :-
CustomerCount MainCountry CustomerTypeID
5695 AU 1
525 AU 2
12268 AU 3
169 AU 5
18658 CA 1
1039 CA 2
24496 CA 3
2259 CA 5
2669 CO 1
10 CO 2
463 CO 3
22 CO 4
39 CO 5
As "AU" not have type 4 so I want a default value for it.
You should JOIN your table with a table with TypeId's. In this case
select count(CustomerID) as CustomerCount,TypeTable.MainCountry,TypeTable.TId
from
Customers
RIGHT JOIN (
select MainCountry,TId from
(
select Distinct MainCountry from Customers
) as T1,
(
select 1 as Tid
union all
select 2 as Tid
union all
select 3 as Tid
union all
select 4 as Tid
union all
select 5 as Tid
) as T2
) as TypeTable on Customers.CustomerTypeID=TypeTable.TId
and Customers.MainCountry=TypeTable.MainCountry
group by TypeTable.TId,TypeTable.MainCountry
Select Country.MainCountry, CustomerType.CustomerTypeId, Count(T.CustomerID) As CustomerCount
From (Select Distinct MainCountry From Customers) As Country
Cross Join (Select Distinct CustomerTypeId From Customers) As CustomerType
Left Join Customers T
On Country.MainCountry = T.MainCountry
And CustomerType.CustomerTypeId = T.CustomerTypeId
-- Edit here
And T.CreatedDate > Convert(DateTime, '1/1/2013')
-- End Edit
Group By Country.MainCountry, CustomerType.CustomerTypeId
Order By MainCountry, CustomerTypeId
Try that:
with cuntry as (
Select Distinct MainCountry From Customers
),
CustomerType as (
(Select Distinct CustomerTypeId From Customers
),
map as (
select MainCountry, CustomerTypeId from cuntry,CustomerType
)
select count(CustomerID) as CustomerCount,a.MainCountry,a.CustomerTypeID
from
map a left join Customers b on a.CustomerCount=b.CustomerCount and a.CustomerTypeID=b.CustomerTypeID