group values in sql server view - sql

Hi i have a view that contains this:
sku quantity price discount
123 4 10 YES
123 1 10 YES
123 1 10 NO
the table have a lot of fields thats just a example what im trying to achieve is to group the sku by refering the quantity and discount column so it will look like this:
sku quantity price discount
123 5 10 YES
123 1 10 NO
so in this case there was 5 items with discount= YES same sku but other one with same sku 123 but quantity 1 and discount= NO, how i can group or sum that to make this work?
thank you

You could use window functions depending on your version of SQL Server:
Create Sample Table:
CREATE TABLE mytable (
sku INT
,quantity INT
,price MONEY
,discount VARCHAR(5)
);
insert into mytable values
(123, 4, 10, 'YES'),
(123, 1, 10, 'YES'),
(123, 1, 10, 'NO');
Query:
select distinct sku,
sum(quantity) OVER (partition by sku,discount order by sku) as quantity,
max(price) OVER (partition by sku,discount order by sku) as price,
discount
from mytable
Result:
+-----+----------+-------+----------+
| sku | quantity | price | discount |
+-----+----------+-------+----------+
| 123 | 1 | 10 | NO |
| 123 | 5 | 10 | YES |
+-----+----------+-------+----------+
SQL Fiddle Demo

Related

How to GROUP and return a value based on the oldest date?

