Calculate previous day in ABAP CDS? - date

I am starting with ABAP, I use the following instruction to obtain the date in the system but I can't get the date of the previous day, does anyone have any suggestions? THANKS.
I tried with:
{
$session.system_date as today,
$session.system_date - 1 as yesterday
}
but I can't do arithmetic operations with dates and it marks an error.

You can use DATS_ADD_DAYS function for this task.
It does not allow putting session vars directly as an argument, but we can do the following trick:
define view Z_TODAY
as select from
zsomething
{
key field1 as type1,
key field2 as type2,
...
$session.system_date as today,
DATS_ADD_DAYS( cast( $session.system_date as abap.dats ),-1,'NULL') as yesterday
}
Wrapping the system date into CAST does the thing.
Another, less intuitive way (which can be more flexible sometimes) is putting optional parameter with predefined value:
define view Z_TODAY
with parameters
#Environment.systemField : #SYSTEM_DATE
p_datum : abap.dats
as select from zsomething
{
key field1 as type1,
key field2 as type2,
...
$session.system_date as today,
DATS_ADD_DAYS( :p_datum,-1,'NULL') as yesterday
}

Related

Postgresql - select column based on condition

In this query the 'Daily' in the case will be replaced by a variable. I am not able to make this query work. I want to have the date column being either a day, a week a month or a year based on the value of the variable. but it is giving me various errors..
CASE types date and double precison cannot be matched
syntax error near "as"
what am I doing wrong?
select
case 'Daily'
when 'Daily' then DATE(to_timestamp(e.startts)) as "Date",
when 'Weekly' then DATE_PART('week',to_timestamp(e.startts)) as "Date",
when 'Monthly' then to_char(to_timestamp(e.startts), 'mm/yyyy') as "Date",
when 'Yearly' then to_char(to_timestamp(e.startts), 'yyyy') as "Date",
end
sum(e.checked)
from entries e
WHERE
e.startts >= date_part('epoch', '2020-10-01T15:01:50.859Z'::timestamp)::int8
and e.stopts < date_part('epoch', '2021-11-08T15:01:50.859Z'::timestamp)::int8
group by "Date"
CASE ... END is an expression. An expression must have a well-defined data type, so PostgreSQL makes sure that the expressions in the THEN clause have the same data type (or at least compatible ones).
You would need a type cast, probably to text, in the first two branches:
... THEN CAST (date(to_timestamp(e.startts)) AS text)
But it would be much better to use to_char in all branches – there are format codes for everything you need.
An expression can have no alias, only an entry in the SELECT or FROM list can. So you need to append AS "Date" at the end of the CASE ... END expression, not somewhere in the middle.

Modify values within a column and row (PSQL)

I get the following error for this query: [22P02] ERROR: invalid input syntax for type numeric: "."
select
date,
row_number () over () as RN,
case when (row_number() over ()) ='8' then '.' else (success/trials) end as "After_1M"
from trials
groupy by date;
Is there another way to indicate that a certain value in a ROWxCOLUMN combination should be adjusted?
Well your description certainly leaves a lot to be desired. But your query only needs slight modification to actually run. First off "groupy by date". I will assume it's just a typo. But a group by without an aggregate function generally doesn't do anything - and this is one of those. But I believe your attempting to get a row count by date. If so the you need the partition by and order by clauses in the in the row_number function. The other issue is in the expression. Each entry in the expression must return the same data type but in case it doesn't. The THEN condition returns character (.) while the ELSE returns a numeric (success/trials) which must define 2 numeric columns to be valid. So which needs to change? I will assume the later. Given this we wind up with:
select date
, row_number() over(partition by date order by trl_date) rn
, case when (row_number() over(partition by date order by trl_date)) = 8
then '.'
else (success/trials)::text
end as "After_1M"
from trials;
Note: Date is a very poor date is a very poor column name. It's a reserved word, as well as a data type.

Use subquery variable inside to_date

I need to update my date with a subquery like this, i aint got a day number .
UPDATE grh
SET date = to_date('subquery.year-subquery.week_number','YYYYWW')
FROM (SELECT year,week_number
FROM grh) AS subquery
how could i use the subquery.year variable inside the to_date fonction ?
TRY 1 : So I've tried this :
UPDATE grh SET date = to_date(week_number, 'WW');
And i have this kind of error :
function to_date(integer,unknown) doesnt exists.
but if you look at this doc : https://www.techonthenet.com/postgresql/functions/to_date.php
They say that WW exists, for specifiing a week number. My 'date' column is a date format .
TRY 2 : this is working :
UPDATE grh SET date = to_date('42018', 'WWYYYY');
As soon as I try to use a variable like that, it doesnt work :
UPDATE grh SET date = to_date(string_agg(week_number,2018), 'WWYYYY');
In Postgres( and most other SQL flavors ), the concatenation operator is ||
UPDATE grh SET date = to_date(week_number||'2018', 'WWYYYY');
The linked documentation on to_date function :
to_date( string1, format_mask )
and the error is
function to_date(integer,unknown) doesnt exists.
so i think that you have a mismatch on the type of your first parameter
Edit1:
for the statement
UPDATE grh SET date = to_date(string_agg(week_number,2018), 'WWYYYY');
if you chekc the documentation of the function string_agg you will see the expected type of input params are string and at least the second one is a integer

