TIMESTAMP_FORMAT not working with OFFSET in DB2 - sql

I'm trying to do pagination in DB2. I wouldn't like to do it with subquery, but OFFSET is not working with TIMESTAMP_FORMAT.
Use of function TIMESTAMP_FORMAT in QSYS2 not valid. Data mapping error on member
I've found this question, but seems here the problem is with content of column and it's not my case, as values are alright and TIMESTAMP_FORMAT works without OFFSET.
I didn't look for some other way to not use TIMESTAMP_FORMAT, as I need to create pagination on queries written not by me, but by client.
The query looks like this.
SELECT DATE(TIMESTAMP_FORMAT(CHAR("tablename"."date"),'YYMMDD'))
FROM tableName
OFFSET 10 ROWS
I get
"[SQL0583] Use of function TIMESTAMP_FORMAT in QSYS2 not valid."
I'm not sure how OFFSET can relate to TIMESTAMP_FORMAT, but when I replace the select with select * it works fine.
I wonder why there is a conflict between OFFSET and TIMESTAMP_FORMAT and is there a way to bypass this without subquery.

From Listing of SQL Messages:
SQL0583
Function &1 in &2 cannot be invoked where specified because it is
defined to be not deterministic or contains an external action.
Functions that are not deterministic cannot be specified in a GROUP BY
clause or in a JOIN clause, or in the default clause for a global
variable.
Functions that are not deterministic or contain an external
action cannot be specified in a PARTITION BY clause or an ORDER BY
clause for an OLAP function and cannot be specified in the select list
of a query that contains an OFFSET clause.
The RAISE_ERROR function
cannot be specified in a GROUP BY or HAVING clause.
I don't know how to check these properties for the QSYS2.TIMESTAMP_FORMAT function (there is no its definition in the QSYS2.SYSROUTINES table), but it looks like improper definition of this function - there is no reason to create it as not deterministic or external action.
You can "deceive" DB2 like this:
CREATE FUNCTION MYSCHEMA.TIMESTAMP_FORMAT(str VARCHAR(4000), fmt VARCHAR(128))
RETURNS TIMESTAMP
DETERMINISTIC
CONTAINS SQL
NO EXTERNAL ACTION
RETURN QSYS2.TIMESTAMP_FORMAT(str, fmt);
SELECT
DATE(MYSCHEMA.TIMESTAMP_FORMAT(CHAR(tablename.date), 'YYMMDD'))
--DATE(QSYS2.TIMESTAMP_FORMAT(CHAR(tablename.date), 'YYMMDD'))
FROM table(values '190412') tableName(date)
OFFSET 10 ROWS;
And use this function instead. It works on my 7.3 at least.
It's a harmless deception, and you may ask IBM support to clarify such a "feature" of QSYS2.TIMESTAMP_FORMAT...

I suspect your problem is bad data...
The default for the IBM interactive tools, STRSQL and ACS Run SQL Scripts, is OPTIMIZE(*FIRSTIO) meaning get the first few rows back as quickly as possible...
With the OFFSET 10 clause you're probably accessing rows initially that you didn't before.
Try the following
create table mytest as (
SELECT DATE(TIMESTAMP_FORMAT(CHAR("tablename"."date"),'YYMMDD')) as mydate
FROM tableName
) with data
If that doesn't error, then yes you've found a bug, open a PMR.
Otherwise, you can see how far along the DB got by looking at the rows in the new table and track down the record with bad data.

Related

Column cannot be found or is not specified for query - Progress SQL Interface

I get the following error, I haven't had this issue before and was wondering if lvscat is an alias for something. From what I read that is a common issue, but even if it is that I am still unsure of how to fix it. This is the full Error
[DataDirect][OpenEdge JDBC Driver][OpenEdge] Column "LVSCAT" cannot be found or is not specified for query.
Here is the query:
INSERT INTO PUB.lvsbk (BookingNo, LvsCat)
VALUES (1007265, 'G')
Mapping with SQL Interface:
It is possible that the column was defined as "lvsCat". That means that the case is important.
Unfortunately, you have to use the double quotes to reference it:
INSERT INTO PUB.lvsbk (BookingNo, "LvsCat")
VALUES (1007265, 'G') ;
If this is the case, you might want to recreate the table without escaping the name of identifiers.
I am unsure what tool you are using to demonstrate the definition of your table, but you can view the actual definition of your table with:
select * from sysprogress.syscolumns where tbl = 'lvsbk';
Alternatively a simple:
select top 1 * from pub.lvsbk;
May provide enough evidence as to what your column is actually called.
I found the issue, it was because the field simply didn't exist.

How do I generate a table name that contains today's date?

