Grouping by most commonly repeated values - sql

I have series of data like below
PRICE AMOUNT TOTAL BUYER SELLER
2.43 250 607,5 TRADER_B TRADER_B(*)
2.43 500 1215 TRADER_D TRADER_B(*)
2.43 13000 31590 TRADER_D TRADER_B(*)
2.43 17000 41310 TRADER_C TRADER_B(*)
2.43 15000 36450 TRADER_A TRADER_B(*)
2.43 10000 24300 TRADER_E TRADER_B(*)
2.43 20000 48600 TRADER_F TRADER_B(*)
2.42 100 242 TRADER_A(*) TRADER_C
2.42 1500 3630 TRADER_A(*) TRADER_F
2.42 10000 24200 TRADER_A(*) TRADER_F
2.42 14500 35090 TRADER_A(*) TRADER_C
2.42 11000 26620 TRADER_A(*) TRADER_A
2.41 400 964 TRADER_A(*) TRADER_B
2.41 200 482 TRADER_B TRADER_C
2.41 1200 2892 TRADER_C TRADER_A
2.40 1000 2400 TRADER_B TRADER_D
2.40 15000 36000 TRADER_F TRADER_E(*)
2.40 20000 48000 TRADER_F TRADER_E(*)
2.40 7500 18000 TRADER_B TRADER_E(*)
2.40 8000 19200 TRADER_A TRADER_E(*)
2.40 2500 6000 TRADER_D TRADER_E(*)
2.40 3500 8400 TRADER_B TRADER_E(*)
My aim, to catching up most stronger buyers and sellers on a stock. That is why I need to grouping by most commonly repeated values according to the BUYER and SELLER columns (I specified the rows by *).
THE BEST BUYERS AMOUNT TOTAL
TRADER_A 37500 90746
THE BEST SELLERS AMOUNT TOTAL
TRADER_E 56500 135600
TRADER_B 75750 184072

If you want the aggregation based on the most common price for each buyer, it would look like:
select bp.*
from (select buyer, price, sum(amount) as amount, sum(total) as total,
row_number() over (partition by buyer order by count(*) desc) as seqnum
from t
group by buyer, price
) bp
where seqnum = 1;

Related

How to find value from a slab range?

I need to filter commission depend on amount means I give a amount like 300000 and get the commission for those slab where 300000 is match
SlabStartAmount
SlabEndAmount
CommissionAmount
100000
200000
62.5
2000001
5000000
75
5000001
7500000
81.25
7500001
10000000
87.5
10000001
0
100
You can use a condition to find out the slab
WHERE #Amount BETWEEN SlabStartAmount AND SlabEndAmount
See this fiddle.

plsql sum another table values to joined tables

I have 3 tables.First table is student.Second is student_detail and last one special_codes.
student table
studentname | invoiceno |tax |invoiceamount
Paul 10 500 1950
Georghe 20 1000 6850
Mary 30 1500 1900
Messy 40 2000 7050
studentdetail
invoiceno | code | product | amount
10 101 pencil 100
10 102 rubber 350
10 103 bag 1500
20 108 wheel 5000
20 109 tv 1500
20 110 ps 300
20 111 mouse 50
30 103 bag 1500
30 105 keyboard 400
40 111 mouse 50
40 112 car 7000
I can join these two table like this and get result table
select s.studentname,s.tax,s.invoiceamount,st.product,sum(st.amount) from student s, studentdetail st
where s.invoiceno = st.invoiceno
group by
s.studentname,
s.tax,
s.invoiceamount,
st.product
result table
studentname tax invoiceamount product amount
Paul 500 1950 bag 1500
Paul 500 1950 pencil 100
Paul 500 1950 rubber 350
Messy 2000 7050 car 7000
Messy 2000 7050 mouse 50
Mary 1500 1900 bag 1500
Mary 1500 1900 keyboard 400
Georghe 1000 6850 mouse 50
Georghe 1000 6850 ps 300
Georghe 1000 6850 tv 1500
Georghe 1000 6850 wheel 5000
Last table is special codes.It contains only one column which is called code
specialcodes table
code
101
102
113
104
105
110
111
What i want to do is to look up studentdetail table and to find codes that are same in specialcodes.Then to sum amount values and write sum to result table as another column.Result table
should be like that
result table(final)
studentname tax invoiceamount product amount taxexclude
Paul 500 1950 bag 1500 450
Paul 500 1950 pencil 100 450
Paul 500 1950 rubber 350 450
Messy 2000 7050 car 7000 50
Messy 2000 7050 mouse 50 50
Mary 1500 1900 bag 1500 400
Mary 1500 1900 keyboard 400 400
Georghe 1000 6850 mouse 50 350
Georghe 1000 6850 ps 300 350
Georghe 1000 6850 tv 1500 350
Georghe 1000 6850 wheel 5000 350
You can use analytic functions rather than GROUP BY and aggregating:
select s.studentname,
s.tax,
invoiceamount,
SUM(d.amount) OVER (PARTITION BY s.invoiceno) AS inv_amt_calc,
d.product,
d.amount,
SUM(CASE WHEN c.code IS NOT NULL THEN d.amount END)
OVER (PARTITION BY s.invoiceno) AS taxexclude
from student s
INNER JOIN studentdetail d
ON s.invoiceno = d.invoiceno
LEFT OUTER JOIN specialcodes c
ON (c.code = d.code)
Note: You can (and should) calculate the invoice amount from the studentdetails table rather than duplicating the data in the student table and violating Third-Normal Form.
Which, for your sample data, outputs:
STUDENTNAME
TAX
INVOICEAMOUNT
INV_AMT_CALC
PRODUCT
AMOUNT
TAXEXCLUDE
Paul
500
1950
1950
rubber
350
450
Paul
500
1950
1950
pencil
100
450
Paul
500
1950
1950
bag
1500
450
Georghe
1000
6850
6850
tv
1500
350
Georghe
1000
6850
6850
wheel
5000
350
Georghe
1000
6850
6850
ps
300
350
Georghe
1000
6850
6850
mouse
50
350
Mary
1500
1900
1900
bag
1500
400
Mary
1500
1900
1900
keyboard
400
400
Messy
2000
7050
7050
mouse
50
50
Messy
2000
7050
7050
car
7000
50
If you really want a version using GROUP BY then:
SELECT s.studentname,
s.tax,
s.invoiceamount,
SUM(d.amount) OVER (PARTITION BY s.invoiceno) AS inv_amt_calc,
d.product,
d.amount,
t.taxexclude
FROM student s
INNER JOIN studentdetail d
ON s.invoiceno = d.invoiceno
LEFT OUTER JOIN (
SELECT invoiceno,
SUM(amount) AS taxexclude
FROM studentdetail
WHERE code IN (SELECT code FROM specialcodes)
GROUP BY
invoiceno
) t
ON s.invoiceno = t.invoiceno;
db<>fiddle here

