Merging Two Tables and Calculating Amount (Currency Conversion) - sql

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)
)

Related

SQL - YTD and MTD in rows instead of columns

Let's say I have this table:
FiscalPeriod
FiscalMonth
FiscalYear
Division
L4
L5
L6
L7
AMT_LEGAL_USD
01-2022
1
2022
A
NOP
OP
GM
NS
1000
02-2022
2
2022
A
NOP
OP
GM
NS
2000
03-2022
3
2022
A
NOP
OP
GM
NS
2000
01-2022
1
2022
B
NOP
OP
GM
NS
1000
02-2022
2
2022
B
NOP
OP
GM
NS
3000
03-2022
3
2022
B
NOP
OP
GM
NS
5000
01-2022
1
2022
C
NOP
OP
GM
NS
1000
02-2022
2
2022
C
NOP
OP
GM
NS
1000
03-2022
3
2022
C
NOP
OP
GM
NS
1000
I'm trying to build a table that queries this one and calculates MTD (month to date) and YTD (Year to Date): for each Division, caculate the MTD and YTD based on FiscalMonth and FiscalYear columns, for each of my KPIs (columns L4 to L7)
I have the following query:
SELECT
ec.FiscalPeriod,
ec.FiscalMonth,
ec.FiscalYear,
ec.Divison,
sum(CASE WHEN L7 = 'NS' then EC.AMT_LEGAL_USD else 0 end) as NS_MTD,
sum(NS_MTD) OVER (PARTITION BY ec.FiscalYear, ec.Divison ORDER BY ec.FiscalPeriod) AS NS_YTD,
sum(CASE WHEN L6 = 'GM' then EC.AMT_LEGAL_USD else 0 end) as GM_MTD,
sum(GM_MTD) OVER (PARTITION BY ec.FiscalYear, ec.Divison ORDER BY ec.FiscalPeriod) AS GM_YTD,
sum(CASE WHEN L5 = 'OP' then EC.AMT_LEGAL_USD else 0 end) as OP_MTD,
sum(OP_MTD) OVER (PARTITION BY ec.FiscalYear, ec.Divison ORDER BY ec.FiscalPeriod) AS OP_YTD,
sum(CASE WHEN L4 = 'NOP' then EC.AMT_LEGAL_USD else 0 end) as NOP_MTD,
sum(NOP_MTD) OVER (PARTITION BY ec.FiscalYear, ec.Divison ORDER BY ec.FiscalPeriod) AS NOP_YTD,
from my table ec
group by 1,2,3,4
having Net_Sales_MTD != 0 and GM_MTD != 0 and OP_MTD != 0 and NOP_MTD != 0
order by 1 asc;
That will return me something like:
FiscalPeriod
FiscalMonth
FiscalYear
Division
NS_MTD
NS_YTD
GM_MTD
GM_YTD
OP_MTD
OP_YTD
NOP_MTD
NOP_YTD
01-2022
1
2022
A
1000
1000
1000
1000
1000
1000
1000
1000
02-2022
2
2022
A
2000
3000
2000
3000
2000
3000
2000
3000
03-2022
3
2022
A
2000
5000
2000
5000
2000
5000
2000
5000
01-2022
1
2022
B
1000
1000
1000
1000
1000
1000
1000
1000
02-2022
2
2022
B
3000
4000
3000
4000
3000
4000
3000
4000
03-2022
3
2022
B
5000
9000
5000
9000
5000
9000
5000
9000
01-2022
1
2022
C
1000
1000
1000
2000
1000
3000
1000
1000
02-2022
2
2022
C
1000
2000
1000
2000
1000
2000
1000
2000
03-2022
3
2022
C
1000
3000
1000
3000
1000
3000
1000
3000
I would like to get an output that would look like:
FiscalPeriod
FiscalMonth
FiscalYear
Division
Period
NOP
OP
GM
NS
01-2022
1
2022
A
MTD
1000
1000
1000
1000
01-2022
1
2022
A
YTD
1000
1000
1000
1000
02-2022
2
2022
A
MTD
2000
2000
2000
2000
02-2022
2
2022
A
YTD
3000
3000
3000
3000
03-2022
3
2022
A
MTD
2000
2000
2000
2000
03-2022
3
2022
A
YTD
5000
5000
5000
5000
01-2022
1
2022
B
MTD
1000
1000
1000
1000
01-2022
1
2022
B
YTD
1000
1000
1000
1000
02-2022
2
2022
B
MTD
3000
3000
3000
3000
02-2022
2
2022
B
YTD
4000
4000
4000
4000
03-2022
3
2022
B
MTD
5000
5000
5000
5000
03-2022
3
2022
B
YTD
9000
9000
9000
9000
01-2022
1
2022
C
MTD
1000
1000
1000
1000
01-2022
1
2022
C
YTD
1000
1000
1000
1000
02-2022
2
2022
C
MTD
1000
1000
1000
1000
02-2022
2
2022
C
YTD
2000
2000
2000
2000
03-2022
3
2022
C
MTD
1000
1000
1000
1000
03-2022
3
2022
C
YTD
3000
3000
3000
3000
Any ideas on how this can be achivied? Hopefully that wasn't too confusing.
Appreciate any feedback and ideas on how to do this.
I think you'll need to do this in two steps:
Calculate MTD
Calculate YTD
Union All
Here is an example based on your data.
with mtd as (
SELECT
ec.FiscalPeriod,
ec.FiscalMonth,
ec.FiscalYear,
ec.Division,
'MTD' as Period,
sum(CASE WHEN L7 = 'NS' then EC.AMT_LEGAL_USD else 0 end) as NS_MTD,
sum(CASE WHEN L6 = 'GM' then EC.AMT_LEGAL_USD else 0 end) as GM_MTD,
sum(CASE WHEN L5 = 'OP' then EC.AMT_LEGAL_USD else 0 end) as OP_MTD,
sum(CASE WHEN L4 = 'NOP' then EC.AMT_LEGAL_USD else 0 end) as NOP_MTD
from data ec
group by 1,2,3,4
)
, ytd as (
SELECT
ec.FiscalPeriod,
ec.FiscalMonth,
ec.FiscalYear,
ec.Division,
'YTD' as Period,
sum(NS_MTD) OVER (PARTITION BY ec.FiscalYear, ec.Division ORDER BY ec.FiscalPeriod) AS NS_YTD,
sum(GM_MTD) OVER (PARTITION BY ec.FiscalYear, ec.Division ORDER BY ec.FiscalPeriod) AS GM_YTD,
sum(OP_MTD) OVER (PARTITION BY ec.FiscalYear, ec.Division ORDER BY ec.FiscalPeriod) AS OP_YTD,
sum(NOP_MTD) OVER (PARTITION BY ec.FiscalYear, ec.Division ORDER BY ec.FiscalPeriod) AS NOP_YTD
from mtd ec
group by 1,2,3,4, NS_MTD, gm_mtd, op_mtd, op_mtd, nop_mtd
)
select * from (
select * from mtd
union all
select * from ytd
) foo
order by fiscalyear, division, fiscalperiod, fiscalmonth, period

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%'

