SQL - Select number of record based on SUM conditions - sql

if you have a order table, is that possible to select all the records which have sum of amount smaller than $1000, assuming that the table already ordered by amount desc
Example:
id product_id amount
1 1 500
2 3 400
3 2 300
4 1 200
Get all the orders which have sum of amount smaller than $1000
then it should return 1 & 2, because the sum of amount of 1 and 2 is 900 < 1000
Get all the orders which have sum of amount smaller than $1300
then it should return 1,2,3 because the sum of amount of 1,2,3 is 1200 < 1300

You are looking for a cumulative sum:
select t.*
from (select t.*, sum(t.amount) over (order by t.amount desc) as cume_amount
from t
) t
where cume_amount < 1000;

with a as (
select sum(amount) over (order by amount desc ) as amount_1 from test_order
)
select * from a where amount_1 < 1000;

Related

SQLite return dataset where top 4 aggregated records are single rows and rest records are agrageted as one row

Sorry for not very good title but maybe someone can help me to understand how to write query using sqlite. So I have table where stored transactions which are assigned to some category I want to sum amount group by category and get top 4 rows, rest records have to be summed with grouping and returned as one row
id
amount
category
1
10
shopping
2
40
mortgage
3
15
shopping
4
10
insurance
5
5
entertainment
6
8
some category 1
7
10
some category 2
And I need result like this
Category
Amount
Mortgage
40
Shopping
25
Insurance
10
some category 2
10
others
13
So how you can see I sum amount of each category and order them after 4th record I sum rest and return as single record
You can use SUM() aggregation and ROW_NUMBER() window function in order to filter the Category others such as
WITH t AS
(
SELECT Category, SUM(Amount) AS sum
FROM tab
GROUP BY Category
), t1 AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY sum DESC ) AS dr
FROM t
)
SELECT Category, sum AS Amount FROM t1 WHERE dr <= 4
UNION ALL
SELECT 'others', SUM(sum) FROM t1 WHERE dr > 4
Demo
You can do it with 2 levels of aggregation and ROW_NUMBER() window function:
SELECT category, SUM(amount) amount
FROM (
SELECT CASE WHEN ROW_NUMBER() OVER (ORDER BY SUM(amount) DESC) <= 4 THEN category ELSE 'others' END category,
SUM(amount) amount
FROM tablename
GROUP BY category
)
GROUP BY category
ORDER BY category = 'others', amount DESC
See the demo.
Results:
category
amount
mortgage
40
shopping
25
insurance
10
some category 2
10
others
13

SQL sum grouped by field with all rows

I have this table:
id sale_id price
-------------------
1 1 100
2 1 200
3 2 50
4 3 50
I want this result:
id sale_id price sum(price by sale_id)
------------------------------------------
1 1 100 300
2 1 200 300
3 2 50 50
4 3 50 50
I tried this:
SELECT id, sale_id, price,
(SELECT sum(price) FROM sale_lines GROUP BY sale_id)
FROM sale_lines
But get the error that subquery returns different number of rows.
How can I do it?
I want all the rows of sale_lines table selecting all fields and adding the sum(price) grouped by sale_id.
You can use window function :
sum(price) over (partition by sale_id) as sum
If you want sub-query then you need to correlate them :
SELECT sl.id, sl.sale_id, sl.price,
(SELECT sum(sll.price)
FROM sale_lines sll
WHERE sl.sale_id = sll.sale_id
)
FROM sale_lines sl;
Don't use GROUP BY in the sub-query, make it a co-related sub-query:
SELECT sl1.id, sl1.sale_id, sl1.price,
(SELECT sum(sl2.price) FROM sale_lines sl2 where sl2.sale_id = sl.sale_id) as total
FROM sale_lines sl1
In addition to other approaches, You can use CROSS APPLY and get the sum.
SELECT id, sale_id,price, Price_Sum
FROM YourTable AS ot
CROSS APPLY
(SELECT SUM(price) AS Price_Sum
FROM YourTable
WHERE sale_id = ot.sale_id);
SELECT t1.*,
total_price
FROM `sale_lines` AS t1
JOIN(SELECT Sum(price) AS total_price,
sale_id
FROM sale_lines
GROUP BY sale_id) AS t2
ON t1.sale_id = t2.sale_id

