Running Total by Group SQL (Oracle) - sql

I have a table in an Oracle db that has the following fields of interest: Location, Product, Date, Amount. I would like to write a query that would get a running total of amount by Location, Product, and Date. I put an example table below of what I would like the results to be.
I can get a running total but I can't get it to reset when I reach a new Location/Product. This is the code I have thus far, any help would be much appreciated, I have a feeling this is a simple fix.
select a.*, sum(Amount) over (order by Location, Product, Date) as Running_Amt
from Example_Table a
+----------+---------+-----------+------------+------------+
| Location | Product | Date | Amount |Running_Amt |
+----------+---------+-----------+------------+------------+
| A | aa | 1/1/2013 | 100 | 100 |
| A | aa | 1/5/2013 | -50 | 50 |
| A | aa | 5/1/2013 | 100 | 150 |
| A | aa | 8/1/2013 | 100 | 250 |
| A | bb | 1/1/2013 | 500 | 500 |
| A | bb | 1/5/2013 | -100 | 400 |
| A | bb | 5/1/2013 | -100 | 300 |
| A | bb | 8/1/2013 | 250 | 550 |
| C | aa | 3/1/2013 | 550 | 550 |
| C | aa | 5/5/2013 | -50 | 600 |
| C | dd | 10/3/2013 | 999 | 999 |
| C | dd | 12/2/2013 | 1 | 1000 |
+----------+---------+-----------+------------+------------+

Ah, I think I have figured it out.
select a.*, sum(Amount) over (partition by Location, Product order by Date) as Running_Amt
from Example_Table a

from Advanced SQL Functions in Oracle 10g book, it has this example.
SELECT dte "Date", location, receipts,
SUM(receipts) OVER(ORDER BY dte
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW) "Running total"
FROM store
WHERE dte < '10-Jan-2006'
ORDER BY dte, location

I could type out all the answer or send you to where I learned it. :)
Check this out, it explains exactly what you are trying to do.
http://www.codeproject.com/Articles/300785/Calculating-simple-running-totals-in-SQL-Server

Related

how to do dynamic sum and substraction [duplicate]

I have a table in an Oracle db that has the following fields of interest: Location, Product, Date, Amount. I would like to write a query that would get a running total of amount by Location, Product, and Date. I put an example table below of what I would like the results to be.
I can get a running total but I can't get it to reset when I reach a new Location/Product. This is the code I have thus far, any help would be much appreciated, I have a feeling this is a simple fix.
select a.*, sum(Amount) over (order by Location, Product, Date) as Running_Amt
from Example_Table a
+----------+---------+-----------+------------+------------+
| Location | Product | Date | Amount |Running_Amt |
+----------+---------+-----------+------------+------------+
| A | aa | 1/1/2013 | 100 | 100 |
| A | aa | 1/5/2013 | -50 | 50 |
| A | aa | 5/1/2013 | 100 | 150 |
| A | aa | 8/1/2013 | 100 | 250 |
| A | bb | 1/1/2013 | 500 | 500 |
| A | bb | 1/5/2013 | -100 | 400 |
| A | bb | 5/1/2013 | -100 | 300 |
| A | bb | 8/1/2013 | 250 | 550 |
| C | aa | 3/1/2013 | 550 | 550 |
| C | aa | 5/5/2013 | -50 | 600 |
| C | dd | 10/3/2013 | 999 | 999 |
| C | dd | 12/2/2013 | 1 | 1000 |
+----------+---------+-----------+------------+------------+
Ah, I think I have figured it out.
select a.*, sum(Amount) over (partition by Location, Product order by Date) as Running_Amt
from Example_Table a
from Advanced SQL Functions in Oracle 10g book, it has this example.
SELECT dte "Date", location, receipts,
SUM(receipts) OVER(ORDER BY dte
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW) "Running total"
FROM store
WHERE dte < '10-Jan-2006'
ORDER BY dte, location
I could type out all the answer or send you to where I learned it. :)
Check this out, it explains exactly what you are trying to do.
http://www.codeproject.com/Articles/300785/Calculating-simple-running-totals-in-SQL-Server

how to sum a column of a queried table in sql

