How to calculate running total grouped by Order No - sql-server-2008

Trying to create a running total for orders in SQL Server 2008, similar to the below table (Order No & Order Total columns exist in my SQL Server table), tried using a recursive cte but my results were a running total for all orders, not grouped by order no. Any suggestions how to have the running total grouped by the order no? Thanks
---------------------------------------------------------
| Order No. | Order Total | Running Total for Order No |
---------------------------------------------------------
| 1 | $10,000 | $10,000 |
---------------------------------------------------------
| 1 | -$5,000 | $5,000 |
---------------------------------------------------------
| 1 | $3,000 | $8,000 |
---------------------------------------------------------
| 2 | $2,500 | $2,500 |
---------------------------------------------------------
| 2 | $5,000 | $7,500 |
---------------------------------------------------------
| 2 | $4,000 | $11,000 |
---------------------------------------------------------

I would do this is with an Instead of Insert Trigger. The trigger would subtract/add from the groups first value. Obviously this should of been done at the creation of the table but you could add it after you make table update.
Keep in mind in order for the below code to work, you would need a primary key on the Order table
CREATE TABLE Orders
(
id INT IDENTITY(0, 1) PRIMARY KEY
, orderNo INT
, orderTotal MONEY
, runningTotal MONEY
);
INSERT INTO Orders
VALUES
(1,10000,10000),
(1,-5000,5000),
(1,3000,8000),
(2,2500,2500),
(2,5000,7500),
(2,4000,11500);
GO
--CREATE TRIGGER
CREATE TRIGGER trg_RunningTotal ON Orders
INSTEAD OF INSERT
AS
BEGIN
DECLARE #PreviousTotal MONEY =
(
SELECT TOP 1
a.runningTotal
FROM Orders AS a
INNER JOIN INSERTED AS b ON a.orderNo = b.orderNo
WHERE a.orderno = b.Orderno
ORDER BY a.id DESC
);
INSERT INTO Orders
SELECT
orderno,
orderTotal,
(#PreviousTotal + orderTotal) AS runningTotal
FROM INSERTED;
END;
--Insert new record
INSERT INTO orders
VALUES
(1,1000,NULL);
--View newly added record
SELECT
*
FROM orders
WHERE orderno = 1;

You need to following query:
SELECT orderno,
SUM((CASE WHEN ISNUMERIC(ordertotal)=1
THEN CONVERT(MONEY,ordertotal) ELSE 0 END)
)
AS [Converted to Numeric]
FROM price group by orderno

Related

MySQL Event, SELECT inside INSERT

I have a problem with a MySQL event. I am making a gym membership manager with java and using MySQL as database. There are three tables which I need to use for this event as shown below:
------------------------- --------------------- --------------------------
| Daily Statements | | Monthly Statements | | Daily Total Statements |
------------------------- --------------------- --------------------------
| ID (PK) | | ID (PK) | | Ref ID (PK) |
| Value Paid | | Value Paid | | Total Daily Value |
| Date Paid | | Date Paid | | Date |
------------------------- ----------------------- ---------------------------
So the event has to sum up every day bills and make a summary of each day or differently said has to make a daily total. But I need it to summarize both daily memberships and monthly ones into one row with the current timestamp. I have thought about using a query as follows:
INSERT INTO `daily_total_statements`(
`Reference ID`,
`Value`,
`Date`
) VALUES (
Null,
(
SELECT
SUM(`Value Paid`)
FROM `daily_statements`
WHERE `Date Paid` = CURRENT_DATE()),
CURRENT_DATE()
)
It works for one table but I can't figure out how to do it for two tables. I think it has to be done with conditionals but I'm not good at that since I'm a beginner. Should I create two distinct events or a trigger instead?
P.s. I want to use the table for creating a line graph with JFreeGraph. Sorry for bad lang. :)
Use a UNION of the two tables, and then combine their totals with SUM().
INSERT INTO daily_total_statements (`Reference ID`, `Value`, `Date`)
SELECT NULL, SUM(combined.total), CURRENT_DATE()
FROM (
SELECT SUM(`Value Paid`) AS total
FROM daily_statements
WHERE `Date Paid` = CURRENT_DATE()
UNION ALL
SELECT SUM(`Value Paid`) AS total
FROM monthly_statements
WHERE `Date Paid` = CURRENT_DATE()
) AS combined

Mysql how to generate row index (rank) in SELECT?

