Long story short, I was handed this query (edited a bit for the forum world) to get it working in order to start creating reports. Having some issues with the 3 CASE statements (tried to add comment within the code to explain a little better what is happening). All data is being pulled from the same table/view.
I know I need to create some nested SELECT statements in order to make it work, but I'm struggling. What I'm trying to have happen is...
CASE 2 to only run if CASE 1 IS NOT NULL, where the column would be a result of (amd_month + 1 month). Format being YYYYMM
CASE 3 to only run if CASE 2 IS NOT NULL, where the column would be a result of (ext_srg_start_date + 6 months). Format being YYYYMM
SELECT
part,
amd_month,
amd actual_demand,
round(roll_12amd * 1.15) srg_lmt,
round(roll_12amd * 1.5) ext_srg_lmt,
-- CASE: 1
-- calculate level- COMPLETE
CASE
WHEN (amd > roll_12amd * 1.5) THEN 'Extreme Surge'
WHEN (amd > roll_12amd * 1.15) THEN 'Surge'
ELSE NULL
END AS srg_nt,
-- CASE: 2
-- if amd_month = 12, (+1 year to) and (-11 from month) from ext_srg_start_date,
-- else +1 month to ext_srg_start_date - COMPLETE
CASE
WHEN substr(amd_month, 5, 2) IN (
'12'
) THEN concat(TO_CHAR(substr(amd_month, 1, 4) + 1), lpad(TO_CHAR(substr(amd_month, 5, 2) - 11), 2, '0'))
ELSE concat(substr(amd_month, 1, 4), lpad(TO_CHAR(substr(amd_month, 5, 2) + 1), 2, '0'))
END AS ext_srg_start_date,
---- CASE: 3
---- +6 to ext_srg_start_date - IN PROGRESS
CASE
WHEN substr(amd_month, 5, 2) IN (
'01',
'02',
'03',
'04',
'05',
'06'
) THEN concat(substr(amd_month, 1, 4), lpad(TO_CHAR(substr(amd_month, 5, 2) + 6), 2, '0'))
ELSE concat(TO_CHAR(substr(amd_month, 1, 4) + 1), lpad(TO_CHAR(substr(amd_month, 5, 2) - 6), 2, '0'))
END AS ext_srg_carry_date
FROM
connect.table
Any help would be awesome. Thanks!
You can do away with case statements 2 and 3 if AMD_Month is a date data type, you can also do away with them if it's not but it takes an extra step:
If AMD_Month is a Date column then ext_srg_start_date and ext_srg_carry_date could be defined as:
...
, AMD_Month + INTERVAL '1' MONTH ext_srg_start_date
, AMD_Month + INTERVAL '6' MONTH ext_srg_carry_date
...
If AMD_Month is a string, then you first need to convert it to a date and I guess then convert the result back to a string:
...
, TO_CHAR( TO_DATE( AMD_Month, 'YYYYMM')
+ INTERVAL '1' MONTH, 'YYYYMM') ext_srg_start_date
, TO_CHAR( TO_DATE( AMD_Month, 'YYYYMM')
+ INTERVAL '6' MONTH, 'YYYYMM') ext_srg_carry_date
...
Date arithmatic works so much better when you store date data types as dates or timestamps than when you store them as strings.
Related
I have the following query. And I am calculating on MYDATE column which is a DECIMAL(8, 0) data type which stores datea in numeric form in YYYYMMDD format like this 20191107.
SELECT DECIMAL((TO_CHAR(TO_DATE(CAST(CAST(MYDATE AS INT) AS VARCHAR(8)), 'yyyymmdd') - 3 MONTHS, 'yyyymmdd')), 8, 0) FROM PDF_TABLE;
It works fine. However, when I use the above conversion in a WHERE clause like below, query does not return anything.
SELECT * FROM PDF_TABLE WHERE MYDATE = DECIMAL((TO_CHAR(TO_DATE(CAST(CAST(MYDATE AS INT) AS VARCHAR(8)), 'yyyymmdd') - 3 MONTHS, 'yyyymmdd')), 8, 0);
Example
Above is the data as is. Now I pass the date 20200601 as parameter in the WHERE clause of the following query, it should return the following row after subtracting 3 months from 20200601.
SELECT * FROM PDF_TABLE WHERE MYDATE = DECIMAL((TO_CHAR(TO_DATE(CAST(CAST(MYDATE AS INT) AS VARCHAR(8)), 'yyyymmdd') - 3 MONTHS, 'yyyymmdd')), 8, 0);
Try this as is:
WITH MYTAB (PDF_VOLUME, MYDATE) AS
(
VALUES
('110 GB', DEC(20200101, 8))
, ('120 GB', DEC(20200301, 8))
, ('390 GB', DEC(20200601, 8))
)
SELECT *
FROM MYTAB
WHERE MYDATE = DEC(TO_CHAR(TO_DATE(CHAR(CAST(? AS DEC(8))), 'YYYYMMDD') - 3 MONTH, 'YYYYMMDD'), 8);
How could it possibly return anything?
WHERE MYDATE = DECIMAL((TO_CHAR(TO_DATE(CAST(CAST(MYDATE AS INT) AS VARCHAR(8)), 'yyyymmdd') - 3 MONTHS
Dropping the conversions, you're asking WHERE MYDATE = MYDATE - 3 months
That's never going to be equal... Perhaps you forgot to change the inner MYDATE to CURRENT_DATE or something? That would also require the conversion to change..
Personally, I use a user defined function for this type of conversion; either write it yourself or download Alan Campin's free iDate source
WHERE MYDATE = ConvertToIDate(CCURRENT_DATE - 3 months, '*CCYMD');
The function should return a new date after the current date and the num_of_flows is added. The num_of_flows is an integer value
ALTER function [dbo].[M20_22_GetLoanMaturityDate_FIN_10]
(
#AcctAcid varchar(50),
#ScheduleNum varchar(50),
#bank_id varchar(6) = '03'
)
returns varchar(50)
as
BEGIN
Declare #lMaturityDate varchar(50)
begin
select #lMaturityDate =
case Finacle_Lrs.LR_FREQ_TYPE
when 'W' then dateadd(day, (Finacle_Lrs.NUM_OF_FLOWS - 1) * 7,Finacle_Lrs.FLOW_START_DATE)
when 'F' then dateadd(day, (Finacle_Lrs.NUM_OF_FLOWS - 1) * 14,Finacle_Lrs.FLOW_START_DATE)
when 'M' then (dateadd(month, Finacle_Lrs.NUM_OF_FLOWS - 1, Finacle_Lrs.FLOW_START_DATE))
when 'Q' then (dateadd(month, (Finacle_Lrs.NUM_OF_FLOWS - 1) * 3, Finacle_Lrs.FLOW_START_DATE))
when 'H' then dateadd(month, (Finacle_Lrs.NUM_OF_FLOWS - 1) * 6, Finacle_Lrs.FLOW_START_DATE)
when 'Y' then dateadd(month, (Finacle_Lrs.NUM_OF_FLOWS - 1) * 12, Finacle_Lrs.FLOW_START_DATE)
end
from [TEST_EIMDW_Archive].[ARCHOWN].[FINCL10_LRS] Finacle_Lrs
where Finacle_Lrs.acid = #AcctAcid
and Finacle_Lrs.shdl_num = #ScheduleNum
and Finacle_Lrs.FLOW_ID in ('PRDEM','EIDEM')
AND Finacle_Lrs.ACTIVE_FLAG = 'Y' AND Finacle_Lrs.DELETE_FLAG= 'N'
and Finacle_Lrs.bank_id = #bank_id
and Finacle_Lrs.FLOW_START_DATE = ( select max(a.FLOW_START_DATE)
from [TEST_EIMDW_Archive].[ARCHOWN].[FINCL10_LRS] a
where a.ACID = Finacle_Lrs.ACID
and a.SHDL_NUM = Finacle_Lrs.SHDL_NUM
and a.FLOW_ID in ('PRDEM', 'EIDEM') AND a.ACTIVE_FLAG = 'Y' AND a.DELETE_FLAG='N' and a.bank_id = #bank_id
);
end
return isnull(#lMaturityDate,null);
END
After doing some checks, I noted that 19629 rows are understated by altest one day when comparaing the orginal code on a oracle database. Please see oracle version of code:
FUNCTION GetLoanMaturityDate(AcctAcid VARCHAR2, ScheduleNum VARCHAR2) RETURN DATE IS
lMaturityDate DATE;
BEGIN
begin
select decode(lrs.LR_FREQ_TYPE, 'W', lrs.FLOW_START_DATE + (lrs.NUM_OF_FLOWS - 1) * 7,
'F', lrs.FLOW_START_DATE + (lrs.NUM_OF_FLOWS - 1) * 14,
'M', add_months(lrs.FLOW_START_DATE, lrs.NUM_OF_FLOWS - 1) ,
'Q', add_months(lrs.FLOW_START_DATE, (lrs.NUM_OF_FLOWS - 1) * 3),
'H', add_months(lrs.FLOW_START_DATE, (lrs.NUM_OF_FLOWS - 1) * 6),
'Y', add_months(lrs.FLOW_START_DATE, (lrs.NUM_OF_FLOWS - 1) * 12)
)
into lMaturityDate
from lrs
where lrs.acid = AcctAcid
and lrs.shdl_num = ScheduleNum
and lrs.FLOW_ID in ('PRDEM','EIDEM')
and lrs.FLOW_START_DATE = ( select max(a.FLOW_START_DATE)
from lrs a
where a.ACID = lrs.ACID
and a.SHDL_NUM = lrs.SHDL_NUM
and a.FLOW_ID in ('PRDEM', 'EIDEM')
) ;
exception
when no_data_found then
lMaturityDate:=NULL;
end;
return lMaturityDate;
END GetLoanMaturityDate;
Also here is the comparsion query I ran to see the incorrect rows:
SELECT eim.acid as eim_acid,it.[ACID] as it_acid,
eim.[MATURITY_DATE] as eim_maturity_date,it.[MATURITY_DATE] as it_maturity_date ,
eim.[DAYS_TO_MATURITY] as eim_DAYS_TO_MATURITY,it.[DAYS_TO_MATURITY] as it_DAYS_TO_MATURITY,(it.[DAYS_TO_MATURITY]-eim.[DAYS_TO_MATURITY]) as diff
FROM [TEST_EIMDW_BOJ_REPORTS].[BOJOWN].[loans_maturity_profile] eim
inner join [dbo].[IT_LOANS_MATURITY_PROFILE] it on eim.acid= it.acid
where eim.MATURITY_DATE != it.MATURITY_DATE
Finally, below is the query result showing the comparison of the correct result set verus the one I currenty trying to fix on sql server:
Just to add to what Gordon said, the exact behaviour of Oracle's ADD_MONTHS function is that if the source date is the last day of its month, then the return date is also the last day of the resulting month (regardless of the length of the month of the source date).
SQL Server has no similar function.
Which implementation is correct, or whether it matters, will depend on your particular circumstances.
Oracle's add_months() and SQL Server's dateaddd(month) have different semantics, particularly at the end of the month.
So:
select add_months(date '2019-02-28', 1)
from dual
--> 2019-03-31
(see db<>fiddle)
Whereas:
select dateadd(month, 1, '2019-02-28')
--> 2019-03-28
(see db<>fiddle)
It can be a little tricky to emulate the Oracle behavior in SQL Server. I'm not even sure if that is desirable.
SQL Server "End of month" - EOMONTH (start_date[, month_to_add ]) function will behave similar to ORACLE add_months for the last day of the month.
I'm getting this type of data in DateandTime Column in SQl.
1803301611.1803301611
Format is yymmddhhmm.yymmddhhmm and I have to convert this data in a date format.
The DateandTime Column date type is Varchar(5)
I don't think the format of your time string can be directly converted by SQL Server. But, we can try to piece together into a format which can be. This is the closest I could come, and it required prepending a 20 in front of the year to make a full 4 digit century:
SELECT
col AS input,
CONVERT(datetime, '20' + SUBSTRING(col, 1, 2) + '-' + SUBSTRING(col, 3, 2) + '-' +
SUBSTRING(col, 5, 2) + ' ' + SUBSTRING(col, 7, 2) + ':' +
SUBSTRING(col, 9, 2), 120) AS output
FROM yourTable;
Demo
We ideally should have been able to use mask 20 without the century, but I could not get it to work.
You can do :
select *, cast(concat(cast(left(col, 6) as date), ' ',stuff(right(col, 4), 3, 0, ':')
) as datetime
) as newdatetime
from table t;
i have the data which look like this
Day Month Time
11 02 12:11:11
12 02 10:10:20
13 02 9:12:6
14 02 6:7:2
as you can see the data in Time Column is not Timestamp but String, therefore some of The Data has the wrong Format like this: 9:12:6 not 09:12:06.
what i want to do now is a new Colum which combine String of Day, Month, and correct Time Format, the ":" need to be removed.
The Result should looks like this:
new Colum
1102121111
1202101020
1302091206
1402060702
Can you please help me?
Thanks
CREATE TABLE Saletime (
day VARCHAR(02) NOT NULL,
month VARCHAR(02) NOT NULL,
time VARCHAR(10) NOT NULL);
INSERT INTO saletime(day, month, time) VALUES ('11','02','12:11:11');
INSERT INTO saletime(day, month, time) VALUES ('12','02','10:10:20');
INSERT INTO saletime(day, month, time) VALUES ('13','02','9:12:6');
INSERT INTO saletime(day, month, time) VALUES ('14','02','6:7:2');
Concatenate the values then parse them
select to_char(
to_timestamp(
day||'-'||month||' '||time,
'DD-MM HH24:MI:SS'),
'DDMMHHMISS')
from Saletime;
SQL Fiddle example
Since the inputs and the output are all strings, perhaps direct string manipulation makes sense. (It would be much better if the output were date data type, but that is in your hands, not in mine.)
I follow your lead in using day and month as column names. That is a very poor practice; I hope your actual column names are different.
It's not clear if you may need the same left-padding with 0 for the day and month; just in case, I handled it too (it's done the same way).
select day, month, time,
lpad(day, 2, '0') || lpad(month, 2, '0')
|| lpad(regexp_substr(time, '\d+', 1, 1), 2, '0')
|| lpad(regexp_substr(time, '\d+', 1, 2), 2, '0')
|| lpad(regexp_substr(time, '\d+', 1, 3), 2, '0') as new_string
from saletime;
DATE MONTH TIME NEW_STRING
---- ----- --------- ----------
11 02 12:11:11 1102121111
12 02 10:10:20 1202101020
13 02 9:12:6 1302091206
14 02 6:7:2 1402060702
You can do this as a numeric calculation:
select (day * 100000000 +
month * 1000000 +
cast(regexp_substr(time, '[0-9]+', 1, 1) as number) * 10000 +
cast(regexp_substr(time, '[0-9]+', 1, 2) as number) * 100 +
cast(regexp_substr(time, '[0-9]+', 1, 3) as number) * 1
)
from saletime;
Here is a SQL Fiddle.
If you want this as a string, just convert it to a string.
We have a table that is char(5) and has data inserted like 6:45, 10:15, 3:00. Our business hours are from 6-3pm...and this table doesn't have am/pm included -a as it is char(5).... I cannot change the table, I need to change the data daily after-the-upload. All of the data loaded is x:xx or xx:xx format.
Yes, they 'should' convert before loading table, but they aren't. How can I go in and 'fix' the entries... changing the 6:00,7:00,8:00,9:00,to have a 06,07,08,09 (leading zero) and change the 1, 2, 3, 4, 5, beginning number to 13,14,15,16 with keeping the rest of the :xx part of the data?
Assuming you never have data between 1AM and 5AM, and can safely assume those values need 12 hours added... then you can convert to a TIME type, evaluate the HOUR value, and add 12 only when its between 1 and 5 - and convert it all back to a char(5) to update.
DECLARE #Sample TABLE (badTime CHAR(5))
INSERT INTO #Sample(badTime)
VALUES ('6:45'),
('07:45'),
('8:45'),
('9:45'),
('10:45'),
('11:45'),
('12:45'),
('1:45'),
('2:45'),
('3:45'),
(null),
('')
SELECT *, CONVERT(VARCHAR(5),CASE WHEN DATEPART(HH,CONVERT(TIME,badTime)) BETWEEN 1 AND 5 THEN DATEADD(HH,12,CONVERT(TIME,badTime)) ELSE CONVERT(TIME,badTime) END,108)
-- UPDATE S SET badTime = CONVERT(VARCHAR(5),CASE WHEN DATEPART(HH,CONVERT(TIME,badTime)) BETWEEN 1 AND 5 THEN DATEADD(HH,12,CONVERT(TIME,badTime)) ELSE CONVERT(TIME,badTime) END,108)
FROM #Sample S
WHERE badTime IS NOT NULL AND badTime!=''
AND ISDATE(badTime)=1
One method is a case. For the values you mention:
select (case when col like '[6789]:%' then stuff(col, 1, 1, '0' + left(col, 1)
when col like '[12345]:%' then stuff(col, 1, 1, cast(left(col, 1) + 12 as char(2))
else col
end)
If you have some data that starts with a zero:
select (case when col like '[6789]:%' then stuff(col, 1, 1, '0' + left(col, 1)
when col like '[12345]:%' then stuff(col, 1, 1, cast(left(col, 1) + 12 as char(2))
when col like '0[12345]:%' then stuff(col, 1, 2, cast(left(col, 2) + 12 as char(2))
else col
end)
And, converting to a time data type uses similar logic:
select (case when hour(cast(col as time)) in (6, 7, 8, 9)
then cast(col as time)
when hour(cast(col as time) in (1, 2, 3, 4, 5)
then dateadd(hour, 12, cast(col as time))
else cast(col as time)
end)