It may seem a little strange, but there are already tables with names for each date.
In my project, I have tables for each date to make statistics easier to handle.
Of course, I don't think this is always the best way, but this is the table structure for my project.
(It's a common technique in Google BigQuery and Amazon Athena. This question is about Google BigQuery)
So to get the data, I want to generate today's date. If I use TODAY, I can get the data of the latest day without rewriting the code even if it is the next day.
I tried, but the code didn't work.
Not work 1:
CONCAT in FROM
SELECT
*
FROM
CONCAT('foo_', FORMAT_TIMESTAMP('%Y%m%d', CURRENT_TIMESTAMP(), 'Asia/Tokyo'))
Error:
Table-valued function not found: CONCAT at [4:3]
Not work 2:
create temporary function:
create temporary function getTableName() as (CONCAT('foo_', FORMAT_TIMESTAMP('%Y%m%d', CURRENT_TIMESTAMP(), 'Asia/Tokyo')));
Error:
CREATE TEMPORARY FUNCTION statements must be followed by an actual query.
Question
How do I generate a table name that contains TODAY's date?
In this case, I would recommend you to use Wild tables in BigQuery, which allows you to use some features in Standard SQL.
With Wild Tables you can use _TABLE_SUFFIX, it grants you the ability to filter/scan tables containing this parameter. The syntax would be as follows:
SELECT *
FROM `test-proj-261014.sample.test_*`
where _TABLE_SUFFIX = FORMAT_DATE('%Y%m%d', CURRENT_DATE)
I hope it helps.
Your first query should go like this:
select CONCAT('foo_', FORMAT_TIMESTAMP('%Y%m%d', CURRENT_TIMESTAMP(), 'Asia/Tokyo'))
For creating temporary function, use the below code:
create temp function getTableName() as
((select CONCAT('foo_', FORMAT_TIMESTAMP('%Y%m%d', CURRENT_TIMESTAMP(), 'Asia/Tokyo'))
));
select getTableName()
The error "CREATE TEMPORARY FUNCTION statements must be followed by an actual query." is because once the temporary functions are defined then you have to use the actual query to use that function and then the validity of function dies out. To define persistent UDFs and use them in multiple queries please go through the link to define permanent functions.You can reuse persistent UDFs across multiple queries, whereas you can only use temporary UDFs in a single query.

What does "SELECT INTO" do?

I'm reading sql code which has a line that looks like this:
SELECT INTO _user tag FROM login.user WHERE id = util.uuid_to_int(_user_id)::oid;
What exactly does this do? The usual way to use SELECT INTO requires specifying the columns to select after the SELECT token, e.g.
SELECT * INTO _my_new_table WHERE ...;
The database is postgresql.
This line must appear inside of a PL/pgSQL function. In that context the value from column tag is assigned to variable _user.
According to the documentation:
Tip: Note that this interpretation of SELECT with INTO is quite different from PostgreSQL's regular SELECT INTO command, wherein the INTO target is a newly created table.
and
The INTO clause can appear almost anywhere in the SQL command. Customarily it is written either just before or just after the list of select_expressions in a SELECT command, or at the end of the command for other command types. It is recommended that you follow this convention in case the PL/pgSQL parser becomes stricter in future versions.

performance of parameterised SQL

I have a query like
SELECT *
FROM myTable
WHERE key LIKE 'XYZ'
The value 'XYZ' is entered by users (and may include % and _)
If I construct the query using string concatenation it runs in 10 seconds.
But this is unsafe, and I should use a parameterised query.
So I'm constructing the query using the odbc command object and it's execute method, and passing a parameter.
SELECT *
FROM myTable
WHERE key LIKE ?
Unfortunately the parameterised SQL execute method takes a full minute.
This query is one of many that are part of a drill-down / investigation package, and I've had similar slow downs with all the parameterised queries (compared to string concatenation).
How do I find out where the time is going (and fix it) ?
Here's my guess without further information.
I've had similar problems on SQL Server. In SQL Server when the column on your table is 'varchar' and the parameterised query parameter is 'nvarchar' (or vice versa), this causes SQL Server to ignore an available index because the parameter type doesn't match the index type, which in turn results in a table scan.
It's possible the same thing happens for Sybase. If you can see the generated query you can confirm if there's a type mismatch.
If this is the case, then two solutions would be
explicitly set the type of the parameter to match the column type
change the type of the column to match the parameter type being generated
Mitch had the right suggestion.
I had to change the connection string to use the OLEDB driver, then I could set the options:
Optimize Prepare=None
Select Method=Direct

Calling a stored function (that returns an array of a user-defined type) in oracle across a database link

Normally, I call my function like so:
SELECT *
FROM TABLE(
package_name.function(parameters)
)
I'm trying to call this function across a database link. My intuition is that the following is the correct syntax, but I haven't gotten it to work:
SELECT *
FROM TABLE(
package_name.function#DBLINK(parameters)
)
> ORA-00904: "PACKAGE_NAME"."FUNCTION": invalid identifier
I've tried moving around the database link to no effect. I've tried putting it after the parameter list, after the last parenthesis, after the package name...I've also tried all of the above permutations including the schema name before the package name. I'm running out of ideas.
This is oracle 10g. I'm suspicious that the issue may be that the return type of the function is not defined in the schema in which I'm calling it, but I feel like I should be getting a different error if that were the case.
Thanks for your help!
What you're trying is the correct syntax as far as I know, but in any case it would not work due to the return type being user-defined, as you suspect.
Here's an example with a built-in pipelined function. Calling it locally works, of course:
SELECT * FROM TABLE(dbms_xplan.display_cursor('a',1,'ALL'));
Returns:
SQL_ID: a, child number: 1 cannot be found
Calling it over a database link:
SELECT * FROM TABLE(dbms_xplan.display_cursor#core('a',1,'ALL'));
fails with this error:
ORA-30626: function/procedure parameters of remote object types are not supported
Possibly you are getting the ORA-904 because the link goes to a specific schema that does not have access to the package. But in any case, this won't work, even if you define an identical type with the same name in your local schema, because they're still not the same type from Oracle's point of view.
You can of course query a view remotely, so if there is a well-defined set of possible parameters, you could create one view for each parameter combination and then query that, e.g.:
CREATE VIEW display_cursor_a_1_all AS
SELECT * FROM TABLE(dbms_xplan.display_cursor('a',1,'ALL'))
;
If the range of possible parameter values is too large, you could create a procedure that creates the needed view dynamically given any set of parameters. Then you have a two-step process every time you want to execute the query:
EXECUTE package.create_view#remote(parameters)
SELECT * FROM created_view#remote;
You have to then think about whether multiple sessions might call this in parallel and if so how to prevent them from stepping on each other.