Convert ABAP date to HANA date returning NULL if empty

My task is to convert a ABAP style date (i.e. 2017-11-20 which is represented as string "20171120") to a HANA date via sql script. This can easily be done by:
select to_date('20171120','YYYYMMDD') from dummy;
But there is another requirement: if the abap date is initial (value '00000000') the database shall store a null value. I have found a working solution: I replace the potential initial date '00000000' with 'Z' and trim the string to null if only 'Z' is found:
select to_date(trim(leading 'Z' from replace('00000000','00000000','Z')),'YYYYMMDD') from dummy;
-- result: null
select to_date(trim(leading 'Z' from replace('20171120','00000000','Z')),'YYYYMMDD') from dummy;
-- result: 2017-11-20
But this looks like a dirty hack. Has anybody an idea for a more elegant solution?
As explained in my presentation Innovation with SAP HANA - What are my options all that string manipulation is really not necessary.
Instead, use the appropriate conversion functions when dealing with ABAP date and time data. In this case, DATS_TO_DATE is the correct function.
with in_dates as
( select '20171120' as in_date from dummy
union all select '00000000' as in_date from dummy)
select
dats_to_date(in_date)
, in_date
from in_dates;
|DATS_TO_DATE(IN_DATE) |IN_DATE
-------------------------+---------
|2017-11-20 |20171120
|? |00000000
The ? here is the output representation for NULL.
DATS_TO_DATE does not return NULL if the given date is initial (0000-00-00), but a special date value (-1-12-31 to be precise).
To receive a NULL value in this case, as you requested, use the following statement:
NULLIF( DATS_TO_DATE(?), DATS_TO_DATE('00000000'))
e. g.:
INSERT INTO null_test VALUES (NULLIF( DATS_TO_DATE('00000000'), DATS_TO_DATE('00000000')));
=> returns NULL
INSERT INTO null_test VALUES (NULLIF( DATS_TO_DATE('20171224'), DATS_TO_DATE('00000000')));
=> returns 2017-12-24
As there are no tedious string operations involved, this statement should yield good performance.

XPath - is a date null

Using XPath, how do I figure out if a date or datetime field is null or blank?
I am using the concat method as a stand-in for the XPath if statement
concat(
substring(../preceding-sibling::my:PerDiem[1]/my:perDiemEnd, 1, ../preceding-sibling::my:PerDiem[1]/my:perDiemEnd = "" * string-length(../preceding-sibling::my:PerDiem[1]/my:perDiemEnd)),
substring(/my:ExpenseForm/my:ExpenseHeader/my:departureDateTime, 1, not(../preceding-sibling::my:PerDiem[1]/my:perDiemEnd = "") * string-length(/my:ExpenseForm/my:ExpenseHeader/my:departureDateTime))
)
More info:
In Infopath 2010, a repeating table has two date/time fields called perDiemStart and perDiemEnd. In the repeating table, the next perDiemStart is the previous perDiemEnd. This is easily done if the default value of perDiemStart is ../preceding-sibling::my:PerDiem[1]/my:perDiemEnd
But for the first perDiemStart (since a previous perDiemEnd does not exist, I suppose it would be null/blank). I want that first (blank) value to be a different: value of departureDateTime node
Node locations:
/my:ExpenseForm/my:ExpenseHeader/my:departureDateTime
/my:ExpenseForm/my:PerDiemDetails/my:PerDiems/my:PerDiem/my:perDiemStart
/my:ExpenseForm/my:PerDiemDetails/my:PerDiems/my:PerDiem/my:perDiemEnd
To check if it is filled:
perDiemStart[text()]
To check if it is empty/null:
perDiemStart[not(text())]
Does this help? http://blogs.msdn.com/b/syamp/archive/2011/03/13/fim-2010-xpath-how-to-check-null-value-on-a-datetime-attribute.aspx
Basically they detect null dates by getting the set of dates after an old date (e.g. 1900-01-01) and then using 'not' to see which nodes would be excluded.