Postgres problem - sql

Say I have the following data in my table;
tran_date withdraw deposit
25/11/2010 0 500
2/12/2010 100 0
15/12/2010 0 300
18/12/2010 0 200
25/12/2010 200 0
Suppose I want to get the following for date range between 1/12/2010 and 31/12/2010.
tran_date withdraw deposit balance days_since_last_tran
1/12/2010 0 0 500 0
2/12/2010 100 0 400 1
15/12/2010 0 300 700 13
18/12/2010 0 200 900 3
25/12/2010 200 0 700 7
31/12/2010 0 0 700 6
Is this doable in PostgreSQL 8.4?

Use:
SELECT t.tran_date,
t.withdraw,
t.deposit,
(SELECT SUM(y.deposit) - SUM(y.withdrawl)
FROM YOUR_TABLE y
WHERE y.tran_date <= t.tran_date) AS balance,
t.tran_date - COALESCE(LAG(t.tran_date) OVER(ORDER BY t.tran_date),
t.tran_date) AS days_since_last
FROM YOUR_TABLE t
8.4+ is nice, providing access to analytic/windowing functions like LAG.

Related

How to delete records of orders that is canceled within 5 minutes in database?

I have a record of users' purchasing behavior. However, it is long and includes a lot of redundant data. I want to delete orders that purchased and deleted within 5 min
My query so far:
--TABLE 3 COD
select z.user_id,
z.date,
z.actions,
x.name,
x.email,
x.address
sum(z.debit) over (partition by z.seller_id order by z.created_at) -
sum(z.credit) over (partition by z.seller_id order by z.created_at)
as balance
from table_1 z
left join
table_2 x
on z.seller_id = x.uid
order by seller_id, created_at
For simplicity, i got this result
user actions credit debit balance date
1 do_action_A 5000 0 5000 2020-01-01 1:00:00 #no need these 2
1 cancel_A 0 5000 0 2020-01-01 1:03:00 #in result
1 do_action_A 5000 0 5000 2020-01-01 1:10:00
1 do_action_b 3000 0 8000 2020-01-01 1:20:00
1 do_action_c 0 7000 1000 2020-01-01 1:30:00
2 do_action_A 5000 0 5000 2020-01-01 1:00:00
2 do_action_B 3000 0 8000 2020-01-01 1:10:00
We know that users can only cancel their orders within 5 minutes, unfortunately, there is a lot of cancels. I need to make this data table simple and short so as to track and visualize it easily.
Here is my expectataion:
user actions credit debit balance date
1 do_action_A 5000 0 5000 2020-01-01 1:10:00
1 do_action_b 3000 0 8000 2020-01-01 1:20:00
1 do_action_c 0 7000 1000 2020-01-01 1:30:00
2 do_action_A 5000 0 5000 2020-01-01 1:00:00
2 do_action_B 3000 0 8000 2020-01-01 1:10:00
You can try using lead()
select * from
(
select z.user_id,z.date,z.actions,x.name,
x.email,x.address,debtit, credit, balance,
lead(z.actions) over(parition by z.user_id order by z.created_at) as next_action
from table_1 z left join table_2 x
on z.seller_id = x.uid
)A where next_action not like '%cancel%' and actions not like '%cancel%'

Merging Two Tables and Calculating Amount (Currency Conversion)

I have table which contains the currency exchange rates and another one with converted amounts.
Currency Table
This table will have the daily rates of the currency. For the ease of mapping I have only included rates for one date.
Branch Code Rate Date
A 0 1 30/10/2019
A 1 200 30/10/2019
A 2 300 30/10/2019
B 0 1 30/10/2019
B 1 10 30/10/2019
B 2 30 30/10/2019
Converted Amounts Table
This table will have the daily exchange details. For the ease of mapping I have only included transactions for one date.
Branch Code Amt Date
A 0 1000 30/10/2019
A 1 2000 30/10/2019
A 2 3000 30/10/2019
A 2 4000 30/10/2019
A 2 5000 30/10/2019
A 0 6000 30/10/2019
B 0 7000 30/10/2019
B 0 8000 30/10/2019
B 0 9000 30/10/2019
B 2 10000 30/10/2019
Resultant Table
Branch Code Date Amt Branch Code Rate Total
A 0 30/10/2019 1000 A 0 1 1000
A 1 30/10/2019 2000 A 1 200 400000
A 2 30/10/2019 3000 A 2 300 900000
A 2 30/10/2019 4000 A 2 300 1200000
A 2 30/10/2019 5000 A 2 300 1500000
A 0 30/10/2019 6000 A 1 1 6000
B 0 30/10/2019 7000 A 1 200 1400000
B 0 30/10/2019 8000 A 1 200 1600000
B 0 30/10/2019 9000 A 1 200 1800000
B 2 30/10/2019 10000 A 2 300 3000000
I could only get the following resultant table.
Branch Code Date Amt Branch Code Rate Total
A 0 30/10/2019 1000 A 0 1 1000
A 1 30/10/2019 2000 A 1 200 400000
A 2 30/10/2019 3000 A 2 300 900000
A 2 30/10/2019 4000 A 2 300 1200000
A 2 30/10/2019 5000 A 2 300 1500000
A 0 30/10/2019 6000 A 1 1 6000
B 0 30/10/2019 7000 A 1 1 7000
B 0 30/10/2019 8000 A 1 1 8000
B 0 30/10/2019 9000 A 1 1 9000
B 2 30/10/2019 10000 A 2 300 3000000
Query I use.
SELECT
*
FROM
converted_amounts_table t1
LEFT OUTER JOIN (
SELECT
(
CASE WHEN code = '0'
AND branch = 'B' THEN '1' ELSE code END
) AS new_code,
branch,
date,
rate
FROM
currency_table
) t2 ON (
t1.date = t2.date
AND t1.code = t2.new_code
)
WHERE
t1.date >= '01-Jan-2019'
AND t1.date <= '30-Sep-2019'
I was able to get the resultant table.
https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=4d5401320bda5ad736070541d55d1d04
SELECT
t1.branch,
t1.date2,
t1.code,
t2.code,
t2.new_code,
t2.rate,
t1.amt,
t1.amt * t2.rate AS Total
FROM
converted_amounts_table t1
LEFT OUTER JOIN (
SELECT
(CASE WHEN code = 1 THEN 0 ELSE code END) AS new_code,
branch,
date1,
code,
rate
FROM
currency_table
WHERE
branch = 'A'
) t2 ON (
t1.date2 = t2.date1
AND t1.code IN (t2.new_code, t2.code)
)
WHERE
t1.date2 = '30 - Oct - 2019'
AND (
t1.branch, t1.code, t2.code, t2.new_code,
t2.rate
) NOT IN (
('B', 0, 0, 0, 1),
('A', 0, 1, 0, 200)
)