SQL oracle - Delete Duplicate Records and update records in other table

Requirement - Delete Duplicate records e.g. from 2 tables and update the records in the other tables.
Input
Table1 Dim_Ctry
PK_Key1 Country
100 Argentina
200 ARGENTINA
300 India
400 INDIA
Table2 Dim_Geo
PK_Key2 Geo
500 Globe
600 GLOBE
700 Market
800 MARKET
900 Unique
Table Fact1
PK_Key15 FK_KEY1 FK_KEY2
1 100 500
2 200 600
3 300 800
4 400 900
Table Fact2
PK_Key16 FK_KEY1 FK_KEY2
5 100 500
6 200 600
7 200 700
8 300 800
output
Table1 Dim_Ctry
PK_Key1 Country
100 Argentina
300 India
Table2 Dim_Geo
PK_Key2 Geo
500 Globe
700 Market
900 Unique
Table Fact1
PK_Key15 FK_KEY1 FK_KEY2
1 100 500
2 100 500
3 300 800
4 300 800
Table Fact2
PK_Key16 FK_KEY1 FK_KEY2 comment
5 100 500
6 100 500
7 100 700
7 300 800
8 1000 2000 no record in dim table just retain
You will need several steps.
Step 1 update related tables
Update all FK_KEY to the min value.
UPDATE Fact1 f1
SET
FK_KEY1 = (SELECT MIN(PK_Key1)
FROM Dim_Ctry dc1
WHERE UPPER(dc1.Country) = (SELECT UPPER(dc2.Country)
FROM Dim_Ctry dc2
WHERE dc2.PK_Key1 = f1.FK_KEY1)
),
FK_KEY2 = (SELECT MIN(PK_Key2)
FROM Dim_Geo dg1
WHERE UPPER(dg1.Geo) = (SELECT UPPER(dg2.Geo)
FROM Dim_Geo dg2
WHERE dg2.PK_Key2 = f1.FK_KEY2)
);
Step 2 delete duplicated
This will delete all duplicated and keep the one with smaller id
DELETE FROM Dim_Ctry dc1
WHERE EXISTS (SELECT PK_Key1
FROM Dim_Ctry dc2
WHERE dc1.PK_Key1 > dc2.PK_Key1
and UPPER(dc1.Country) = UPPER(dc2.Country)
Step 3 update the text
You should update to lower or upper to standard format.
UPDATE Dim_Ctry
SET Country = UPPER(Country)
debug query
SELECT f1.PK_Key15, f1.FK_KEY1, f1.FK_KEY2,
(SELECT UPPER(dc2.Country)
FROM Dim_Ctry dc2
WHERE dc2.PK_Key1 = f1.FK_KEY1
) as CurrentName,
(SELECT MIN(PK_Key1)
FROM Dim_Ctry dc1
WHERE UPPER(dc1.Country) = (SELECT UPPER(dc2.Country) FROM Dim_Ctry dc2 WHERE dc2.PK_Key1 = f1.FK_KEY1) ) as minKey
FROM Fact1 f1

adding two columns in two tables having multiple layers

I am having two tables here from which I needed to add two columns.
table 1 table 2
1 ram 100 null 1 ram 100 1000
2 ram 200 1000 2 ram 200 null
3 ram 100 2000 3 ram 100 3000
4 ram 100 3000 4 ram 100 4000
5 ram 100 null 5 ram 100 5000
1 rahim 100 5000 1 rahim 100 null
2 ram 200 6000 2 ram 200 7000
3 ram 200 null 3 ram 200 8000
4 ram 200 null 4 ram 200 9000
5 rahim 100 9000 5 rahim 100 null
1 robert 100 10000 1 robert 100 11000
2 rahim 200 11000 2 rahim 200 12000
3 ram 300 12000 3 ram 300 null
4 rahim 400 13000 4 rahim 400 14000
5 robert 100 14000 5 robert 100 15000
result should be in the form:
1 ram 100 1000
2 ram 200 -1000
3 ram 100 1000
4 ram 100 1000
5 ram 100 5000
1 rahim 100 -5000
2 ram 200 1000
3 ram 200 8000
4 ram 200 9000
5 rahim 100 -9000
1 robert 100 1000
2 rahim 200 1000
3 ram 300 -12000
4 rahim 400 1000
5 robert 100 1000
You can use join with coalesce to remove the null values:
select t1.id, t1.somefield, t1.someint,
coalesce(t2.someint2,0)-coalesce(t1.someint2,0)
from table1 t1
join table2 t2 on t1.id = t2.id
and t1.somefield = t2.somefield
and t1.someint = t2.someint
SQL Fiddle Demo
Based on your input data, this joins on the first 3 columns. Not completely sure this is what you want, but should get you going in the correct direction.
I think try subtract table2.col4 with table1.col4.
SELECT a.col1,
a.col2,
a.col3,
NVL(a.col4, 0) - NVL(b.col4, 0) SUB
FROM table1 A
JOIN table2 B
ON A.col1 = b.col1
AND a.col2 = b.col2

Postgres problem

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.