I have this query (simplified):
FOR TABLE IN (
SELECT
tables FROM project.dataset.table)
DO
EXECUTE IMMEDIATE
FORMAT("""
SELECT
PARSE_DATE('%Y%m%d', event_date)
event_timestamp,
event_name,
user_pseudo_id,
user_first_touch_timestamp,
device.category,
device.mobile_brand_name,
device.mobile_model_name,
device.web_info.hostname,
geo.country,
geo.city,
traffic_source.name,
traffic_source.medium,
traffic_source.source
FROM
%s""", TABLE.tables);
END FOR;
I get the following error:
Query error: Invalid format specifier character "Y" in FORMAT string
The query works fine without:
PARSE_DATE('%Y%m%d', event_date)
As soon as this line is put in, it fails with the above error. The percent marks have their own meaning inside FORMAT(), however I am wondering how to make this work?
I've tried escaping and using raw strings but it is didn't work.
You should escape % in your dynamic query with additional %,
Use below
PARSE_DATE('%%Y%%m%%d', event_date)
Related
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.
I have a table with datehourminute column with string datatype and formatted as 202012062302. I want to select the date and cast it to date, so I made a query that looks like this:
select cast(date_parse(created_date, '%Y-%m-%d') as date) created_date,
daily_user
from
(
select concat(substr(datehourminute,1,4),'-',
substr(datehourminute,5,2),'-',substr(datehourminute,7,2))
as created_date, sum(users) as daily_user
from "a-schema".a-table
group by 1
)
order by 1;
However, that query returns this error:
SQL Error [100071] [HY000]: [Simba]AthenaJDBC
An error has been thrown from the AWS Athena client.
INVALID_FUNCTION_ARGUMENT: Invalid format: "(oth-er-)"
Any idea how to fix this? Thanks!
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
I am trying to convert Timestamp data type columns to Date datatype using:
bq query -q --destination_table=NEW_DATE_TABLE --replace "SELECT DATE(CURR_DT) AS CURR_DT from TEST.DATE_TABLE"
The new table shows the column as STRING rather than date. Is there a way to convert timestamp to date data type.
Requested Screenshot
If you use Standard SQL, you can do the following:
SELECT * REPLACE(EXTRACT(DATE FROM curr_dt)) AS curr_dt FROM test.date_table
If curr_dt is repeated field, then the solution will look the following:
SELECT * REPLACE(
ARRAY(
SELECT EXTRACT(DATE FROM curr_dt) FROM t.curr_dt
) AS curr_dt)
FROM test.date_table t
Consider below!
Works in both Legacy and Standard SQL
SELECT CAST(DATE(CURR_DT) AS DATE) AS CURR_DT FROM TEST.DATE_TABLE
Added to address comment
Try below - as I mentioned above - it works for both Legacy and Standard
SELECT CAST(DATE(CURR_DT) AS DATE) AS CURR_DT
FROM (SELECT CURRENT_TIMESTAMP() AS CURR_DT)
if you are interested in making your case working with Legacy SQL - provide more details about CURR_DT field
Try this
SELECT TIMESTAMP_SECONDS(CAST(CURR_DT AS INT64)) AS CURR_DT FROM TEST.DATE_TABLE
With the following query, the Oracle exception is thrown.
However, I cant see why. Can anyone shed some light?
select visit_id, to_date(response, 'DD/MM/YYYY') as convertedDate from
(
select *
from dat_results_ext
where item_name = 'CALLBACKDATE'
)
where to_date(response, 'DD/MM/YYYY') > sysdate
I understand the exception to be mean that its trying to convert the 'response' field, but it is meeting a non-numeric. Problem is the row that it should bring back has everything in the right format.
The 'response' field is a varchar field, but all the rows coming back with the 'item_name = 'CALLBACKDATE' clause are all of the correct format.
Any ideas?
The optimizer can rewrite your query before trying to find the best execution plan. In your case since you have no hints that would prevent the optimizer from doing this, it will probably unnest your subquery and rewrite your query as:
SELECT *
FROM dat_results_ext
WHERE item_name = 'CALLBACKDATE'
AND to_date(response, 'DD/MM/YYYY') > sysdate
You don't have control over the order of evaluation of the statements in the WHERE clause, so Oracle probably evaluated the to_date function first on a row that is not convertible to a date, hence the error.
I see two options to force Oracle to evaluate the statements in the order you want:
Use rownum. Rownum will materialize the subquery, preventing Oracle from merging it with the outer query:
SELECT visit_id, to_date(response, 'DD/MM/YYYY') AS convertedDate
FROM (SELECT r.*,
rownum /* will materialize the subquery */
FROM dat_results_ext r
WHERE item_name = 'CALLBACKDATE')
WHERE to_date(response, 'DD/MM/YYYY') > sysdate
Use the NO_MERGE hint:
SELECT visit_id, to_date(response, 'DD/MM/YYYY') AS convertedDate
FROM (SELECT /*+ NO_MERGE */ *
FROM dat_results_ext
WHERE item_name = 'CALLBACKDATE')
WHERE to_date(response, 'DD/MM/YYYY') > sysdate
The TO_DATE clause has to be evaluated before the truth of the WHERE clause can be determined. If you have values of response that can't be evaluated in the TO_DATE function, you'll see the error.
To be very precise, this is caused because some value of response do not match the format mask of DD/MM/YYYY. For example, if your session is set to default date format of DD-MON-YY, execute the following and you will receive the error message:-
select to_date('17/SEP/2012','DD/MM/YYYY') from dual;
ERROR:
ORA-01858: a non-numeric character was found where a numeric was expected
Since you passed a character in the month field and Oracle expects a number.