Oracle crash creating/executing view from another view in a CTE - sql

I'm trying to create a view of a CTE in Oracle 19c, but any attempt to execute the SQL or create a view from it results in a crash of the session process, giving me a "No more data to read from socket" in SQL Developer and terminating my session.
I've got a table, DATA, with a few columns, including PROJECT_ID and DATA_IDENTITY. I can select from this table just fine. I've created a recursive CTE that does some work on this table, resulting in a subset of the data being returned when the view is executed. I then save this CTE as a view, ELEMENTS_BY_PROJECT_V - I can select from this view just fine.
Now I'm working with another recursive CTE, HIERARCHY_BY_ELEMENT_V, which uses that view as its first table. Here's an outline of the two CTE queries that I've described.
CREATE OR REPLACE VIEW ELEMENTS_BY_PROJECT_V AS
WITH
HISTORY(PROJECT_ID, COMMIT_ID, PREVIOUS_ID, LVL) AS (...),
ELEMENT_DATA(PROJECT_ID, COMMIT_ID, DATA_IDENTITY, E_DATA, LVL) AS (...),
LATEST_VERSIONS(LVL, DATA_IDENTITY_ID) AS (...)
SELECT D.PROJECT_ID, D.COMMIT_ID, D.DATA_IDENTITY, D.E_DATA FROM LATEST_VERSIONS V, ELEMENT_DATA D WHERE V.LVL=D.LVL AND V.DATA_IDENTITY=D.DATA_IDENTITY
CREATE OR REPLACE VIEW HIERARCHY_BY_ELEMENT_V AS
WITH
ROOTS(PROJECT_ID, ELEMENT_ID) AS (
--SELECT PROJECT_ID, DATA_IDENTITY FROM ELEMENTS_BY_PROJECT_V -- Causes crash
--SELECT PROJECT_ID, DATA_IDENTITY FROM DATA -- Works fine
),
HIERARCHY(ROOT_PROJECT_ID, ROOT_ID, ELEMENT_ID, LVL) AS (...),
ELEMENT_DATA(ELEMENT_ID, NAME, TYPE) AS (...),
IN_PACKAGES(ROOT_PROJECT_ID, ROOT_ID, PACKAGE_NAMES, PACKAGE_IDS) AS (...)
SELECT * FROM IN_PACKAGES WHERE IN_PACKAGES.PROJECT_ID='123' AND IN_PACKAGES.ROOT_ID='abc'
In the second query:
If I use SELECT PROJECT_ID, DATA_IDENTITY FROM ELEMENTS_BY_PROJECT_V, the session errors as described above.
If I select from the table directly with SELECT PROJECT_ID, DATA_IDENTITY FROM DATA, the CTE executes fine.
This makes me think that there's an issue with calling a CTE from within another CTE. I know you can't do that explicitly, but if it's done through a view I thought that be acceptable. However, I've also tried combining both queries into a single CTE like this and that still has the session crash issue.
CREATE OR REPLACE VIEW COMBINED_V AS
WITH
HISTORY(PROJECT_ID, COMMIT_ID, PREVIOUS_ID, LVL) AS (...),
ELEMENT_DATA(PROJECT_ID, COMMIT_ID, DATA_IDENTITY, E_DATA, LVL) AS (...),
LATEST_VERSIONS(LVL, DATA_IDENTITY_ID) AS (...)
ROOTS(PROJECT_ID, ELEMENT_ID) AS (
SELECT D.PROJECT_ID, D.DATA_IDENTITY FROM LATEST_VERSIONS V, ELEMENT_DATA D WHERE V.LVL=D.LVL AND V.DATA_IDENTITY=D.DATA_IDENTITY
),
HIERARCHY(ROOT_PROJECT_ID, ROOT_ID, ELEMENT_ID, LVL) AS (...),
ELEMENT_DATA2(ELEMENT_ID, NAME, TYPE) AS (...),
IN_PACKAGES(ROOT_PROJECT_ID, ROOT_ID, PACKAGE_NAMES, PACKAGE_IDS) AS (...)
SELECT * FROM IN_PACKAGES WHERE IN_PACKAGES.PROJECT_ID='123' AND IN_PACKAGES.ROOT_ID='abc'
Any idea why I can't create or execute the second view?
EDIT
I replicated my data in an Oracle 21c installation, and in that environment the issue does not occur (probably why dbfiddle didn't show the error either). This seems to be an issue in Oracle 19c somewhere, not necessarily with the syntax.

There are plenty records about this 'crash' (you named it perfectly) like:
A problem with networking.
Wrong JDBC driver version.
Some issues with a special data structure
Database bug
and some explanations like:
"This error indicates an abort of a process, and the first step in resolving this error is to look in the alert log and look for a trace file. The "no more data to read from socket" is not a JDBC or an Oracle error. Rather, it is a generic communications error, often as the result of a TNS connectivity issue"
Some people clame they resolved it by increasing initialSize and maxActive size of connection pool.
I experienced it using the view through a double dblink - when it was changed on the other side (or simply mulfunctioning - some strange issue with null value of a number column)
instead of message about invalidity got this error. Never found out what exactly happened. Recompiling on all sides made it gone.
Try to check/change a few things:
First check that all the objects involved are valid (I don't know, but maybe you are using some dblinks or packages or some other views or ... ...)
Select OWNER, OBJECT_TYPE, OBJECT_NAME
From dba_objects
Where STATUS != 'VALID'
Order By OWNER, OBJECT_TYPE;
Second - move your CTE column aliasing into the CTE Select clause as there are some issues (some would say bugs)
when defining aliases outside, especialy if it is done multiple times and with the aliases repeating in different CTEs
-- Instead of
WITH some_cte (A_NMBR, A_LTTR) AS (Select 1, 'A' From Dual)
-- Put it this way
WITH some_cte AS (Select 1 "A_NMBR", 'A' "A_LTTR" From Dual)
I realy do hope that it will help...

Its' likely an ORACLE bug not warning you that your HIERARCHY_BY_ELEMENT_V references 2 different CTE with the same name: ELEMENT_DATA is defined in HIERARCHY_BY_ELEMENT_V itself but also in ELEMENTS_BY_PROJECT_V which is used by HIERARCHY_BY_ELEMENT_V.

Related

How do I pass a series of parameters into a TVF to get series of tables in Big Query

In Postgres I have a query that uses a table value function
SELECT
forecast.*
FROM (
SELECT
generate_series(begin_date, end_date, '1 mon'::interval)::date zdate
) zdate
LEFT JOIN LATERAL forecast_f(zdate.zdate)
forecast(forecast_version , source, forecast_date, gl_date, customer, program, rev) ON true
where 1=1;
and forecast_f looks like:
A lot of boiler plate and then:
BEGIN
return query
select * from table where a lot of parameters are pulled in.
I'm trying to do the same thing in Bigquery and have googled around a few uncommon concepts:
Generating a series
passing parameters into a udf with the right data type (always an adventure)
tvf
and the documentation did not have a lot on TVF's I thought maybe it can't handle tvfs and I'd have to join it all in to a column and split it somehow when it comes out of the function. When I googled, others complained about special cases when TVF's don't work, but that would suggest there are cases where it does work, like maybe mine. So I made this:
create or replace temp function snap(t timestamp)
as
(select * from forecast_stuff.forecast_full_practice where zfrom <= t and (zto> t or zto is null));
select * from snap(current_time())
which didn't work. Also, this fancy number:
create or replace temp function snap(t timestamp)
as
((select intersection from forecast_stuff.forecast_full_practice where zfrom <= t and (zto> t or zto is null)));
select * from snap(current_time())
Didn't work either. Something about if not exist not supported in temporary functions. I remember doing something like this in f1 or dremel a few years back. Did they not bring the technology forward?

Nested SELECT "works" when using nonexistant column - why?

folks, I have the following query in SQLite:
select license, username from check_table where
(
username not in (
select username from Address
)
) order by license, username;
Address is another table. The fun part is: Address has no usernamecolumn!!
Details:
Result: Query finished in 0.004 second(s)
If I modify the username part (e.g. to userrname) I get a no such column error, which is totally fine
it never returns any results, even when I replace username with mail_username (which actually exists) in the sub-select - which is totally strange, because it really should.
Now, my question is: Why don't I get an error here?! And does it have something to do with the fact that I never get any results?
You're selecting username from the check_table, not from the address table.
Try to add aliases and check it out:
select ct.license, ct.username
from check_table as ct
where
(
ct.username not in (
select ct.username
from Address as a
)
) order by ct.license, ct.username;
I bet if you will try to use select a.username... you'll get an error about not existing column.
For this purpose, all the time when you're using multiple tables in the query is good to use aliases.

sql server rewrites my query incorrectly?

There is a dirty data in input.
We are trying to cleanup dataset and then make some calculations on cleared data.
declare #t table (str varchar(10))
insert into #t select '12345' union all select 'ABCDE' union all select '111aa'
;with prep as
(
select *, cast(substring(str, 1, 3) as int) as str_int
from #t
where isnumeric(substring(str, 1, 3)) = 1
)
select *
from prep
where 1=1
and case when str_int > 0 then 'Y' else 'N' end = 'Y'
--and str_int > 0
Last 2 lines are doing the same thing. First one works, but if you uncomment second one it will crash with Conversion failed when converting the varchar value 'ABC' to data type int.
Obviously, SQL Server is rewriting query mixing all the conditions together.
My guess it that it considers 'case' as a havy operation and performs it as a last step. That's why workaround with case works.
Is this behavior documented in any way? or is it a bug?
This is a known issue with SQL Server, and Microsoft does not consider it a bug although users do. The difference between the two queries is the execution path. One is doing the conversion before the filtering, the other after.
SQL Server reserves the right to re-order the processing. The documentation does specify the logical processing of clauses as:
FROM
ON
JOIN
WHERE
GROUP BY
WITH CUBE or WITH ROLLUP
HAVING
SELECT
DISTINCT
ORDER BY
TOP
With (presumably but not explicitly documented here) CTEs being logically processed first. What does logically processed mean? Well, it doesn't mean that run-time errors are caught. It really determines the scope of identifiers during the compile phase.
When SQL Server reads from a data source, it can add new variables in. This is a convenient time to do this, because everything is in memory. However, this might occur before the filtering, which is what is causing the error when it occurs.
The fix to this problem is to use a case statement. So, the following CTE will usually work:
with prep as (
select *, (case when isnumeric(substring(str, 1, 3)) = 1 and str not like '%.%'
then cast(substring(str, 1, 3) as int)
end) as str_int
from #t
where isnumeric(substring(str, 1, 3)) = 1
)
Looks weird. And I think Redmond thinks so too. SQL Server 2012 introduced try_convert() (see here) which returns NULL if the conversion fails.
It would also help if you could instruct SQL Server to materialize CTEs. That would also solve the problem in this case. You can vote on adding such an option to SQL Server here.

Evaluate a varchar2 string into a condition for a SQL statement

I'm trying to find which rows are missing from 1 database to another, I already have link to the both DBs and I already found out that I can't just join separate tables so what I'm trying right now is select the ID's from one table and paste them into the select statement for the other DB however I don't know how to parse a clob into a condition.
let me explain further:
I got this collection of varchar2's with all the ID's i need to check on the other DB, and I can iterate through that collection so I get a clob with form: 'id1','id2','id3'
I want to run this query on the other DB
SELECT * FROM atable#db2
WHERE id NOT IN (clob_with_ids)
but I don't know how to tell PL/SQL to evaluate that clob as part of the statement.
id field on atable#db2 is an integer and the varchar2 id's I got are from runnning a regex on a clob
edit:
I've been ask to add the example I was trying to run:
SELECT *
FROM myTable#db1
WHERE ( (creation_date BETWEEN to_date('14-JUN-2011 00:00:00','DD-MON-YYYY HH24:MI:SS') AND to_date('14-JUN-2011 23:59:59','DD-MON-YYYY HH24:MI:SS')) )
AND acertain_id NOT IN ( SELECT to_number(REGEXP_REPLACE(REGEXP_REPLACE(REGEXP_SUBSTR(payload,'<xmlTag>([[:alnum:]]+)-'),'<xmlTag>',''),'-','')) as sameIDasOtherTable
FROM anotherTable#db2
WHERE condition1 ='bla'
AND condition2 ='blabla'
AND ( (creation_date BETWEEN to_date('14-JUN-2011 00:00:00','DD-MON-YYYY HH24:MI:SS') AND to_date('14-JUN-2011 23:59:59','DD-MON-YYYY HH24:MI:SS')) ) )
ORDER BY TO_CHAR(creation_date, 'MM/DD/YYYY') ASC;
I get error ORA-22992
Any suggestiongs?
It seems to me you have invested a lot of time in developing the wrong solution. A way simpler solution would be to use a SET operator. This query retrieves all the IDs in the local instance of ATABLE which are missing in the remote instance of the same table:
select id from atable
minus
select id from atable#db2
If your heart is set on retrieving the whole local row, you could try an anti-join:
select loc.*
from atable loc
left join atable#db2 rem
on (loc.id = rem.id )
where rem.id is null
/
I don't believe you can do that, but I've been proved wrong on many occasions... Even if you could find a way to get it to treat the contents of the CLOB as individual values for the IN you'd probably hit the 1000-item limit (ORA-01795) fairly quickly.
I'm not sure what you mean by 'I already found out that I can't just join separate tables'. Why can't you do something like:
SELECT * FROM atable#db2 WHERE id NOT IN (SELECT id FROM atable#db1)
Or:
SELECT * from atable#db2 WHERE id IN (
SELECT id FROM atable#db2 MINUS SELECT id FROM atable#db1)
(Or use #APC's anti-join, which is probably more performant!)
There may be performance issues with joining large tables on remote databases, but it looks like you have to do that at some point, and if it's a one-off task then it might be bearable.
Edited after question updated with join error
The ORA-22992 is because you're trying to pull a CLOB from the the remote database, which doesn't seem to work. From this I assume your reference to not being able to join is because you're joining two remote tables.
The simple option is not to pull all the columns - specify which you need rather than doing a select *. If you do need the CLOB value, the only thing I can suggest trying is using a CTE (WITH tmp_ids AS (SELECT <regex> FROM anotherTable#db2) ...), but I really have no idea if that avoids the two-link restriction. Or pull the IDs into a local temporary table; or run the query on one of the remote databases.

ORA-01731: circular view definition encountered

we are migrating over to oracle from sql server side.
on sqlserver we used to have a view like the following
create view blah
AS
Select column1,
column2
FROM blah;
but doing this on oracle produces circular view error.
is this not allowed on oracle side?
You cannot have a view reference itself. It logically does not make sense. A view is essentially a cached query whose results are displayed as a table. How can a query refer to itself?
Indeed, circular view definitions are not allowed in Oracle. If you have a circular view definition, then you likely have a bug in your database code that should be addressed. Perhaps the translation from SQL server to Oracle was flawed and accidentally introduced this circular definition?
You can actually do this in ORACLE, but it is more fragile, as you need to explicitly list the output columns of your CTE. So if you change the tables, you need to manually update the CTE.
Here is an example from our db, showing how to calculate the hierarchical depth of the a record...
CREATE OR REPLACE VIEW deploy.PHARMACYDISPENSE_EX
AS
WITH SRC (
PDID, WAREID, GCN_SEQNO, QTY, UOFM, XACTDTTM, CREATEDON, PROCESSEDON,
XACTTYPE, OPDID, CLOSEDON, BYPASSEDON, BYPASSEDBY, ITEMNO, LOTNO,
EXP_DATE, VOLUMETYPE, POTYPE, DEPTH
) AS (
SELECT D.PDID, D.WAREID, D.GCN_SEQNO, D.QTY, D.UOFM, D.XACTDTTM,
D.CREATEDON, D.PROCESSEDON, D.XACTTYPE, D.OPDID, D.CLOSEDON,
D.BYPASSEDON, D.BYPASSEDBY, D.ITEMNO, D.LOTNO, D.EXP_DATE,
D.VOLUMETYPE, D.POTYPE, 0 FROM deploy.PHARMACYDISPENSE D
WHERE OPDID IS NULL
UNION ALL
SELECT D.PDID, D.WAREID, D.GCN_SEQNO, D.QTY, D.UOFM, D.XACTDTTM,
D.CREATEDON, D.PROCESSEDON, D.XACTTYPE, D.OPDID, D.CLOSEDON,
D.BYPASSEDON, D.BYPASSEDBY, D.ITEMNO, D.LOTNO, D.EXP_DATE,
D.VOLUMETYPE, D.POTYPE, (S.DEPTH + 1)
FROM deploy.PHARMACYDISPENSE D JOIN SRC S ON S.PDID = D.OPDID
)
SELECT PD.*
FROM SRC PD;
The important part here is the WITH SRC (<output column list>) AS .... You need that output column list. So it is possible, and does work, it just takes a bit more code than in SQL Server.
Your example is incomplete - well at least doesn't show the pertinent parts.:
-- create a table
CREATE TABLE Scrap
(fieldName VARCHAR2(20));
-- create a view
CREATE VIEW ScrapVW1
AS
SELECT * FROM Scrap;
-- create a second view that uses the first view
CREATE VIEW ScrapVW2
AS
SELECT * FROM Scrap
UNION ALL
SELECT * FROM ScrapVW1;
-- recreate the first view that references the 2nd view which contains a reference to itself
CREATE OR REPLACE VIEW SCRAP_VW1
AS
SELECT * FROM ScrapVW2;
Gives a circular reference error when you try to recreate ScrapVW1. I would guess you have some unintentional name collision going on in your conversion. If it's quite complex I'd get rid of the 'CREATE OR REPLACE VIEW' syntax and just use CREATE VIEW which would then give you 'ORA-00955 Name already used' error.
Oracle deals with Hierarchical problems different than SQL apparently. Instead of self referring view, you can use connect by clause
SELECT employee_id, last_name, manager_id
FROM employees
CONNECT BY PRIOR employee_id = manager_id;