I have this table from a query and I would like to find the sum of the Total Cost (after discount). I have searched for a solution but I can't seem to find the one I'm looking for.
Here are the sample data from my tables
Booking
+-----------+-------------+----------+------------+
| vehicleNo |  bookingDay | driverNo | acc_status |
+-----------+-------------+----------+------------+
| 10 | 13/06/2021 | 2 | B |
| 10 | 14/06/2021 | 0 | B |
| 10 | 15/06/2021 | 2 | B |
| 20 | 17/06/2021 | 2 | B |
+-----------+-------------+----------+------------+
Vehicle
+-----------+-------------+----------------+------+
| vehicleNo |  vehicleReg | make_model | cost |
+-----------+-------------+----------------+------+
| 10 | IN10NGT | Nissan R34 GTR | 90 |
| 20 | IN10MRX | Mazda RX7 | 70 |
| 30 | IN10TSU | Toyota Supra | 80 |
+-----------+-------------+----------------+------+
Here is the query
SELECT IF(COUNT(Vehicle.vehicleNo) > 1, ROUND(Vehicle.cost,1) * ROUND(COUNT(Vehicle.vehicleNo) * 0.9,1), Vehicle.cost * ROUND(COUNT(Vehicle.vehicleNo),1)) AS 'Total after discount'
FROM Booking
INNER JOIN Vehicle
ON Vehicle.vehicleNo = Booking.vehicleNo
WHERE Booking.driverNo = 2
GROUP BY Vehicle.vehicleNo
ORDER BY Vehicle.vehicleNo;
an here is the result
+----------------------+
| Total after discount |
+----------------------+
| 162 |
| 70 |
+----------------------+
and I am expecting to have a table after calculating the sum like this
+----------------------+
| Overall cost |
|after discount |
+----------------------+
| 232 |
+----------------------+
any help is much appreciated.
i have figured it out. i used this query:
SELECT SUM(Cost) FROM (SELECT IF(COUNT(Vehicle.vehicleNo) > 1, ROUND(Vehicle.cost,1) * ROUND(COUNT(Vehicle.vehicleNo) * 0.9,1), Vehicle.cost * ROUND(COUNT(Vehicle.vehicleNo),1)) AS Cost
FROM Vehicle INNER JOIN Booking
ON Vehicle.vehicleNo = Booking.vehicleNo AND Booking.driverNo = 2
GROUP BY Vehicle.vehicleNo) AS x;

Determine closest date to another date value teradata

My dataset looks like this. For every combination of customerid,orderid and ship date, i would like to retrieve 1 process date that is less than or equal to the ship date. If the process date is greater than the ship date and no lower process date exist, then use the ship date as the process date
+-------------+----------+------------+--------------+--+
| Customer ID | Order ID | Ship Date | Process Date | |
+-------------+----------+------------+--------------+--+
| 1000 | 100 | 9/17/2020 | 9/17/2020 | |
| 1000 | 100 | 9/17/2020 | 10/16/2020 | |
| 1000 | 100 | 9/17/2020 | 9/16/2020 | |
| 2000 | 200 | 8/15/2020 | 8/13/2020 | |
| 2000 | 300 | 10/14/2020 | 10/13/2020 | |
| 3000 | 400 | 3/4/2020 | 4/2/2020 | |
| 3000 | 400 | 3/4/2020 | 3/3/2020 | |
| 3000 | 400 | 3/4/2020 | 3/5/2020 | |
| 4000 | 500 | 5/1/2020 | 5/3/2020 | |
| 5000 | 600 | 6/1/2020 | 7/1/2020 | |
| 5000 | 600 | 6/1/2020 | 7/2/2020
| 6000 | 700 | 7/14/2020 | 7/13/2020 | |
| 6000 | 700 | 7/14/2020 | 6/10/2020 | |
+-------------+----------+------------+--------------+--+ | |
+-------------+----------+------------+--------------+--+
Desired Output
+-------------+----------+------------+--------------+--+
| Customer ID | Order ID | Ship Date | Process Date | |
+-------------+----------+------------+--------------+--+
| 1000 | 100 | 9/17/2020 | 9/17/2020 | |
| 2000 | 200 | 8/15/2020 | 8/13/2020 | |
| 2000 | 300 | 10/14/2020 | 10/13/2020 | |
| 3000 | 400 | 3/4/2020 | 3/3/2020 | |
| 4000 | 500 | 5/1/2020 | 5/1/2020 | |
| 5000 | 600 | 6/1/2020 | 6/1/2020 | |
| 6000 | 700 | 7/14/2020 | 7/13/2020 | |
+-------------+----------+------------+--------------+--+
I tried using ROWNUM and date difference, but I'm stuck after getting the row number in ascending order.Not sure how to proceed ahead.
"If the process date is greater than the ship date and no lower process date exist, then use the ship date as the process date."
Do a GROUP BY. You can use MAX() to return the latest ProcessDate <= ShipDate. If no such ProcessDate exists, return ShipDate.
select CustomerID, orderID, ShipDate,
coalesce(MAX(case when ProcessDate <= ShipDate then ProcessDate end), ShipDate)
from tablename
group by CustomerID, orderID, ShipDate
I think you want filtering and row_number():
select t.*
from (select t.*,
row_number() over (partition by customer_id, order_id, ship_date order by process_date desc) as seqnum
from t
where process_date <= ship_date
) t
where seqnum = 1;
I'm not sure if customer_id and ship_date are really needed in the partition by clause. order_id seems sufficient.
This should return the expected result:
select CustomerID, orderID, ShipDate,
-- If the process date is greater than the ship date and no lower
-- process date exist, then use the ship date as the process date
least(ProcessDate, ShipDate)
from tablename
qualify
-- retrieve 1 process date that is less than or equal to the ship date
row_number()
over (partition by CustomerID, orderI
order by case when ProcessDate <= ShipDate then ProcessDate end desc nulls last) = 1

