SAP HANA CX_AMDP_EXECUTION_FAILED Dump SQL code 339 Date SQL - abap

I have a sqlscript inside an AMDP class. I get a dump on the following statement:
sel1 = select mandt, equnr,
ROW_NUMBER() OVER ( PARTITION BY equnr ORDER BY equnr, idate, itime, mdocm) as rnum,
to_date(idate) as idate,
cast(to_varchar(idate) || to_varchar(itime) as "$ABAP.type( TSTMP_BW_EXTRACT )" ) AS mytimestmp,
LEAD(cast(to_varchar(idate) || to_varchar(itime) as "$ABAP.type( TSTMP_BW_EXTRACT )" )) OVER ( ORDER
BY equnr, idate, itime, MDOCM) timdelta,
to_decimal('0.0',25,6) as mydiff,
VLCOD,
LEAD(vlcod, 1) OVER ( ORDER BY equnr,idate,itime,MDOCM) as nxtVlcod,
TO_DECIMAL('0.0',25,6) as T_PRESS_RUN,
TO_DECIMAL('0.0',25,6) as T_PRESS_DWN,
TO_DECIMAL('0.0',25,6) as T_UPRESS_DWN
from :sel_imrg
where equnr = :v_equnr
and idate between v_date_begin and v_date_end
order by mandt, equnr, idate, itime, MDOCM;
The issue seems to be with converting separate idate and itime fields into a timestamp. I've tried many different data types for the timestamp value, such as TIMESTAMP and the ABAP type shown above. I've also tried to_timestamp(), cast(), to_decimal(), etc.
Strange thing is, almost exact same statement worked just fine in the HANA studio SQL console in a HANA sidecar.
The dump says CX_AMDP_EXECUTION_FAILED SQL error 339
"[339] (range 3) invalid number exception: invalid number: "TST"."SAPTST"."ZCL_TEST_CLASS=>EXECUTE#stb2#20210405110801": |
| l"
System is S/4 1809 SAP_ABA 75D SP5 on HANA 2.00.048.00.1591276203
I appreciate any help you all can provide.

SAP support helped me solve the problem.
Although SAP support didn't specifically mention it, there appears to be a bug in hana sql script (or undocumented feature, depending on how you look at it)
If you you are trying to form a timestamp value from a separate date and time value, you must concatenate date and time together with a space in between 'YYYY-MM-DD HH24:MI:SS'. However, you can't just use ' ' for space. You must use the ascii representation for space: char(32).
As I mentioned previously. The original version of this code worked just fine inside an anonymous block in HANA studio. Only when it is inside an AMDP did it dump.
This code successfully executes inside AMDP with no dumps:
sel1 = select mandt,
EQUNR,
ROW_NUMBER() OVER ( PARTITION BY equnr ORDER BY equnr, idate, itime, MDOCM) as rnum,
to_date(idate) as idate,
ifnull(to_timestamp( idate || char(32) || itime, 'YYYY-MM-DD HH24:MI:SS'), '0001-01-01 00:00:00') AS mytimestmp,
ifnull(LEAD(to_timestamp( idate || char(32) || itime, 'YYYY-MM-DD HH24:MI:SS')) OVER ( ORDER BY equnr, idate, itime, MDOCM), '0001-01-01 00:00:00') timdelta,
to_decimal('0.0',25,6) as mydiff,
VLCOD,
LEAD(vlcod, 1) OVER ( ORDER BY equnr,idate,itime,MDOCM) as nxtVlcod,
TO_DECIMAL('0.0',25,6) as T_PRESS_RUN,
TO_DECIMAL('0.0',25,6) as T_PRESS_DWN,
TO_DECIMAL('0.0',25,6) as T_UPRESS_DWN
from :sel_imrg
where equnr = :v_equnr
and idate between v_date_begin and v_date_end
order by mandt, equnr, idate, itime, MDOCM;

The error message "[339] (range 3) invalid number exception: invalid number refers to a failed conversion of a string to a number data type.
This means, that this is not about converting numbers or strings to a date or timestamp data type.
A potential cause for an implicit conversion is this part of the WHERE clause:
where equnr = :v_equnr
If :v_equnr is a numeric data type but the column equnr is a character data type, an implicit type conversion needs to be performed, i.e. the string equnr gets type cast into a numeric data type. When column equnr contains characters at all, this will produce the error the OP encountered.
So, this depends not just on the statement and table structure but also on the actual data in the table, which may be the reason the same statement worked on another system.

