Aggregation level is off (Postgresql) - sql

I have Order data for 2 customers and their order. And I am trying to calculate what the sum for the price is for every customter for that specific order only for product N
Table:
This is my query:
select Customer_ID, Order_ID, Sales_Date,
sum(Price) over (partition by Customer_ID, Order_ID order by Customer_ID, Order_ID)
from orders
group by 1,2,3, Price
order by;
For some reason I do not understand it gives me several rows per same customer. I am trying to get only one row generated per customer and order for product N
This is my current Output:
Desired Outcome:

Why are you using window functions? I think you just want aggregation:
select Customer_ID, Order_ID, Sales_Date,
sum(Price)
from orders
group by 1,2,3;
If you only want one product, add where product = 'N'.

Related

SQL Query - second ID of a list ordered by date and ID

I have a SQL database with a list of Customer IDs CustomerID and invoices, the specific product purchased in each invoice ProductID, the Date and the Income of each invoice . I need to write a query that will retrieve for each product, which was the second customer who made a purchase
How do I do that?
EDIT:
I have come up with the following query:
SELECT *,
LEAD(CustomerID) OVER (ORDER BY ProductID, Date) AS 'Second Customer Who Made A Purchase'
FROM a
ORDER BY ProductID, Date ASC
However, this query presents multiple results for products that have more than two purchases. Can you advise?
SELECT a2.ProductID,
(
SELECT a1.CustomerID
FROM a a1
WHERE a1.ProductID = a2.ProductID
ORDER BY Date asc
LIMIT 1,1
) as SecondCustomer
FROM a a2
GROUP BY a2.ProductID
I need to write a query that will retrieve for each product, which was the second customer who made a purchase
This sounds like a window function:
select a.*
from (select a.*,
row_number() over (partition by productid order by date asc) as seqnum
from a
) a
where seqnum = 2;

Transforming table with aggregation over rows and new column creation

I am to new to post table views, so I will try to explain how my data looks:
I have the customer id, order id, the sales date, the product bought and also the price of the product. We sell 3 Products: K, N and E. Every row shows the product the customer bought and it's price. Customers can buy in the same order the same product several times, but also buy other products. Below I am trying to aggregate the prices per product, so that in the end I will have one column per customer and order and new price columns created.
Currently writing CTEs:
with N as (select Customer_ID, Order_ID, Sales_Date,
sum(Price)
from orders
group by 1,2,3
where product = 'N'),
K as (select Customer_ID, Order_ID, Sales_Date,
sum(Price)
from orders
group by 1,2,3
where product = 'K'),
E as (select Customer_ID, Order_ID, Sales_Date,
sum(Price)
from orders
group by 1,2,3
where product = 'E')
select N.*,
K.Price as K_Price,
E.Price as E_Price
from N as N
left join K as K on K.Customer_ID=N.Customer_ID
left join E as E on E.Customer_ID=N.Customer_ID
Is there a more efficient way to do this? If product options increase from 3 to 20 - I will have 20 CTEs, maybe it's better to write the query in a different way?
You can use conditional aggregation:
select Customer_ID, Order_ID, Sales_Date,
sum(price) filter (where product = 'N') as n_price,
sum(price) filter (where product = 'K') as k_price,
sum(price) filter (where product = 'E') as e_price
from orders o
group by Customer_ID, Order_ID, Sales_Date;

Group by number of instances of product sold descending and then order by string length of product name in SQL

I have a table with two columns: product_id and product_name. Each product_id is repeated multiple times and each occurrence equals one sale.
I want to count the number of times the product_ids occur and order them from the most sold to the least and then I want to order it by the length of the product_name which is a string.
Right now this is what I have now and I am not sure it is correct:
SELECT product_id, COUNT(*), LEN(product_name) AS NameLength
FROM table
GROUP BY product_id
ORDER BY COUNT(product_id) DESC, LEN(product_name);
You can not add LEN(product_name) in the selection without adding the same in the GROUP BY part. You can try this following script which will first order the result by Most Order Count of a Product and then by length of product name if there more then one product available with the same count.
SELECT product_id,LEN(product_name), COUNT(*)
FROM table
GROUP BY product_id,LEN(product_name)
ORDER BY COUNT(product_id) DESC, LEN(product_name)
I don't believe that you want in the SELECT list the length of the product_name but the product_name itself, so you must GROUP BY product_id, product_name and ORDER BY COUNT(product_id) DESC, LEN(product_name):
SELECT product_id, COUNT(*), product_name
FROM tablename
GROUP BY product_id, product_name
ORDER BY COUNT(product_id) DESC, LEN(product_name);
See the demo.