Properly 'Joining' two Cross Applies

I've got a query with three Cross-Applies that gather data from three different tables. The first Cr-Ap assists the 2nd and 3rd Cr-Ap's. It finds the most recent ID of a certain refill for a 'cartridge', the higher the ID the more recent the refill.
The second and third Cr-Ap's gather the SUMS of items that have been refilled and items that have been dispensed under the most recent Refill.
If I run the query for Cr-Ap 2 or 3 separately the output would look something like:
ID Amount
1 100
2 1000
3 100
4 0
5 0
etc
Amount would be either the amount of dispensed or refilled items.
Only I don't want to run these queries separately, I want them next to each other.
So what I want is a table that looks like this:
ID Refill Dispense
1 100 1
2 1000 5
3 100 7
4 0 99
5 0 3
etc
My gut tells me to do
INNER JOIN crossaply2 ON crossapply3.ID = crossapply2.ID
But this doesn't work. I'm still new to SQL so I don't exactly know what I can and can't join, what I do know is that you can use crossapply as a join (sorta?). I think that might be what I need to do here, I just don't know how.
But that's not it, there's another complication, there are certain refills where nothing gets dispensed. In these scenarios the crossapply I wrote for dispenses won't return anything for that refillID. With nothing I don't mean NULL, I mean it just skips the refillID. But I'd like to see a 0 in those cases. Because it just skips over those ID's I can't get COALESCE or ISNULL to work, this might also complicate the joining of these two applies. Because an INNER JOIN would skip any line where there is no Dispensed amount, even though there is a Refilled amount Id like to see.
Here is my code:
-- Dispensed SUM and Refilled SUM combined
SELECT [CartridgeRefill].[FK_CartridgeRegistration_Id]
,Refills.Refilled
,Dispenses.Dispensed
FROM [CartridgeRefill]
CROSS APPLY(
SELECT MAX([CartridgeRefill].[Id]) AS RecentRefillID
FROM [CartridgeRefill]
GROUP BY [CartridgeRefill].[FK_CartridgeRegistration_Id]
) AS RecentRefill
CROSS APPLY(
SELECT [CartridgeRefill].[FK_CartridgeRegistration_Id] AS RefilledID
,SUM([CartridgeRefillMedication].[Amount]) AS Refilled
FROM [CartridgeRefillMedication]
INNER JOIN [CartridgeRefill] ON [CartridgeRefillMedication].[FK_CartridgeRefill_Id] = [CartridgeRefill].[Id]
WHERE [CartridgeRefillMedication].[FK_CartridgeRefill_Id] = RecentRefill.RecentRefillID
GROUP BY [CartridgeRefill].[FK_CartridgeRegistration_Id]
) AS Refills
CROSS APPLY(
SELECT [CartridgeRefill].[FK_CartridgeRegistration_Id] AS DispensedID
,SUM([CartridgeDispenseAttempt].[Amount]) AS Dispensed
FROM [CartridgeDispenseAttempt]
INNER JOIN [CartridgeRefill] ON [CartridgeDispenseAttempt].[FK_CartridgeRefill_Id] = [CartridgeRefill].[Id]
WHERE [CartridgeDispenseAttempt].[FK_CartridgeRefill_Id] = RecentRefill.RecentRefillID
GROUP BY [CartridgeRefill].[FK_CartridgeRegistration_Id]
) AS Dispenses
GO
The output of this code is as follows:
1 300 1
1 300 1
1 200 194
1 200 194
1 200 8
1 200 8
1 0 39
1 0 39
1 100 14
1 100 14
1 200 1
1 200 1
1 0 28
1 0 28
1 1000 102
1 1000 102
1 1000 557
1 1000 557
1 2000 92
1 2000 92
1 100 75
1 100 75
1 100 100
1 100 100
1 100 51
1 100 51
1 600 28
1 600 28
1 200 47
1 200 47
1 200 152
1 200 152
1 234 26
1 234 26
1 0 227
1 0 227
1 10 6
1 10 6
1 300 86
1 300 86
1 0 194
1 0 194
1 500 18
1 500 18
1 1000 51
1 1000 51
1 1000 56
1 1000 56
1 500 48
1 500 48
1 0 10
1 0 10
1 1500 111
1 1500 111
1 56 79
1 56 79
1 100 6
1 100 6
1 44 134
1 44 134
1 1000 488
1 1000 488
1 100 32
1 100 32
1 100 178
1 100 178
1 500 672
1 500 672
1 200 26
1 200 26
1 500 373
1 500 373
1 100 10
1 100 10
1 900 28
1 900 28
2 900 28
2 900 28
2 900 28
etc
It is total nonsense that I can't do much with, it goes on for about 20k lines and goes through all the ID's, eventually.
Any help is more than appreciated :)
Looks like overcomplicated a bit.
Try
WITH cr AS (
SELECT [FK_CartridgeRegistration_Id]
,MAX([CartridgeRefill].[Id]) RecentRefillID
FROM [CartridgeRefill]
GROUP BY [FK_CartridgeRegistration_Id]
)
SELECT cr.[FK_CartridgeRegistration_Id], Refills.Refilled, Dispenses.Dispensed
FROM cr
CROSS APPLY(
SELECT SUM(crm.[Amount]) AS Refilled
FROM [CartridgeRefillMedication] crm
WHERE crm.[FK_CartridgeRefill_Id] = cr.RecentRefillID
) AS Refills
CROSS APPLY(
SELECT SUM(cda.[Amount]) AS Dispensed
FROM [CartridgeDispenseAttempt] cda
WHERE cda.[FK_CartridgeRefill_Id] = cr.RecentRefillID
) AS Dispenses;