Dynamic subtraction in SQL

I have a table structure like this:
|Account | MaxBalance | UsedAmount|
|--------|-------------|-----------|
Acc1 10000 2000
Acc2 20000 4000
Acc3 50000 2000
Acc3 50000 3000
Acc3 50000 8000
Acc4 20000 1000
Acc4 20000 5000
Acc5 5000 500
The output that I want is for same account usedAmount is dynamically deleted from new remainingAmount.
Account | MaxBalance | UsedAmount | Remaining
----------------------------------------------
Acc1 10000 2000 8000
Acc2 20000 4000 16000
Acc3 50000 2000 48000
Acc3 50000 3000 45000
Acc3 50000 8000 37000
Acc4 20000 1000 19000
Acc4 20000 5000 14000
Acc5 5000 500 4500
This is really cumulative sum -- and then subtraction using that. However, you need a column that specifies the ordering, so I'll assume you have one (otherwise the question doesn't make sense):
select t.*,
(maxbalance -
sum(usedamount) over (partition by account order by <ordering col>)
) as remaining
from t;
Here is a db<>fiddle showing that this does exactly what your question is asking for.

Place product_id into a price range

I would like to add for a given product_id a price range, in 500 increments. For example a product with the price of 450 should have the price range of 500 and a product with a price 2450 should have the price range of 2000.
Main table
product_id price
32828 2593
23224 456
34344 1000
58283 2420
43585 550
Output table
product_id price price_range
32828 2593 3000
23224 456 500
34344 1000 1000
58283 2420 2000
43585 550 600
you could use case when for manage the range as you prefer
select case when price between 0 and 500 then 500
when price between 501 and 600 then 600
when price between 601 and 1500 then 1000
when price between 1501 and 2500 then 2000
END range

Dynamic Columns With Calculated Values

1) StructureTable:
StrId StrName Figure Base On
1 Basic 40 Percent Total
2 D.A. 3495 Amount Total
3 O.A. 0 Remaining Total
2) SalaryTable
StaffId StaffName Salary
1 Ram 25000
2 Shyam 40000
3 Hari 30000
4 Ganesh 15000
3) IncrementTable
StaffId IncAmt
1 5000
2 3000
3 2000
4 4000
Desired Columns Resulted Output by Pivot or others:
StaffId StaffName Basic_Salary D.A_Salary O.A_Salary Total_Salary Basic_Inc D.A_Inc O.A_Inc Total_Inc Basic_Total D.A_Total O.A_Total Total_Total
1 Ram 10000 3495 18495 25000 2000 0 3000 5000 12000 3495 21495 30000
2 Shyam 16000 3495 27495 40000 1200 0 1800 3000 17200 3495 29295 43000
3 Hari 12000 3495 21495 30000 800 0 1200 2000 12800 3495 22695 32000
4 Ganesh 6000 3495 12495 15000 1600 0 2400 4000 7600 3495 14895 19000
Total 44000 13980 79980 110000 5600 0 8400 14000 49600 13980 88380 124000