SQL query for table with multiple keys?

I am sorry if this seems too easy but I was asked this question and I couldn't answer even after preparing SQL thoroughly :(. Can someone answer this?
There's a table - Seller id, product id, warehouse id, quantity of products at each warehouse for each product as per each seller.
We have to list the Product Ids with Seller Id who has highest number of products for that product and the total number of units he has for that product.
I think I got confused because there were 3 keys in the table.
It's not quite clear which DBMS you are using currently. The below should work if your DBMS support window functions.
You can find count of rows for each product and seller, rank each seller within each product using window function rank and then use filter to get only top ranked sellers in each product along with count of units.
select
product_id,
seller_id,
no_of_products
from (
select
product_id,
seller_id,
count(*) no_of_products,
rank() over (partition by product_id order by count(*) desc) rnk
from your_table
group by
product_id,
seller_id
) t where rnk = 1;
If window functions are not supported, you can use correlated query to achieve the same effect:
select
product_id,
seller_id,
count(*) no_of_products
from your_table a
group by
product_id,
seller_id
having count(*) = (
select max(cnt)
from (
select count(*) cnt
from your_table b
where b.product_id = a.product_id
group by seller_id
) t
);
Don't know why having id columns would mess you up... group by the right columns, sum up the totals and just return the first row:
select *
from (
select sellerid, productid, sum(quantity) as total_sold
from theres_a_table
group by sellerid, productid
) x
order by total_sold desc
fetch first 1 row only
If I do not think about optimization, straight forward answer is like this
select *
from
(
select seller_id, product_id, sum(product_qty) as seller_prod_qty
from your_table
group by seller_id, product_id
) spqo
inner join
(
select product_id, max(seller_prod_qty) as max_prod_qty
from
(
select seller_id, product_id, sum(product_qty) as seller_prod_qty
from your_table
group by seller_id, product_id
) spqi
group by product_id
) pmaxq
on spqo.product_id = pmaxq.product_id
and spqo.seller_prod_qty = pmaxq.max_prod_qty
both spqi (inner) and sqpo (outer) give you seller, product, sum of quantity across warehouses. pmaxq gives you max of each product again across warehouses, and then final inner join picks up sum of quantities if seller has highest (max) of the product (could be multiple sellers with the same quantity). I think this is the answer you are looking for. However, I'm sure query can be improved, since what I'm posting is the "conceptual" one :)

Sorting Records on the Basis of Number of Items in a Group- SQL Server

I have a set of records and I want to sort these records on the basis of the number of items in a group.
I want to arrange the records in such a way that Products with maximum number of items are at the top i.e. the required order is- Product_ID 3 (with 6 items), then Product_ID 1 (with 5 items) and the last one would be Product_ID 2(with 3 items).
The following query returns the count of the items with same Product_ID, however, I want Item_Name, Item_Description and Item_Number to be arranged as well.
Select Product_ID, Count(*) from Product group by Product_ID order by Count(*) DESC
I have tried another query as follows, but I know I am wrong somewhere that it is not giving the desired results and I can't think of a possible solution:
Select Product_ID, Item_Name, Item_Description, Item_Number from Product
group by Product_ID,item_name,item_description,item_number
order by COUNT(product_ID)
Thanks in advance for your help!!
Select Product_ID, Item_Name, Item_Description, Item_Number
from Product
order by COUNT(1) over (partition by Product_ID) desc
I assume you want to group by the ID only but you want to list all other fields, you don't need to group by at all if you just want to order by:
SELECT product_id,
item_name,
item_description,
item_number
FROM product p1
ORDER BY (SELECT Count(product_id)
FROM product p2
WHERE p1.product_id = p2.product_id) DESC
Try using an alias:
Select Product_ID, Count(*) AS num_products from Product group by Product_ID order by num_products DESC;