So I have this table:
n | id_product | name | price | quantity | created_at
-------------------------------------------------------------------------------
1 1da05150 pencil 800 10 31-12-2021
2 1da05150 pencil 700 7 15-01-2022
3 1da05150 pencil 1500 13 20-01-2022
4 510eac00 book 350 25 29-12-2021
I'd like to group them by ID_PRODUCT column.
On the columns i'd like on return would be ID_PRODUCT, NAME, sum of quantities by id_product, and for the PRICE column i'd like to obtain the price value that comes from the oldest product (i'd like it to consider the CREATED_AT column for the price purpose)
On the result should be like this:
n | id_product | name | price | quantity | created_at
-------------------------------------------------------------------------------
1 1da05150 pencil 800 30 31-12-2021
2 510eac00 book 350 25 29-12-2021
you need Subquery to join table with itself
your data
create temporary table tmp_a (
n int
,id_product VARCHAR(30)
,name VARCHAR(30)
,price int
,quantity int
,created_at date
);
INSERT INTO tmp_a
(n,id_product,name,price,quantity,created_at)
VALUES (1,'1da05150','pencil',800,10,'12-31-2021'),
(2,'1da05150','pencil',700,7,'01-15-2022'),
(3,'1da05150','pencil',1500,13,'01-20-2022'),
(4,'510eac00','book',350,25,'12-29-2021');
your query
SELECT t1.n,
t1.id_product,
t1.NAME,
t1.price,
t2.quantity,
t2.created_at
FROM tmp_a t1
JOIN (SELECT id_product,
NAME,
Sum(quantity) quantity,
Min(created_at) created_at
FROM tmp_a
GROUP BY id_product,
NAME) t2
ON t1.id_product = t2.id_product
AND t1.created_at = t2.created_at

Postgres - Query to select fields from multiple tables as columns

I have the following tables
Table 1 : Product
id name
1 Bread
2 Bun
3 Cake
Table 2: Expense Items
product| quantity
1 | 100
2 | 150
3 | 180
1 | 25
2 | 30
Table 3: Income Items
product| quantity
1 | 100
2 | 150
3 | 180
1 | 25
2 | 30
Now I want the results like this
product | sum of quantity of expenseitem | sum of quantity of income item
1 | 125 | 125
2 | 180 | 180
3 | 180 | 180
What is the query to get this result ?
Thanks
You can try to use UNION ALL in a subquery with the condition in the aggregate function
Schema (PostgreSQL v9.6)
CREATE TABLE Product(
id int,
name varchar(50)
);
INSERT INTO Product VALUES (1,'Bread');
INSERT INTO Product VALUES (2,'Bun');
INSERT INTO Product VALUES (3,'Cake');
CREATE TABLE ExpenseItems(
product int,
quantity int
);
INSERT INTO ExpenseItems VALUES (1,100);
INSERT INTO ExpenseItems VALUES (2,150);
INSERT INTO ExpenseItems VALUES (3,180);
INSERT INTO ExpenseItems VALUES (1,25);
INSERT INTO ExpenseItems VALUES (2,30);
CREATE TABLE IncomeItems(
product int,
quantity int
);
INSERT INTO IncomeItems VALUES (1,100);
INSERT INTO IncomeItems VALUES (2,150);
INSERT INTO IncomeItems VALUES (3,180);
INSERT INTO IncomeItems VALUES (1,25);
INSERT INTO IncomeItems VALUES (2,30);
Query #1
SELECT p.id,
SUM(CASE WHEN grp = 1 THEN quantity END) SUMExpenseItems,
SUM(CASE WHEN grp = 2 THEN quantity END) SUMIncomeItems
FROM (
SELECT product, quantity,1 grp
FROM ExpenseItems
UNION ALL
SELECT product, quantity,2
FROM IncomeItems
) t1 JOIN Product p on p.id = t1.product
GROUP BY p.id;
| id | sumexpenseitems | sumincomeitems |
| --- | --------------- | -------------- |
| 1 | 125 | 125 |
| 2 | 180 | 180 |
| 3 | 180 | 180 |
View on DB Fiddle
Similar to #D-Shih's answer, PostgreSQL 9.4+ supports the FILTER() clause for conditional aggregation in place of CASE statements:
SELECT p.id,
SUM(quantity) FILTER (WHERE grp = 1) SUMExpenseItems,
SUM(quantity) FILTER (WHERE grp = 2) SUMIncomeItems
FROM
-- ...same union all query...
GROUP BY p.id

get continuosly increasing sale records from table sql server

I have 2 tables
Product
ProdId, ProdName
1 A
2 B
and
Sale
SaleId, ProdId, Sale, Year
1, 1, 100, 2012
2, 1, 130, 2013
3, 2, 100, 2012,
4, 1, 150, 2014,
5, 1, 180, 2015
6, 2, 120, 2013,
7, 2, 90, 2014,
8, 2, 130, 2015
I want the name of product whose sale is continuosly increasing.
Like Product "A" has sale record like in year 2012 - 100 Units,2013 - 130 Units,2014 - 150 Units,2015 - 180 Units, So this product A is having continuous increase in sale. Another case of non-continuous record is, product "B" having sale record 2012 - 100 Units,2013 - 120 Units,2014 - 90 Units, 2015 - 130 Units, So for product "B", it is not continuous.
I want records like product "A", who is having continuous increasing sale.
Help appreciated.
You can do this using row_number() twice:
select prod_id
from (select s.*,
row_number() over (partition by s.prod_id order by sale) as seqnum_s,
row_number() over (partition by s.prod_id order by year) as seqnum_y
from sales s
) s
group by prod_id
having sum( case when seqnum_s = seqnum_y then 1 else 0 end) = count(*);
That is, order by the year and the sales. When all row numbers are the same, then the sales are increasing.
Note: There are some cases where tied sales might be considered increasing. This can be handled by the logic -- either by excluding or including such situations. I have not included logic for this, because your question is not clear what to do in that situation.
Use cross apply to get the previous year's sale amount and check with conditional aggregation for the increasing amount condition.
select prodid
from sale s1
cross apply (select sale as prev_sale
from sale s2
where s1.prodid=s2.prodid and s2.year=s1.year-1) s2
group by prodid
having sum(case when sale-prev_sale<0 then 1 else 0 end) = 0
To get the all the rows for such prodId's, use
select * from sale
where prodid in (select prodid
from sale s1
cross apply (select sale as prev_sale
from sale s2
where s1.prodid=s2.prodid and s2.year=s1.year-1) s2
group by prodid
having sum(case when sale-prev_sale<0 then 1 else 0 end) = 0
)
Here's a way with a CTE
declare #sale table (SaleID int, ProdId int, Sale int, Year int)
insert into #sale
values
(1,1,100,2012),
(2,1,130,2013),
(3,2,100,2012),
(4,1,150,2014),
(5,1,180,2015),
(6,2,120,2013),
(7,2,90,2014),
(8,2,130,2015)
declare #product table (ProdID int, ProdName char(1))
insert into #product
values
(1,'A'),
(2,'B')
;with cte as(
select
row_number() over (partition by ProdId order by Year) as RN
,*
from #sale)
select
p.ProdName
,cte.*
from cte
inner join
#product p on
p.ProdID=cte.ProdId
where cte.ProdId IN
(select distinct
c1.ProdId
from cte c1
left join
cte c2 on c2.RN = c1.rn+1 and c2.ProdId = c1.ProdId
group by c1.ProdId
having min(case when c1.Sale < isnull(c2.Sale,999999) then 1 else 0 end) = 1)
RETURNS
+----------+----+--------+--------+------+------+
| ProdName | RN | SaleID | ProdId | Sale | Year |
+----------+----+--------+--------+------+------+
| A | 1 | 1 | 1 | 100 | 2012 |
| A | 2 | 2 | 1 | 130 | 2013 |
| A | 3 | 4 | 1 | 150 | 2014 |
| A | 4 | 5 | 1 | 180 | 2015 |
+----------+----+--------+--------+------+------+

How to compute the differential sum per group of values based on order

I have an invoice table which contains customers, the products they bought, and the amount of sales.
+----------+---------+-------+
| customer | product | sales |
+----------+---------+-------+
| bob | apple | 10 |
| john | apple | 8 |
| sarah | apple | 3 |
| bob | pear | 22 |
| glenn | pear | 13 |
| tim | pear | 8 |
| cody | pear | 4 |
+----------+---------+-------+
This table would be generated by a query of
SELECT customer, product, SUM(sales)
FROM Invoice
GROUP BY customer, product
ORDER BY product, SUM(sales) desc
Is it possible to write a query that computes - per product - the sum of the difference in sales between the top customer and the rest? For example, for apple, the value would be 9. (10 - 8) + (10 - 3) = 9. For pear, the value would be 41. (22 - 13) + (22 - 8) + (22-4) = 41.
This new query would return a result of
+---------+-----------+
| product | salesDiff |
+---------+-----------+
| apple | 9 |
| pear | 41 |
+---------+-----------+
For products that have only 1 customer, i would like the query to return 0 in sales difference.
Yes.
Start by determining the max per product. Then sum the difference.
I've included your sample data and added a single customer buying oranges to demonstrate that aspect of the requirement.
declare #t table (
Customer varchar(10),
Product varchar(10),
Sales int
)
insert #t
select 'john', 'orange', 10 union all
select 'bob', 'apple', 10 union all
select 'john', 'apple', 8 union all
select 'sarah', 'apple', 3 union all
select 'bob', 'pear', 22 union all
select 'glenn', 'pear', 13 union all
select 'tim', 'pear', 8 union all
select 'cody', 'pear', 4
;with MaxSalesPerProduct as (
select MAX(Sales) ms, Product
from #t t
group by t.Product
)
select t.Product, SUM(ms.ms - t.Sales)
from #t t
inner join MaxSalesPerProduct ms on
ms.Product = t.Product
group by t.Product
Note that no special handling of the 'top customer' is needed because the difference there cancels out to 0.
Addendum
While my original answer works with the sample data you provided, it does assume only a single row per customer+product combination. If this is not the case, then you'll need to adjust the query to take that into consideration.
;with SalesPerCustomer as (
select SUM(Sales) CustomerSales, t.Product, t.Customer
from #t t
group by t.Product, t.Customer
), SaleStats as (
select spc.Product, MAX(spc.CustomerSales) MaxSales, COUNT(*) CustomerCount, SUM(spc.CustomerSales) TotalSales
from SalesPerCustomer spc
group by spc.Product
)
select *, MaxSales*CustomerCount - TotalSales as DiffSum
from SaleStats
Wrap your query with one more grouping
SELECT product, count(customer)*max(sales) - SUM(sales) as diff
FROM (
SELECT customer, product, SUM(sales) as sales
FROM Invoice
GROUP BY customer, product
) t
GROUP BY product
ORDER BY SUM(sales) desc
Simplest way should be to find max of sum of sales in the same query where you're finding sum of sales and then just sum up the differences by aggregating on product.
Try this:
select
product, sum(max_sales - sales) salesDiff
from (
SELECT customer, product, SUM(sales) sales, max(SUM(sales)) over (partition by product) max_sales
FROM Invoice
GROUP BY customer, product
) t
group by product;
Sure.
create table dbo.Customer_Prod
(Customer varchar(32),
Product varchar (32),
Sales real
)
insert into dbo.Customer_Prod values ('bob', 'apple', 10), ('john', 'apple', 8),('sarah', 'apple', 3),('bob', 'pear', 22),('glenn', 'pear', 13),('tim', 'pear', 8),('cody', 'pear', 4)
with max_sales_Per_Product as (
Select max(Sales) as Max_Sales, product
from [AtlasDB].[dbo].[Customer_Prod]
Group by Product
)
Select sum(B.Max_Sales - (A.sales)) AS Diff_Sales, A.Product
from [AtlasDB].[dbo].[Customer_Prod] A LEFT OUTER JOIN
max_sales_Per_Product B on B.Product=A.Product
group by A.Product

Solve QUERY for showing TOP 5 selling Products

I have a table of Customer_Invoice having columns of item_name and Quantity. I want to show the top 5 Items on the specific item & Item Quantity Sold in Descending order i-e if the number of item A is sold 5 and the number of item B is sold 3 then Item A should be on Top and and item B will be on 2nd number.
| ITEMCODE | QUANTITY |
------------------------
| kb434 | 1 |
| A4tech123 | 4 |
| HDD40GB | 4 |
| Cell12 | 4 |
| Icd123 | 2 |
| A4tech123 | 6 |
In the above diagram I want A4tech123 on 1st no HDD40GB on 2nd No, Cell12 on third no and so on.
select top 5 Item_code, sum(Quantity)
from customer_invoice
group by Item_code
Order by sum(Quantity) desc
select top 5 item_name , sum(Quantity) as Quantity from Customer_Invoice
group by item_name
ORDER BY sum(Quantity) DESC
If you are using the postgres as DB then use the below query:
select Item_code, Quantity from customer_invoice order by Quantity desc limit 5
OR
if you using any other DB use this query:
select top 5 Item_code, Quantity from customer_invoice order by Quantity desc
i didn't checked the second as i am using Postgres DB, so before using confirm that query
CREATE TABLE invoice
(ITEMCODE varchar(9), QUANTITY int)
;
INSERT INTO invoice
VALUES
('kb434', 1),
('A4tech123', 4),
('HDD40GB', 4),
('Cell12', 4),
('Icd123', 2),`
('A4tech123', 6)
;
SELECT ITEMCODE,
SUM(QUANTITY) as total_quantity,
ROW_NUMBER() OVER (order by sum(QUANTITY) desc) as rank_n
FROM invoice
GROUP BY ITEMCODE
http://sqlfiddle.com/#!18/da13e/6
SELECT TOP 5 * FROM Customer_Invoice ORDER BY QUANTITY