I'm trying to use a CTE in a DB2 LUW v11.5.4.0 scalar subquery, but this doesn't work:
SELECT 1
FROM SYSIBM.dual
WHERE 1 IN (
WITH t (x) AS (SELECT 1 FROM SYSIBM.dual)
SELECT * FROM t
);
I'm getting this error:
SQL Error [42601]: An unexpected token "AS" was found following "1 IN (
WITH t (x)". Expected tokens may include: "JOIN".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.26.14
Can this be done? Is there a workaround?
(This is similar but not the same as this question, which is about derived tables, not scalar subqueries. Derived tables support CTE in version 11.5.4.0)
It seems that in version 11.5.4.0, it's possible to use CTEs in derived tables, so the query can be emulated as follows:
SELECT 1
FROM SYSIBM.dual
WHERE 1 IN (
SELECT *
FROM (
WITH t (x) AS (SELECT 1 FROM SYSIBM.dual)
SELECT * FROM t
) t
);
However, this workaround also doesn't work in older versions of Db2, e.g. in version v11.1.4.4 as can be seen in this dbfiddle or in this question. The workaround in those versions will be to push the CTE to the top level of the query:
WITH t (x) AS (SELECT 1 FROM SYSIBM.dual)
SELECT 1
FROM SYSIBM.dual
WHERE 1 IN (
SELECT * FROM t
);
Side note
HSQLDB seems to suffer from a similar limitation / bug, see https://sourceforge.net/p/hsqldb/bugs/1617.
Related
If I have an Oracle SQL query like this:
with
query1 as (
select * from animals where type = 'dog'
),
query2 as (
select * from animals where type = 'cat'
)
select * from query1;
Will the DBMS actually do the work of resolving/running query2, or does Oracle know that query2 is not required by the final output, so the work of that CTE/with should be skipped?
Oracle version is 12c Enterprise.
I was going going to say "it's up to the optimizer" or "this is hard to answer" or "you need to look at the execution plan". But coming up with a single example where the code is not run is sufficient.
So here is an example demonstrating that at least one version of Oracle for at least one example does not evaluate the CTE:
with query1 as (
select * from animals where type = 'dog'
),
query2 as (
select a.*, type + 1 from animals a
)
select * from query1;
The second CTE would generate an error if it were evaluated.
This is not a guarantee, of course, that Oracle always ignores unused CTEs. And there could possibly be more arcane explanations for the behavior, but non-evaluation seems like the simplest.
This is a minimized version of complex recursive query. The query works when columns in recursive member (second part of union all) of recursive CTE are listed explicitly:
with t (c,p) as (
select 2,1 from dual
), rec (c,p) as (
select c,p from t
union all
select t.c,t.p from rec join t on rec.c = t.p
)
select * from rec
I don't get why error ORA-01789: query block has incorrect number of result columns is raised when specified t.* instead.
with t (c,p) as (
select 2,1 from dual
), rec (c,p) as (
select c,p from t
union all
select t.* from rec join t on rec.c = t.p
)
select * from rec
Why t.* is not equivalent to t.c,t.p here? Could you please point me to documentation for any reasoning?
UPDATE: reproducible on 11g and 18 (dbfiddle).
I finally asked on AskTom forum and according to response from Oracle expert Connor McDonald, this behavior is in compliance with documentation, namely the sentence The number of column aliases following WITH query_name and the number of columns in the SELECT lists of the anchor and recursive query blocks must be the same which can be found in this paragraph.
The point is, the expansion of star expression is done after checking whether the numbers of columns are same. Hence one must list columns explicitly, shortening to star is not possible.
Seems like there could be some kind of bug to me. I modified the query slightly just to test various cases and am now able to reproduce an ORA-00600 error in my Oracle 19.6.0.0.0 database! Running the problematic query on apex.oracle.com or on livesql.oracle.com (which is running 19.8.0.0.0) also results in errors. Reporting it to Oracle now!
In Oracle, we can write this to generate a single row using a SELECT statement.
SELECT 1 AS x FROM dual
What is Teradata's equivalent?
Generally, no such table is needed
In most cases, no table is really needed in the Teradata database. The following is valid SQL (just like in H2, PostgreSQL, Redshift, SQL Server, SQLite, Sybase ASE, Sybase SQL Anywhere, Vertica)
SELECT 1
SELECT 1 WHERE 1 = 1
Exceptions
However, there is an exception, when a set operation is desireable. E.g. this is invalid in Teradata:
SELECT 1 UNION ALL SELECT 2
Yielding this error:
A SELECT for a UNION,INTERSECT or MINUS must reference a table.
But since the FROM clause is generally optional, it's very easy to emulate a DUAL table as follows:
SELECT 1 FROM (SELECT 1 AS "DUMMY") AS "DUAL"
UNION ALL
SELECT 2 FROM (SELECT 1 AS "DUMMY") AS "DUAL"
Compatibility
In case compatibility needs to be achieved with Oracle etc, it is easy to create a view that behaves like Oracle's dual:
CREATE VIEW "DUAL" AS (SELECT 1 AS "DUMMY");
Notice that DUAL is a keyword in Teradata, thus the view needs to be quoted.
Other dialects
In case anyone is interested, the jOOQ user manual lists various ways of emulating DUAL (if it's required) in 30+ SQL dialects.
Trying to execute in SQLAssitant (v 15.x Teradata):
WITH TEMP1 (EMP_ID,E_NAME,E_SAL) AS (WITH TEMP (EMP_ID,E_NAME,E_SAL) AS (SELECT EMP_ID,E_NAME,E_SAL FROM EMP_TABLE_TEST)
SELECT EMP_ID,E_NAME,E_SAL FROM TEMP) SELECT EMP_ID,E_NAME,E_SAL FROM TEMP1
Error: SELECT Failed. 6926: definitions, views, triggers or stored procedure
WITH TEMP (EMP_ID,E_NAME,E_SAL) AS (SELECT EMP_ID,E_NAME,E_SAL FROM EMP_TABLE_TEST ) , TEMP1 (EMP_ID,E_NAME,E_SAL) AS (
SELECT EMP_ID,E_NAME,E_SAL FROM TEMP) SELECT EMP_ID,E_NAME,E_SAL FROM TEMP1
Error: SELECT Failed. 3807: Object 'TEMP' does not exist.
Does Teradata really support Multiple WITH clause or WITH within WITH clause?
I heard it is supported in 14.x higher version but it is not supporting for 15.x.
The syntax is different (and is the same as in other databases)
With t1 as (...),t2 as (...), t3 as (...) select ...
Currently the reference order is upside-down -
t2 can refer t3 and t1 can refer t2 and t3.
The "right" order will be supported in TD16.
This has been fixed in Teradata 16. Please see the release summary chapter 2.
http://www.info.teradata.com/doclist.cfm?RetainParams=Y&FilterCall=Y&selDocType=100
Previously, when a nonrecursive WITH clause defined multiple CTEs, a CTE could only reference a
subsequent CTE in the WITH clause. Now, a CTE can reference a preceding or subsequent CTE in the
WITH clause.
From Teradata Release Summary for version 16
I receive the following error when I try to execute a sql statement that uses a CTE:
ORA-32033: unsupported column aliasing
32033. 00000 - "unsupported column aliasing"
*Cause: column aliasing in WITH clause is not supported yet
*Action: specify aliasing in defintion subquery and retry
Error at Line: 1 Column: 9
The code I am trying to execute is:
WITH cte1
(
SELECT *
FROM test_table
)
SELECT *
FROM cte1;
I know this is a simple statement and there is no need to use a CTE, but I am just trying to start using CTEs in Oracle (I am coming from T-SQL).
Why doesn't the code execute?
You're missing the AS:
WITH cte1 AS
(
SELECT *
FROM test_table
)
SELECT *
FROM cte1;
I just figured this out - I need the AS keyword after the CTE name. So the statement should be:
WITH cte1 AS
(
SELECT *
FROM test_table
)
SELECT *
FROM cte1;