Sum of rows below in qlikview - qlikview

I have a table like this :
Date
Amount
06/Jan/2021
300
05/Jan/2021
200
04/Jan/2021
-100
03/Jan/2021
-500
02/Jan/2021
200
01/Jan/2021
100
I want to get a column with the running totals but keeping the min amount to 0. The total resets to 0 once its below 0.
the expected outcome is as below
Date
Amount
Total
06/Jan/2021
300
500
05/Jan/2021
200
200
04/Jan/2021
-100
0
03/Jan/2021
-500
0
02/Jan/2021
200
200
01/Jan/2021
100
100

First we need to sort our data.
Second we need to select previous total and add current amount + add condition.
Third we need sort our table way as we like (newest on top).
Most important function used is Peek.
// example data (I simplified data)
[data]:
LOAD
*
INLINE [
Date, Amount
6, 300
5, 200
4, -100
3, -500
2, 200
1, 100
];
// order as we need use data from previous row correctly
[data_ordered]:
NoConcatenate LOAD
*
Resident
[data]
Order by
Date asc;
DROP Table [data];
// condition, peek function and alt needed for first row where is no data yet
[data_totals]:
LOAD
Date,
Amount,
If((Amount + Alt(Peek('Total', -1), 0)) > 0,
Amount + Alt(Peek('Total', -1), 0),
0) as Total
Resident
[data_ordered];
DROP Table [data_ordered];
final table:

Related

A question again on cursors in SQL Server

I am reading data using modbus The data contains status of the 250 registers in a PLC as either off or on with the time of reading as the time stamp. The raw data received is stored in table as below where the column register represents the register read and the column value represents the status of the register as 0 or 1 with time stamp. In the sample I am showing data for just one register (ie 250). Slave ID represents the PLC from which data was obtained
I need to populate one more table Table_signal_on_log from the raw data table. This table should contain the time at which the value changed to 1 as the start time and the time at which it changes back to 0 as end time. This table is also given below
I am able to do it with a cursor but it is slow and if the number of signals increases could slow down the processing. How could I do without cursor. I tried to do it with set based operations I couldn't get one working. I need to avoid repeat values ie after recording 13:30:30 as the time at which signal becomes 1, I have to ignore all entries till it becomes 0 and record that as end time. Again ignore all values till becomes 1. This process is done once in 20 seconds (can be done at any interval but presently 20). So I may have 500 rows to be looped through every time. This may increase as the number of PLCs connected increases and cursor operation is bound to be an issue
Raw data table
SlaveID Register Value Timestamp ProcessTime
-------------------------------------------------------
3 250 0 13:30:10 NULL
3 250 0 13:30:20 NULL
3 250 1 13:30:30 NULL
3 250 1 13:30:40 NULL
3 250 1 13:30:50 NULL
3 250 1 13:31:00 NULL
3 250 0 13:31:10 NULL
3 250 0 13:31:20 NULL
3 250 0 13:32:30 NULL
3 250 0 13:32:40 NULL
3 250 1 13:32:50 NULL
Table_signal_on_log
SlaveID Register StartTime Endtime
3 250 13:30:30 13:31:10
3 250 13:32:50 NULL //value is still 1
This is a classic gaps-and-islands problem, there are a number of solutions. Here is one:
Get the previous Value for each row using LAG
Filter so we only have rows where the previous Value is different or non-existent, in other words the beginning of an "island" of rows.
Of those rows, get the next Timestamp for eacc row using LEAD.
Filter so we only have Value = 1.
WITH cte1 AS (
SELECT *,
PrevValue = LAG(t.Value) OVER (PARTITION BY t.SlaveID, t.Register ORDER BY t.Timestamp)
FROM YourTable t
),
cte2 AS (
SELECT *,
NextTime = LEAD(t.Timestamp) OVER (PARTITION BY t.SlaveID, t.Register ORDER BY t.Timestamp)
FROM cte1 t
WHERE (t.Value <> t.PrevValue OR t.PrevValue IS NULL)
)
SELECT
t.SlaveID,
t.Register,
StartTime = t.Timestamp,
Endtime = t.NextTime
FROM cte2 t
WHERE t.Value = 1;
db<>fiddle

How to multiply two measures prior to aggregation

I have two measures. The first is amount, and the second consist of values -1,0 and 1, so table looks like this:
Amount Sign
--------------
400 -1
200 1
300 0
Result I want to get is 400*(-1) + 200*1 + 300*0 = -200, but I am getting (400+200+300)*(-1+1+0) = 0
This is my calculated member:
WITH
MEMBER [Measures].[Result]
AS
[Measures].[Sign]*[Measures].[Amount]
select
[Measures].[Result] on 0,
[Time].[Time].members on 1
from [MyCube]
In you SSAS project, go to the datasource view, for the underlying fact table add a NamedCalculation. In that do the multiplication that you explained. Now in the Cube add that as a measure. It will behave exactly like you want it to behave.

Sliding window functions in SQL Server, advanced calculation