SQL - Join on changing dates

I've been scratching my head on this for a week now.
Consider two tables - one tallying inventory:
+------------+--------------+----------+-------------------+
| product_id | product_name | date | on_hand_inventory |
+------------+--------------+----------+-------------------+
| 1 | Product A | 6/1/2019 | 37 |
| 1 | Product A | 6/2/2019 | 36 |
| 1 | Product A | 6/3/2019 | 35 |
| 1 | Product A | 6/4/2019 | 40 |
| 1 | Product A | 6/5/2019 | 42 |
+------------+--------------+----------+-------------------+
... and another tracking costs:
+------------+----------------+------------+------------+------------+
| product_id | cost_component | cost_value | start_date | end_date |
+------------+----------------+------------+------------+------------+
| 1 | FOB | 15 | 1/1/2019 | 6/1/2019 |
| 1 | FOB | 15.5 | 6/2/2019 | 6/3/2019 |
| 1 | FOB | 16 | 6/4/2019 | 12/31/9999 |
+------------+----------------+------------+------------+------------+
The layout of the cost table is what's driving me nuts. I need to join these
tables to keep a running valuation of on-hand inventory, and I can't think of a
method in SQL that would let me select the appropriate row in the cost table.
A join on produt_id doesn't work because it would return all cost components for
that item whether or not they apply to that date. I feel like should be
involving a CASE statement, but I'm not sure what that would look like.
This is in MSSQL 2016, for what its worth.
If you want the most recent cost, you can use join:
select t.*, c.*
from inventory i join
costs c
on c.product_id = i.product_id and
i.date between c.start_date and c.end_date;

how to adjust the sum() of a group using the sum() of a subgroup()

I am trying to get the Output shown in the third table below using the tables "Assets" and "Transactions".
I am trying to group by Cmpy, Acct and AssetID and get the Sum(cost). But each cost has to be adjusted from the Transactions table before being summed. Not sure how to do it.
Table: Assets
+----------+------+---------+--------+
| Cpny | Acct | AssetID | Cost |
+----------+------+---------+--------+
| 50 | 120 | 109 | 100.00 |
| 50 | 120 | 109 | 200.00 |
| 50 | 120 | 110 | 300.00 |
| 50 | 120 | 110 | 20.00 |
| 50 | 121 | 107 | 150.00 |
| 50 | 121 | 201 | 200.00 |
+----------+------+---------+--------+
Table: Transactions
+------+---------+--------+
| Cpny | AssetID | Amt |
+------+---------+--------+
| 50 | 109 | -50.00 |
| 50 | 110 | 50.00 |
| 50 | 110 | -20.00 |
| 50 | 201 | -50.00 |
+------+---------+--------+
OUTPUT
+------+------+--------+
| Cpny | Acct | Total |
+------+------+--------+
| 50 | 120 | 600.00 |
| 50 | 121 | 300.00 |
+------+------+--------+
This one should give you an accurate answer:
SELECT a.Cpny,
a.Acct,
SUM(a.Cost + ISNULL(t.Adjustment, 0)) AS Total
FROM Assets a
LEFT JOIN (SELECT Cpny,
AssetID,
SUM(Amt) AS Adjustment
FROM Transactions
GROUP BY Cpny, AssetID) t
ON t.Cpny = a.Cpny AND t.AssetID = a.AssetID
GROUP BY a.Cpny, a.Acct
Associated SQLFiddle here.
Essentially, SUM the adjustment amounts in the transactions table, then join this to the main results list, summing the cost plus the adjustment for each asset in each account.
If the "relationship" between Acct and AssetID values are 1 to many then you could use this query (which is not so efficient):
SELECT x.Cpny,x.Acct, SUM( ISNULL(x.Total,0) + ISNULL(y.Total,0) ) AS Total
FROM
(
SELECT a.Cpny,a.Acct,a.AssetID, SUM(a.Cost) AS Total
FROM dbo.Assets a
GROUP BY a.Cpny,a.Acct,a.AssetID
) x
LEFT JOIN
(
SELECT t.Cpny,t.AssetID, SUM(t.Cost) AS Total
FROM dbo.Transactions t
GROUP BY t.Cpny,t.AssetID
) y ON x.Cpny=y.Cpny AND x.AssetID=y.AssetID
GROUP BY x.Cpny,x.Acct;