Timescaledb JPA time_bucket function - spring-boot

I want to use timescaledb in my spring boot application like:
#Query("""select time_bucket(':bucket' minutes) as bucket, avg(data) as value
from h_table ht
where
...
group by bucket""", nativeQuery=true)
fun getByDeviceAndCode(#Param("bucket") bucket:Int,
...) : List<ResultData>
but I've got an error:
ERROR: invalid input syntax for type interval: ":bucket minutes"
how can I pass :bucket parameter to sql?
thx,
Zamek

I think you have a mistake in the ending quote, and the time column seems missing. It has to be as follows (where time_col should be replaced with the name of your time column):
select time_bucket(':bucket minutes', time_col) as bucket, avg(data) as value ...
https://docs.timescale.com/api/latest/hyperfunctions/time_bucket/#sample-usage
If you still get the error, try to cast it explicitly to a postgres interval with something like this:
select time_bucket(cast(':bucket minutes' as interval), time_col) as bucket, avg(data) as value ...
To avoid problems, I would also change the type of bucket to a String and include the time unit (minutes) inside it. This way it will be treated as a whole string and avoid issues with single quotes:
select time_bucket(cast(:bucket as interval), time_col) as bucket, avg(data) as value ...

Related

worksheet.format("A2:A", { "numberFormat": { "type": "DATE_TIME" }}) doesn't work for text

I'm trying to log temperature and humidity to a google spreadsheet using gspread and python.
That works, however when I insert a row using the following code:
worksheet.append_row((datetime.datetime.now().strftime("%d-%m-%Y %H:%M:%S"), temp, humidity))
now for example cell 'A2' has the value: '12-05-2020 00:11:50 (Note the single quotation mark)
I want the data to be represented in a chart. This cannot be done with the above value so I have to convert it to a date_time value.
worksheet.format("A2:A", { "numberFormat": { "type": "DATE_TIME" }})
I expect the entire column to be converted to Date Time. This doesn't convert the values with a single quotation mark.
I spend the whole day trying to get this to work but for some reason I can't seem to find a way to have a 'normal' date_time value added that Google Sheets recognizes as a date_time...
If I enter a (numeric) value manually in a cell in column A. The code to set the format works just fine.
Also if I manually select the column and select he formatting from the menu it works fine with the gspread added date time rows.
I really want it to be done programmatically and not by hand of course.
Any help is greatly appreciated.
In that case, please use value_input_option as follows. By this, the date is put as the date object.
From:
worksheet.append_row((datetime.datetime.now().strftime("%d-%m-%Y %H:%M:%S"), temp, humidity))
To:
worksheet.append_row((datetime.datetime.now().strftime("%d-%m-%Y %H:%M:%S"), temp, humidity), value_input_option="USER_ENTERED")
Reference:
append_rows(values, value_input_option='RAW', insert_data_option=None, table_range=None)
ValueInputOption

ORA-01722: invalid number When I try to execute an store procedure. Oracle error

I know ORA-01722 occurs when I try to convert an invalid character to number. For example: "a123". In this case I only try to make a where condition, where the parameter is the ID of the table and the parameter is defined based on table type.
PROCEDURE SP_CPR_AGRUPAR_COMPRA(ID_SOLICITUD IN cpr_solicitud.id%type, ID_GRUPO IN cpr_solicitud.ID_GRUPO%type ) AS
BEGIN
UPDATE cpr_solicitud
SET ID_GRUPO=ID_GRUPO
WHERE id=ID_SOLICITUD;
END SP_CPR_AGRUPAR_COMPRA;
I try to format the ID_SOLICITUD with TO_NUMBER function but the error continue. Something like this:
UPDATE cpr_solicitud
SET ID_GRUPO=ID_GRUPO
WHERE id=TO_NUMBER(ID_SOLICITUD);
I did a test passing directly the information and it works.
UPDATE cpr_solicitud SET ID_GRUPO = 18 WHERE id = 942000;
I did many test and the conclusion is that the error is related to the ID_SOLICITUD parameter. I don't why but if I pass the ID_GRUPO and I leave the ID_SOLICITUD it works.
It's works:
UPDATE cpr_solicitud
SET ID_GRUPO=ID_GRUPO
WHERE id=1
It's not works:
UPDATE cpr_solicitud
SET ID_GRUPO=1
WHERE id=TO_NUMBER(ID_SOLICITUD);
As stated in the documentation:
If a SQL statement references a name that belongs to both a column and either a local variable or formal parameter, then the column name takes precedence.
Caution: When a variable or parameter name is interpreted as a column name, data can be deleted, changed, or inserted unintentionally.
In your code,
SET ID_GRUPO=ID_GRUPO
clearly falls into that warning, as #Bob hinted. Every row that matched the filter would be updated with it's current value (i.e. nothing changes), not the value passed into the procedure. As you've confirmed in a comment that the table has a column called ID_SOLICITUD too, so does:
WHERE id=ID_SOLICITUD;
You are getting the error because it is implicitly converting the column value from ID_SOLICITUD - which is presumably not numeric - to a number so it can be compared with id. The ID_SOLICITUD parameter value is not being used, so its data type isn't relevant. You are effectively doing:
UPDATE cpr_solicitud
SET cpr_solicitud.ID_GRUPO=cpr_solicitud.ID_GRUPO
WHERE cpr_solicitud.id=cpr_solicitud.ID_SOLICITUD;
which clearly isn't what you intended. If you run that statement on its on you'll get the same error.
You can either prefix the variable names with the object they actually belong to:
PROCEDURE SP_CPR_AGRUPAR_COMPRA(ID_SOLICITUD IN cpr_solicitud.id%type, ID_GRUPO IN cpr_solicitud.ID_GRUPO%type ) AS
BEGIN
UPDATE cpr_solicitud
SET ID_GRUPO=SP_CPR_AGRUPAR_COMPRA.ID_GRUPO
WHERE id=SP_CPR_AGRUPAR_COMPRA.ID_SOLICITUD;
END SP_CPR_AGRUPAR_COMPRA;
or (more simply and safely, perhaps) change the names, e.g. with a simple prefix:
PROCEDURE SP_CPR_AGRUPAR_COMPRA(p_ID_SOLICITUD IN cpr_solicitud.id%type, p_ID_GRUPO IN cpr_solicitud.ID_GRUPO%type ) AS
BEGIN
UPDATE cpr_solicitud
SET ID_GRUPO=p_ID_GRUPO
WHERE id=p_ID_SOLICITUD;
END SP_CPR_AGRUPAR_COMPRA;

Why does Java 8 DateTimeFormatter allows an incorrect month value in ResolverStyle.STRICT mode?

Why does this test pass, while the month value is obviously invalid (13)?
#Test
public void test() {
String format = "uuuuMM";
String value = "201713";
DateTimeFormatter.ofPattern(format).withResolverStyle(ResolverStyle.STRICT)
.parse(value);
}
When using a temporal query, the expected DateTimeParseException is thrown:
DateTimeFormatter.ofPattern(format).withResolverStyle(ResolverStyle.STRICT)
.parse(value, YearMonth::from);
What happens when no TemporalQuery is specified?
EDIT: the 13 value seems to be a special one, as I learned thanks to the answer of ΦXocę 웃 Пepeúpa ツ (see Undecimber).
But the exception is not thrown even with another value, like 50:
#Test
public void test() {
String format = "uuuuMM";
String value = "201750";
DateTimeFormatter.ofPattern(format).withResolverStyle(ResolverStyle.STRICT)
.parse(value);
}
I've made some debugging here and found that part of the parsing process is to check the fields against the formatter's chronology.
When you create a DateTimeFormatter, by default it uses an IsoChronology, which is used to resolve the date fields. During this resolving phase, the method java.time.chrono.AbstractChronology::resolveDate is called.
If you look at the source, you'll see the following logic:
if (fieldValues.containsKey(YEAR)) {
if (fieldValues.containsKey(MONTH_OF_YEAR)) {
if (fieldValues.containsKey(DAY_OF_MONTH)) {
return resolveYMD(fieldValues, resolverStyle);
}
....
return null;
As the input has only the year and month fields, fieldValues.containsKey(DAY_OF_MONTH) returns false, the method returns null and no other check is made as you can see in the Parsed class.
So, when parsing 201750 or 201713 without a TemporalQuery, no additional check is made because of the logic above, and the parse method returns a java.time.format.Parsed object, as you can see by the following code:
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("uuuuMM").withResolverStyle(ResolverStyle.STRICT);
TemporalAccessor parsed = fmt.parse("201750");
System.out.println(parsed.getClass());
System.out.println(parsed);
The output is:
class java.time.format.Parsed
{Year=2017, MonthOfYear=50},ISO
Note that the type of the returned object is java.time.format.Parsed and printing it shows the fields that were parsed (year and month).
When you call parse with a TemporalQuery, though, the Parsed object is passed to the query and its fields are validated (of course it depends on the query, but the API built-in ones always validate).
In the case of YearMonth::from, it checks if the year and month are valid using the respective ChronoField's (MONTH_OF_YEAR and YEAR) and the month field accepts only values from 1 to 12.
That's why just calling parse(value) doesn't throw an exception, but calling with a TemporalQuery does.
Just to check the logic above when all the date fields (year, month and day) are present:
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("uuuuMMdd").withResolverStyle(ResolverStyle.STRICT);
fmt.parse("20175010");
This throws:
Exception in thread "main" java.time.format.DateTimeParseException: Text '20175010' could not be parsed: Invalid value for MonthOfYear (valid values 1 - 12): 50
As all the date fields are present, fieldValues.containsKey(DAY_OF_MONTH) returns true and now it checks if it's a valid date (using the resolveYMD method).
The month 13 is called : Undecimber
The gregorian calendar that many of us use allows 12 months only but java includes support for calendars which permit thirteen months so it depends on what calendar system you are talking about
For example, the actual maximum value of the MONTH field is 12 in some years, and 13 in other years in the Hebrew calendar system. So the month 13 is valid
It is a little odd that an exception is not thrown when parse is called without a given TemporalQuery. Some of the documentation for the single argument parse method:
This parses the entire text producing a temporal object. It is typically more useful to use parse(CharSequence, TemporalQuery). The result of this method is TemporalAccessor which has been resolved, applying basic validation checks to help ensure a valid date-time.
Note that it says it is "typically more useful to use parse(CharSequence, TemporalQuery)". In your examples, parse is returning a java.time.format.Parsed object, which is not really used for anything other than creating a different TemporalAccessor.
Note that if you try to create a YearMonth from the returned value, an exception is thrown:
YearMonth.from(DateTimeFormatter.ofPattern(format)
.withResolverStyle(ResolverStyle.STRICT).parse(value));
throws
Exception in thread "main" java.time.DateTimeException: Unable to obtain YearMonth from TemporalAccessor: {Year=2017, MonthOfYear=50},ISO of type java.time.format.Parsed
at java.time.YearMonth.from(YearMonth.java:263)
at anl.nfolds.Test.main(Test.java:21)
Caused by: java.time.DateTimeException: Invalid value for MonthOfYear (valid values 1 - 12): 50
at java.time.temporal.TemporalAccessor.get(TemporalAccessor.java:224)
at java.time.YearMonth.from(YearMonth.java:260)
... 1 more
Documentation for Parsed:
A store of parsed data.
This class is used during parsing to collect the data. Part of the parsing process involves handling optional blocks and multiple copies of the data get created to support the necessary backtracking.
Once parsing is completed, this class can be used as the resultant TemporalAccessor. In most cases, it is only exposed once the fields have been resolved.
Since:1.8
#implSpecThis class is a mutable context intended for use from a single thread. Usage of the class is thread-safe within standard parsing as a new instance of this class is automatically created for each parse and parsing is single-threaded

pg: exec_params not replacing parameters?

First time using pg gem to access postgres database. I've connected successfully and can run queries using #exec, but now building a simple query with #exec_params does not seem to be replacing parameters. I.e:
get '/databases/:db/tables/:table' do |db_name, table_name|
conn = connect(db_name)
query_result = conn.exec_params("SELECT * FROM $1;", [table_name])
end
results in #<PG::SyntaxError: ERROR: syntax error at or near "$1" LINE 1: SELECT * FROM $1; ^ >
This seems like such a simple example to get working - am I fundamentally misunderstanding how to use this method?
You can use placeholders for values, not for identifiers (such as table and column names). This is the one place where you're stuck using string interpolation to build your SQL. Of course, if you're using string wrangling for your SQL, you must be sure to properly quote/escape things; for identifiers, that means using quote_ident:
+ (Object) quote_ident(str)
Returns a string that is safe for inclusion in a SQL query as an identifier. Note: this is not a quote function for values, but for identifiers.
So you'd say something like:
table_name = conn.quote_ident(table_name)
query_result = conn.exec("SELECT * FROM #{table_name}")

ORA - 00972 : identifier too long

I am getting error (ORA - 00972 : identifier too long) while creating the view.
Please find the view statement.
create or replace view ELVW_ATM_REC_HANDOFF_1
(Rectype
,Recseq
,Record_Type
,Record_Sequence
,MESSAGE_TYPE
,PAN
,PROCESSING_CODE
,TRANSACTION_AMOUNT
,TRANSACTION_CURRENCY_CODE
,SETTLEMENT_AMOUNT
,SETTLEMENT_CURRENCY_CODE
,Billing_AMOUNT
,Billing_CURRENCY_CODE
,Transaction_DATE
,Settlement_Date
,TRACE
,REFERENCE_NUMBER
,Switch_Log_ID
,AUTHORIZATION_NUMBER
,RESPONSE_CODE
,Host_Error_Code
,TERMINAL_ID
,Acceptor_ID
,ACQUIRING_INSTITUTION_CODE
,REV_FLAG
,Original_Trace_Number
,From_Account
,To_Account)
as
select * from
(select 'FT'
,'count'
,'DT'
,rownum
,msg_type
,pan,proc_code
,txn_amt
,txn_ccy_code
,setl_amt
,setl_ccy_code
,bill_amt
,bill_ccy_code
,trans_dt_time
,setl_date
,stan,trn_ref_no
,'iso field 60'
,'isofield 38'
,resp_code
,error_code
,term_id
,'ISOmessage42'
,acq_ins_id
,decode(substr(msg_type,1,1),4,reverse(msg_type),msg_type)
,'ISOfield90'
,from_acc
,to_acc
from swtb_txn_log)
It seems error occurs at the decode function. if i comment it. its working fine. Please find the below code
create or replace view ELVW_ATM_REC_HANDOFF_1(Rectype,Recseq,Record_Type,Record_Sequence,MESSAGE_TYPE,PAN,PROCESSING_CODE,TRANSACTION_AMOUNT,TRANSACTION_CURRENCY_CODE,SETTLEMENT_AMOUNT,SETTLEMENT_CURRENCY_CODE,Billing_AMOUNT,Billing_CURRENCY_CODE,Transaction_DATE,/*Transaction_TIME,*/Settlement_Date,TRACE,REFERENCE_NUMBER,Switch_Log_ID,AUTHORIZATION_NUMBER,RESPONSE_CODE,Host_Error_Code,TERMINAL_ID,Acceptor_ID,ACQUIRING_INSTITUTION_CODE,/*REV_FLAG,*/Original_Trace_Number,From_Account,To_Account) as
select * from (select 'FT','count','DT',rownum,msg_type,pan,proc_code,txn_amt,txn_ccy_code,setl_amt,setl_ccy_code,bill_amt,bill_ccy_code,trans_dt_time,/*trans_dt_time,*/setl_date,stan,trn_ref_no,'iso field 60',
'isofield 38',resp_code,error_code,term_id,'ISOmessage42',acq_ins_id,/*decode(substr(msg_type,1,1),4,reverse(msg_type),msg_type),*/'ISOfield90',from_acc,to_acc from swtb_txn_log)
I have checked the length of the column name. Its less than 30 characters. Looking forward for your help.
Try giving an alias (that is shorter than 30 characters) to the DECODE function.
Example:
DECODE( ...stuff... ) MYALIAS
True, all of the column names in the view spec are less than thirty characters.
Howver, your view includes a inline query:
select * from ( select ...
This may be the problem. Because it may be trying to work out at identifier for DECODE() statement at that intermediate point. I say "may" because I can't reproduce this on my 10g box: defining column names for the view solves the ORA-01948.
Regardless, you can fix the problem simply by giving your DECODE() column an alias which is of an acceptable length.

Resources