SSRS REPORT SQL

I have data as below
Year Period Country STATUS COST1 COST2 TOTAL COST
2019 1 Australia PERM 100 200 300
2019 2 NZ PERM 200 200 400
2019 3 ASIA TEMP 400 200 600
2019 4 NZ TEMP 500 200 700
I like to show in the SSRS report
I need period on COLUMN and STATUS in ROWS like below and total cost in data section
Period
1 2 3 4
+PERM TOTAL COST
+TEMP
And when end user toggle on + it will show more detail. But otherwise just like that.
Year Country COST1 COST2 TOTAL COST
PERM 2019 1 Australia 100 200 300
2019 2 NZ 200 200 400
TEMP 2019 3 ASIA 400 200 600
2019 4 NZ 500 200 700
thanks in advance
You seem to want conditional aggregation:
select status,
sum(case when period = 1 then total_cost else 0 end) as total_cost_1,
sum(case when period = 2 then total_cost else 0 end) as total_cost_2,
sum(case when period = 3 then total_cost else 0 end) as total_cost_3,
sum(case when period = 4 then total_cost else 0 end) as total_cost_4
from t
group by status;
With a Matrix in SSRS you can set the row groups to be based on the Period and Status without having to add an additional dataset.
Use Period for the Column Grouping so the field will expand to 4 columns based on the Period values.
Result:
This way you can have the detail below in the same table and hide it until the user toggles it.

Oracle SQL Query one row with monthly value only, but need to group it by month

I can't figure out the correct query on Oracle SQL
I have the following data:
Name Monthly_amount Start_date
Bob 100 April 2014
Mike 120 June 2014
Steve 80 Sept 2014
Bob 50 Dec 2014
And I would like to get the following result
Name |Jan-14| Feb-14| Mar-14| Apr-14 |May-14| Jun-14| Jul-14 |Aug-14|Sep-14|Oct-14| Nov-14| Dec-14
Bob 0 0 0 100 100 100 100 100 100 100 100 150
Mike 0 0 0 0 0 120 120 120 120 120 120 120
Steve 0 0 0 0 0 0 0 0 80 80 80 80
Something along the lines of this should work for you. If you need the column definitions to be dynamic, you would have to create it dynamically, but it's better to do that kind of things in your application.
SELECT Name,
SUM(CASE WHEN Start_date <= TO_DATE('01-JAN-2014','DD-MON-YYYY')
THEN Monthly_Amount ELSE 0 END) AS Jan14,
SUM(CASE WHEN Start_date <= TO_DATE('01-FEB-2014','DD-MON-YYYY')
THEN Monthly_Amount ELSE 0 END) AS Feb14,
(etc.)
FROM table1
GROUP BY Name;
(This assumes Name uniquely defines a person)