I have a problem that it's very easy to be solved in C# code for example, but I have no idea how to write in a SQL query.
Here is the situation: let's say I have a table with 3 columns (ID, Date, Amount), and here is some data:
ID Date Amount
-----------------------
1 01.01.2016 -500
2 01.02.2016 1000
3 01.03.2016 -200
4 01.04.2016 300
5 01.05.2016 500
6 01.06.2016 1000
7 01.07.2016 -100
8 01.08.2016 200
The result I want to get from the table is this (ID, Amount .... Order By Date):
ID Amount
-----------------------
2 300
4 300
5 500
6 900
8 200
The idea is to distribute the amounts into installments, but the thing is when negative amount comes into play you need to remove amount from the last installment. I don't know how clear I am, so here is an example:
Let's say I have 3 Invoices with amounts 500, 200, -300.
If i start distribute these Invoices, first i distribute the amount 500, then 200. But when i come to the third one -300, then i need to remove from the last Invoice. In other workds 200 - 300 = -100, so the amount from second Invoice will disappear, but there are still -100 that needs to be substracted from first Invoice. So 500 - 100 = 400. The result i need is dataset with one row (first invoice with amount 400)
Another example when the first invoice is with negative amount (-500, 300, 500).
In this case, the first (-500) invoice will make the second disappear and another 200 will be substracted from the third. So the result will be: Third Invoice with amount 300.
This is something like Stack implementation in programming language, but i need to make it with sliding-window functions in SQL Server.
If anyone have any idea, please share.
Thanks.
I solved it using TSQL. But I think what this task also can solve using recursive CTE.
I used ID for finding a prev or next row.
-- create and fill test table
CREATE TABLE Invoices(
ID int,
[Date] date,
Amount float
)
INSERT Invoices(ID,Date,Amount) VALUES
(1,'20160101', -500),
(2,'20160201', 1000),
(3,'20160301', -200),
(4,'20160401', 300),
(5,'20160501', 500),
(6,'20160601', 1000),
(7,'20160701', -100),
(8,'20160801', 200)
My solution
-- copy all the data into temp table
SELECT *
INTO #Invoices
FROM Invoices
DECLARE
#nID int,
#nAmount float,
#pID int
-- run infinity loop
WHILE 1=1
BEGIN
-- set all the variables to NULL
SET #nID=NULL
SET #nAmount=NULL
SET #pID=NULL
-- get data from the last negative row
SELECT
#nID=ID,
#nAmount=Amount
FROM
(
SELECT TOP 1 *
FROM #Invoices
WHERE Amount<0
ORDER BY ID DESC
) q
-- get prev positive row
SELECT #pID=ID
FROM
(
SELECT TOP 1 *
FROM #Invoices
WHERE ID<#nID
AND Amount>0
ORDER BY ID DESC
) q
IF(#pID IS NULL)
BEGIN
-- get next positive row
SELECT #pID=ID
FROM
(
SELECT TOP 1 *
FROM #Invoices
WHERE ID>#nID
AND Amount>0
ORDER BY ID
) q
END
-- exit from loop
IF(#pID IS NULL) BREAK
-- substract amount from positive row
UPDATE #Invoices
SET
Amount+=#nAmount
WHERE ID=#pID
-- delete used negative row
DELETE #Invoices
WHERE ID=#nID
END
-- show result
SELECT *
FROM #Invoices
DROP TABLE #Invoices

SQL : how to distinguish between different rows with same value in some field and have a separate function applied to another field

I have a query output showing a list of orders. Some orders might occupy more then one record in the query output if those orders consist of sub-orders.Each sub-order occupies a separate line in the output. There is the OrderID column which has the same value for all sub-orders in the output:
OrderID Sub-Order Price
1 1 100
1 2 50
2 1 30
3 1 50
I need to add a column "Discount" to the output and fill it by following rules:
If certain order has one sub-order - the discount is 10% of the Price
If certain order has more than one sub-order, the discount is 20% on all sub-orders'
My query is a UNION of two SELECTs.
I use mssql with ms sql studio
Use CASE and COUNT window function
SELECT OrderID, Sub-Order, Price,
CASE WHEN (count(*) OVER (PARTITION BY OrderID)) > 1
THEN Price * 0.8
ELSE Price * 0.9
END
FROM ( table or <query> )

Visual Foxpro Query for pending quantity

I am having two tables AORDER for Purchase & BORDER for sale. I want to get pending quantity. Sale orders can have more than 1 records against one purchase order. I do not want to show those order having pending quantities 0. I tried this:
SELECT ;
aorder.orderid,;
aorder.orderdate,;
aorder.itemname,;
aorder.partyname,;
aorder.qty as Purchase,;
SUM(border.qty) AS Sale,;
SUM(aorder.qty-border.qty) as Pending;
FROM ;
aorder;
LEFT JOIN border ;
ON aorder.orderid = border.porderid;
GROUP BY ;
aorder.orderid,;
aorder.orderdate,;
aorder.itemname,;
aorder.partyname,;
aorder.qty
But I am failed to hide those records having purchase qty = sale qty.
Thnx in advance.
As Shahkalpesh mentioned, you do need to apply the having, but your SUM in incorrect.
It should be
aorder.qty - SUM(border.qty) > 0; && also for your field reference.
The reason, SUM is summing each part WITHIN the sum. You will have only one "Purchase" record, but many "Sale" records, as if inventory control First in / First Out (FIFO), Last In / First Out (LIFO), etc
So, say you have PURCHASE order #1 with a quantity of 10, and have sold separate times for quantities 2, 1, 1, 3, 2, 1... Total of 6 sale records. What you are doing is
sum( 10 - 2
+ 10 - 1
+ 10 - 1
+ 10 - 3
+ 10 - 2
+ 10 - 1 )
The revised way is...
10 - SUM( 2 + 1 + 1 + 3 + 2 + 1 )