Related

How to convert a date to a string

I want yo get only the 'date hours:minutes:seconds' from the Date column
Date
10/11/22 12:14:01,807000000
11/12/22 13:15:46,650000000
29/12/22 14:30:46,501000000
and I want to get a string column with date hours:minutes:seconds
Date_string
10/11/22 12:14:01
11/12/22 13:15:46
29/12/22 14:30:46
I tried this code but it doesn't work:
select*, TO_CHAR(extract(hour from (Date)))||':'||TO_CHAR(extract(minute from (Date)))||':'||TO_CHAR(extract(second from (Date))) as Date_string
from table;
If this is a date column, you could use to_char directly:
SELECT m.*, TO_CHAR(my_date_column, 'dd/mm/yy hh24:mi:ss')
FROM mytable m
You can use REGEX SUBSTRING function to get the date string on the left.
SELECT REGEXP_SUBSTR (Date_string, '[^,]+', 1, 1)
AS left_part
FROM Table1;
where ^, means look for chars that are NOT comma on 1st position
and get the first occurrence (on the left)
Result:
LEFT_PART
10/11/22 12:14:01
11/12/22 13:15:46
29/12/22 14:30:46
reference:
https://docs.oracle.com/cd/B12037_01/server.101/b10759/functions116.htm
Just do it with the TO_DATE() and TO_CHAR() function pair, both operating on the Oracle date format strings:
Building the scenario:
-- your input ..
WITH indata(dt) AS (
SELECT '10/11/22 12:14:01,807000000' FROM dual UNION ALL
SELECT '11/12/22 13:15:46,650000000' FROM dual UNION ALL
SELECT '29/12/22 14:30:46,501000000' FROM dual
)
-- end of your input. Real query starts here.
-- Change following comma to "WITH" ..
,
-- Now convert to TIMESTAMP(9) ...
as_ts AS (
SELECT
TO_TIMESTAMP(dt ,'DD/MM/YY HH24:MI:SS,FF9') AS ts
FROM indata
)
SELECT
ts
, CAST(ts AS TIMESTAMP(0)) AS recast -- note: this is rounded
, TO_CHAR(ts,'DD/MM/YY HH24:MI:SS') AS reformatted -- this is truncated
FROM as_ts
Result:
TS
RECAST
REFORMATTED
10-NOV-22 12.14.01.807000000
10-NOV-22 12.14.02
10/11/22 12:14:01
11-DEC-22 13.15.46.650000000
11-DEC-22 13.15.47
11/12/22 13:15:46
29-DEC-22 14.30.46.501000000
29-DEC-22 14.30.47
29/12/22 14:30:46
Going by what you have in your question, it appears that the data in the field Date is a timestamp. This isn't a problem, but the names of the table (TABLE) and field (Date) present some challenges.
In Oracle, TABLE is a reserved word - so to use it as the name of a table it must be quoted by putting it inside double-quotes, as "TABLE". Similarly, Date is a mixed-case identifier and must likewise be quoted (e.g. "Date") every time it's used.
Given the above your query becomes:
SELECT TO_CHAR("Date", 'DD/MM/YY HH24:MI:SS') AS FORMATTED_DATE
FROM "TABLE"
and produces the desired results. db<>fiddle here
Generally, it's best in Oracle to avoid using reserved words as identifiers, and to allow the database to convert all names to upper case - if you do that you don't have to quote the names, and you can refer to them by upper or lower case as the database automatically converts all unquoted names to upper case internally.

What causes error "Strings cannot be added or subtracted in dialect 3"

I have the query:
WITH STAN_IND
AS (
SELECT ro.kod_stanow, ro.ind_wyrob||' - '||ro.LP_OPER INDEKS_OPERACJA, count(*) ILE_POWT
FROM M_REJ_OPERACJI ro
JOIN M_TABST st ON st.SYMBOL = ro.kod_stanow
WHERE (st.KOD_GRST starting with 'F' or (st.KOD_GRST starting with 'T') ) AND ro.DATA_WYKON>'NOW'-100
GROUP BY 1,2)
SELECT S.kod_stanow, count(*) ILE_INDEKS, SUM(ILE_POWT-1) POWTORZEN
from STAN_IND S
GROUP BY S.kod_stanow
ORDER BY ILE_INDEKS
That should be working, but I get an error:
SQL Error [335544606] [42000]: Dynamic SQL Error; expression evaluation not supported; Strings cannot be added or subtracted in dialect 3 [SQLState:42000, ISC error code:335544606]
I tried to cast it into bigger varchar but still no success. What is wrong here? Database is a Firebird 2.1
Your problem is 'NOW'-100. The literal 'NOW' is not a date/timestamp by itself, but a CHAR(3) literal. Only when compared to (or assigned to) a date or timestamp column will it be converted, and here the subtraction happens before that point. And the subtraction fails, because subtraction from a string literal is not defined.
Use CAST('NOW' as TIMESTAMP) - 100 or CURRENT_TIMESTAMP - 100 (or cast to DATE or use CURRENT_DATE if the column DATA_WYKON is a DATE).