Divide each value of a column by the total count of records in a table

A query that is capable of dividing each value of a column by the total number of records in the table
I tried the following query
select ( (p.rank/count(*)) * 100 ) as rankratio from RankTable p;
I see an error and not able to execute the query.
for example
total records is 5 so (1/5)*100 = 20
RankTable
rank rankratio
1 20
2 40
3 60
4 80
5 100
use analytic count(*) over():
select ( (s.rank/s.total_count) * 100 ) as rankratio
from
(
select rank, count(*) over() as total_count
from RankTable p
)s
order by s.rank;

Sum function in SQL Server 2008

I have a table:
PropertyID Amount
--------------------------
1 40
1 20
1 10
2 10
2 90
I would like to achieve :
PropertyId Amount Total_Amount
---------------------------------------
1 40 70
1 20 70
1 10 70
2 10 100
2 90 100
using below query :
SELECT
PropertyID,
SUM(Amount),
SUM(TotalAmount)
FROM
yourTable
WHERE
EndDate IS NULL
GROUP BY
PropertyID
Output:
PropertyId Amount TotalAmount
-------------------------------------
1 70 70
2 100 100
Let me know how can I get my desired output ...
You can do this using window functions:
select PropertyID, Amount,
sum(Amount) over (partition by PropertyId) as TotalAmount
from yourtable;
The window function for sum() does the following. It calculates the sum of amount for groups of rows in the same group. The group is defined by the partition by clause, so rows with the same value of PropertyId are in the same group.
SELECT PropertyID,
Amount,
(select sum(yt.Amount)
from yourTable yt where yt.PropertyID==y.PropertyID and yt.EndDate IS NULL)
as TotalAmount
FROM yourTable y
WHERE y.EndDate IS NULL

How to select Remain values after subtract with one Fixed value

Need To select Data From One Table After Minus With One Value
this is the question i already asked and this solution for one value input to table and result. but i need this with more input values for different categories and each categories output
for eg(based of previous question)
Table 1
SNo Amount categories
1 100 type1
2 500 type1
3 400 type1
4 100 type1
5 100 type2
6 200 type2
7 300 type2
8 500 type3
9 100 type3
and
values for type1 - 800
values for type2 - 200
values for type3 - 100
and the output need is
for type-1
800 - 100 (Record1) = 700
700 - 500 (record2) = 200
200 - 400 (record3) = -200
The table records starts from record 3 with Balance Values Balance 200
Table-Output
SNo Amount
1 200
2 100
that means if minus 800 in first table the first 2 records will be removed and in third record 200 is Balance
same operation for remain types also and how to do it?
SQLFiddle demo
with T1 as
(
select t.*,
SUM(Amount) OVER (PARTITION BY [Type] ORDER BY [SNo])
-
CASE WHEN Type='Type1' then 800
WHEN Type='Type2' then 200
WHEN Type='Type3' then 100
END as Total
from t
)select Sno,Type,
CASE WHEN Amount>Total then Total
Else Amount
end as Amount
from T1 where Total>0
order by Sno
UPD: If types are not fixed then you should create a table for them, for example:
CREATE TABLE types
([Type] varchar(5), [Value] int);
insert into types
values
('type1',800),
('type2',200),
('type3',100);
and use the following query:
with T1 as
(
select t.*,
SUM(Amount) OVER (PARTITION BY t.[Type] ORDER BY [SNo])
-
ISNULL(types.Value,0) as Total
from t
left join types on (t.type=types.type)
)select Sno,Type,
CASE WHEN Amount>Total then Total
Else Amount
end as Amount
from T1 where Total>0
order by Sno
SQLFiddle demo
UPDATE: For MSSQL 2005 just replace SUM(Amount) OVER (PARTITION BY t.[Type] ORDER BY [SNo]) with (select SUM(Amount) from t as t1
where t1.Type=t.Type
and t1.SNo<=t.SNo)
with T1 as
(
select t.*,
(select SUM(Amount) from t as t1
where t1.Type=t.Type
and t1.SNo<=t.SNo)
-
ISNULL(types.Value,0) as Total
from t
left join types on (t.type=types.type)
)select Sno,Type,
CASE WHEN Amount>Total then Total
Else Amount
end as Amount
from T1 where Total>0
order by Sno
SQLFiddle demo