As result of mysql query, I have this table:
orders | customer |
1 | A |
1 | A |
1 | B |
1 | B |
1 | B |
Using mysql only, I need to create a column with index oder ocurrence to each customer to get this table:
orders | customer | index
1 | A | 1
1 | A | 2
1 | B | 1
1 | B | 2
1 | B | 3
I try to use this:
set #i=1;
while #i<99999 do
select
count(order_id) as 'orders',
customer_id as 'customer',
#i as 'index'
from
orders
set #i= #i+1;
end while;
But I get an error of statement. Sorry, I have no more idea how to do it. Any idea will be appreciated.
The standard way of doing this with MySQL 8.0 is to use a windowing function:
SELECT orders, customer,
ROW_NUMBER() OVER (PARTITION BY customer) AS `index`
FROM orders
Prior to MySQL 8.0, you can do tricks with inline user variables.
SET #i = 0, #c = '';
SELECT
orders,
IF(#c=customer, #i:=#i+1, #i:=1) AS `index`,
#c:=customer AS customer
FROM orders
ORDER BY customer;
Unfortunately, this needs the customer column to be after the index column.
SELECT
orders.* ,
customerOrderCount ,
IF(#i > 1, #i:= #i - 1, #i:=customerOrdercount) AS orderIndex
FROM (SELECT * FROM orders ORDER BY customer ASC ) AS orders
JOIN (SELECT customer, count(*) AS customerOrderCount FROM orders GROUP BY
customer) counts USING (customer)
ORDER BY customer ASC, orderIndex;

table creation logic

I am looking to take two tables I have a perform a data transformation to create a single table. I have an events table and user table:
Events: {id, user_id, start_date, end_date, cost...}
Users: {id, name, ...}
I am trying to create a table at that shows user spend at a daily level, assuming the user start with a starting cost of zero and it goes up after every event.
The intended output would be:
{date, userid, beginning_balance, sum(cost), num_of_events}
i need some direction on how to tackle this one as I am not very familiar with data transformation within SQL
Your requirement is a bit unclear but you may be after something like this
drop table if exists event;
create table event(id int auto_increment primary key, user_id int,start_date date, end_date date, cost int);
insert into event (user_id,start_date , end_date, cost) values
(1,'2017-01-01','2017-01-01',10),(1,'2017-01-01','2017-01-01',10),
(1,'2017-02-01','2017-01-01',10),
(2,'2017-01-01','2017-01-01',10);
select e.user_id,start_date,
ifnull(
(select sum(cost)
from event e1
where e1.user_id = e.user_id and e1.start_date <e.start_date
), 0 )beginning_balance,
sum(cost),count(*)
as num_of_events
from users u
join event e on e.user_id = u.userid
group by e.user_id,start_date
+---------+------------+-------------------+-----------+---------------+
| user_id | start_date | beginning_balance | sum(cost) | num_of_events |
+---------+------------+-------------------+-----------+---------------+
| 1 | 2017-01-01 | 0 | 20 | 2 |
| 1 | 2017-02-01 | 20 | 10 | 1 |
| 2 | 2017-01-01 | 0 | 10 | 1 |
+---------+------------+-------------------+-----------+---------------+
3 rows in set (0.03 sec)
Can you try this query
SELECT
data,
User.id AS userid,
0 AS beginning_balance,
SUM(cost) AS cost,
COUNT(0) AS num_of_events
FROM
Users
LEFT JOIN Events ON (user_id = Users.id)
GROUP BY
Users.id

SQL query with EXISTS not working as I thought

Hi these two SQL Queries return the same result
SELECT DISTINCT ItemID
FROM Sale INNER JOIN Department
ON Department.DepartmentID = Sale.DepartmentID
WHERE DepartmentFloor = 2
ORDER BY ItemID
SELECT DISTINCT ItemID
FROM Sale
WHERE EXISTS
(SELECT *
FROM Department
WHERE Sale.DepartmentID = Department.DepartmentID
AND DepartmentFloor = 2)
ORDER BY ItemID;
The Subquery Inside the Exists returns True So why doesnt the secod query return the equivalent of
SELECT DISTINCT ItemID
FROM Sale
Which guves a different result from the two above.
You are getting confused by EXISTS().. It occurs on a line by line basis, based on table correlation, not just a single true/false. This line of your subquery is your correlation clause:
Sale.DepartmentID = Department.DepartmentID
It is saying "Only show the Sale.ItemIDs where that ItemID's Sale.DepartmentID is in Department."
It achieves the same function as a join predicate, like in your first query:
FROM Sale S
JOIN Department D on S.DepartmentID = D.DepartmentID --here
Conversely, this query:
SELECT DISTINCT ItemID
FROM Sale
Has no limiting factor.
As an aside, you also further limit the results of each query with:
WHERE DepartmentFloor = 2
But I don't think that is the part that is throwing you off, I think it is the concept that a correlated subquery occurs for each record. If you were to remove your correlating clause, then the subquery would actually return true always, and you would get all results back.
The subquery isn't always returning true. It will evaluate for each row, joining on DepartmentID where the DepartmentFloor is 2.
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE Sale ( ItemID int, DepartmentID int ) ;
INSERT INTO Sale ( ItemID, DepartmentID )
VALUES (1,1), (2,2), (3,3), (4,1), (5,4), (6,2), (7,3), (8,4) ;
CREATE TABLE Department ( DepartmentID int, DepartmentFloor int ) ;
INSERT INTO Department ( DepartmentID, DepartmentFloor )
VALUES (1,1), (2,1), (3,2), (4,2) ;
Query 1:
SELECT *
FROM Department
WHERE DepartmentFloor = 2
Results: This lists only the Departments on DepartmentFloor 2.
| DepartmentID | DepartmentFloor |
|--------------|-----------------|
| 3 | 2 |
| 4 | 2 |
Query 2:
SELECT *
FROM Sale
Results: This lists ALL of your Sales.
| ItemID | DepartmentID |
|--------|--------------|
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 1 |
| 5 | 4 |
| 6 | 2 |
| 7 | 3 |
| 8 | 4 |
Query 3:
SELECT *
FROM Sale
WHERE DepartmentID IN (3,4)
Results: And this one shows what is the equivalent of you EXISTS statement. It only shows 4 rows that will match up in my data. So you'd only get back ItemIDs 3,5,7 and 8.
| ItemID | DepartmentID |
|--------|--------------|
| 3 | 3 |
| 5 | 4 |
| 7 | 3 |
| 8 | 4 |
because the uppper part of the query is equivalent to
SELECT DISTINCT ItemID FROM Sale where EXISTS (true)
the upper is the only query that really check the condition ..

Deleting all but the most recent entry from single SQL table

I have a single SQL table that contains multiple entries for each customerID (some customerID's only have one entry which I want to keep). I need to remove all but the most recent entry per customerID, using the invoiceDate field as my marker.
So I need to go from this:
+------------+-------------+-----------+
| customerID | invoiceDate | invoiceID |
+------------+-------------+-----------+
| 1 | 1393995600 | xx |
| 1 | 1373688000 | xx |
| 1 | 1365220800 | xx |
| 2 | 1265220800 | xx |
| 2 | 1173688000 | xx |
| 3 | 1325330800 | xx |
+------------+-------------+-----------+
To this:
+------------+-------------+-----------+
| customerID | invoiceDate | invoiceID |
+------------+-------------+-----------+
| 1 | 1393995600 | xx |
| 2 | 1265220800 | xx |
| 3 | 1325330800 | xx |
+------------+-------------+-----------+
Any guidance would be greatly appreciated!
Write a query to select all the rows you want to delete:
SELECT * FROM t
WHERE invoiceDate NOT IN (
SELECT MAX(invoiceDate)
-- "FROM t AS t2" isn't supported by MySQL, see http://stackoverflow.com/a/14302701/227576
FROM (SELECT * FROM t) AS t2
WHERE t2.customerId = t.customerId
GROUP BY t2.customerId
)
This may take a long time on a big database.
If you're satisfied, change the query to a DELETE statement:
DELETE FROM t
WHERE invoiceDate NOT IN (
SELECT MAX(invoiceDate)
-- "FROM t AS t2" isn't supported by MySQL, see http://stackoverflow.com/a/14302701/227576
FROM (SELECT * FROM t) AS t2
WHERE t2.customerId = t.customerId
GROUP BY t2.customerId
)
See http://sqlfiddle.com/#!9/6e031/1
If you have multiple rows whose date is the most recent for the same customer, you would have to look for duplicates and decide which one you want to keep yourself. For instance, look at customerId 2 on the SQL fiddle link above.
Try out this one
with todelete as
(
select
CustomerId, InvoiceId, InvoiceDate, Row_Number() over (partition by CustomerId order by InvoiceDate desc) as Count
from DeleteDuplicate
)
delete from todelete
where count > 1
Let us asume that the table name is transaction_table.
create table test1 AS
select * from (
select * from transaction_table order by customerID, invoiceDate desc) temp
group by customerID
You will have the output data in test1 table.
delete from ex_4 where
rowid in
(select rowid
from ex_4 a
where to_date(invoicedate,'DDMMYYYY') = (select max(to_date(invoicedate,'DDMMYYYY')) from ex_4 b where a.customerid != b.customerid))
This is how it will be done in oracle.This query will delete all but most recently added row.Looking at your table structure i am assuming that the invoicedate column is varchar2 type so converting it to date used to_date function here