Rename Column name in Pivot query and format its time value in format HH:MM:SS

I am preparing one report for which I need to have sum of time taken by various processes in column 2.
I am sharing small snippet in which I am not able to figure out. Below is the query.
SELECT DISTINCT *
FROM CTE_NAME
PIVOT ( SUM(TIME) FOR ACTIVITY IN ( NULL
,Process 1
,Process 2
)
) order by 2 desc
Things to be noted:-
hours_diff is the value calculated in a CTE expression above this shared snippet
hours_diff is of date type.
Things to be done:-
It is required to change the Column name NULL to TOTAL_TIME
It is required to convert the value of TIME to HH:MM:SS
Things I have tried:-
I tried using SUM(TIME) AS TOTAL_TIME ... it didn't seem to work. Also after that I tried replacing NULL with TOTAL_TIME but it changed in a way that TIME values of Process 1 shifted towards column 2.
In order to convert the time value (which is in seconds). I have this previously used TO_CHAR(TRUNC(sec_diff/3600),'FM9900') || ':' || TO_CHAR(TRUNC(MOD(sec_diff,3600)/60),'FM00') || ':' || TO_CHAR(MOD(sec_diff,60),'FM00') as time_diff. But as I am unable to fetch the column from above snippet I am not able to convert the values to HH:MM:SS
If I convert the value of TIME inside CTE then SUM function in SELECT query throws error Invalid Number as the value being passed to SUM function is in format HH:MM:SS
For giving name to the column, you can provide name in IN list of PIVOT as follows:
SELECT DISTINCT *
FROM CTE_NAME
PIVOT ( SUM(TIME) FOR ACTIVITY
IN ( NULL as TOTAL_TIME, -- THIS
,Process 1
,Process 2
)
) order by 2 desc;
To calculate HH:MI:SS from seconds, use this in select.(works for seconds in diff is less than 86400(1 day)
TO_CHAR(TRUNC(SYSDATE) + INTERVAL '1' SECOND * YOUR_COLUMN_SECONDS, 'HH24:MI:SS')
Or following will work for any bigger values
Lpad(Trunc(your_column_seconds/86400),2,'0')
|| ':' ||
Lpad(Trunc(your_column_seconds/1440),2,'0')
|| ':' ||
Lpad(Trunc(your_column_seconds/60),2,'0')
Note: column name of seconds difference generated by pivot should be used in above expression.

Invalid data error in Redshift

I have a query I am running in redshift that produces an error when I try to compare two dates. I have determined this is due to a data problem where the dates are VARCHAR and some are empty strings. The best solution is clearly to fix this at the source, but while trying to build a work around, I stumbled upon some very odd behavior.
To get around, I preselect the dates that are not empty strings, and cast as dates, then convert to integer date format (YYYYMMDD) and convert to INT. This runs fine. However, if I try to compare this with an integer in a WHERE clause, the query crashes with a data type error.
Here is a toy version of the working query
SELECT
date_id,
COUNT(*)
FROM
(
SELECT
CONVERT(int, date_id) AS date_id
FROM
(
SELECT
DATE_PART('year', start_dttm)*10000+DATE_PART('month', start_dttm)*10+DATE_PART('day', start_dttm) AS date_id
FROM
(
SELECT
CAST(start_dttm AS DATETIME) AS start_dttm
FROM
sfe.calendar_detail
WHERE
start_dttm <> ''
) cda
) cdb
) cd
GROUP BY
date_id
;
And here is the failed query
SELECT
date_id,
COUNT(*)
FROM
(
SELECT
CONVERT(int, date_id) AS date_id
FROM
(
SELECT
DATE_PART('year', start_dttm)*10000+DATE_PART('month', start_dttm)*10+DATE_PART('day', start_dttm) AS date_id
FROM
(
SELECT
CAST(start_dttm AS DATETIME) AS start_dttm
FROM
sfe.calendar_detail
WHERE
start_dttm <> ''
) cda
) cdb
) cd
WHERE
date_id >= 20170920
GROUP BY
date_id
;
As I mentioned above, the correct solution is to fix the data type and count empty dates as Nulls not empty strings, but I am very curious as to why the second query crashes on an invalid data type error.
Many Thanks!
Edit:
Here is the error
ERROR: Invalid digit, Value '1', Pos 0, Type: Integer
DETAIL:
-----------------------------------------------
error: Invalid digit, Value '1', Pos 0, Type: Integer
code: 1207
context:
query: 2006739
location: :0
process: query0_39 [pid=0]
-----------------------------------------------
Rather than converting dates to the human-readable YYYYMMDD format, it is always better to keep them as DATE or TIMESTAMP format. This way, date operations can be easily performed (eg adding 5 days to a date). You can still do easy comparison operators by using 'YYYYMMDD'::DATE.
Given that you are converting from a String, and casting to a Date seems to work, and that you have some empty strings, use this to convert it to a date:
SELECT
NULLIF(start_dttm, '')::DATE AS dt
FROM sfe.calendar_detail
WHERE dt > '20170920'::DATE
This will return a NULL if the string is empty, and a Date if it contains a date that could be converted.

query to subtract date from systimestamp in oracle 11g

I want to perform a subtraction operation on the date returned from another query and the system time in oracle SQL. So far I have been able to use the result of another query but when I try to subtract from systimestamp it gives me the following error
ORA-01722: invalid number
'01722. 00000 - "invalid number"
*Cause: The specified number was invalid.
*Action: Specify a valid number.
Below is my query
select round(to_number(systimestamp - e.last_time) * 24) as lag
from (
select ATTR_VALUE as last_time
from CONFIG
where ATTR_NAME='last_time'
and PROCESS_TYPE='new'
) e;
I have also tried this
select to_char(sys_extract_utc(systimestamp)-e.last_time,'YYYY-MM-DD HH24:MI:SS') as lag
from (
select ATTR_VALUE as last_time
from CONFIG
where ATTR_NAME='last_time'
and PROCESS_TYPE='new'
) e;
I want the difference between the time intervals to be in hours.
Thank you for any help in advance.
P.S. The datatype of ATTR_VALUE is VARCHAR2(150). A sample result of e.last_time is 2016-09-05 22:43:81796
"its VARCHAR2(150). That means I need to convert that to date"
ATTR_VALUE is a string so yes you need to convert it to the correct type before attempting to compare it with another datatype. Given your sample data the correct type would be timestamp, in which case your subquery should be:
(
select to_timestamp(ATTR_VALUE, 'yyyy-mm-dd hh24:mi:ss.ff5') as last_time
from CONFIG
where ATTR_NAME='last_time'
and PROCESS_TYPE='new'
)
The assumption is that your sample is representative of all the values in your CONFIG table for the given keys. If you have values in different formats your query will break on some other way: that's the danger of using this approach.
So finally after lots of trial and errors I got this one
1. Turns out initially the error was because the data_type of e.last_time was VARCHAR(150).
To find out the datatype of a given column in the table I used
desc <table_name>
which in my case was desc CONFIG
2. To convert VARCHAR to system time I have two options to_timestamp and to_date. If I use to_timestamp like
select round((systimestamp - to_timestamp(e.last_time,'YYYY-MM-DD HH24:MI:SSSSS')) * 24, 2) as lag
from (
select ATTR_VALUE as last_time
from CONFIG
where ATTR_NAME='last_time'
and PROCESS_TYPE='new'
) e;
I get an error that round expects NUMBER and got INTERVAL DAY TO SECONDS since the difference in date comes out to be like +41 13:55:20.663990. To convert that into hour would require a complex logic.
An alternative is to use to_data which I preferred and used it as
select round((sysdate - to_date(e.last_time,'YYYY-MM-DD HH24:MI:SSSSS')) * 24, 2) as lag
from (
select ATTR_VALUE as last_time
from CONFIG
where ATTR_NAME='last_time'
and PROCESS_TYPE='new'
) e;
This returns me the desired result i.e. the difference in hours rounded off to 2 floating digits