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;
Related
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.
I am trying to create a view based on complex query in HSQLDB (version 2.5.1).
The query looks like this (simplified for clarity), also includes DDL for the tables:
DROP VIEW TEST_VIEW IF EXISTS;
DROP TABLE TEST_1 IF EXISTS;
CREATE TABLE TEST_1 (
contentid VARCHAR(10),
contenttype VARCHAR(10),
downloaddate TIMESTAMP
);
DROP TABLE TEST_2 IF EXISTS;
CREATE TABLE TEST_2 (
dbid INTEGER,
contentid VARCHAR(10),
version VARCHAR(10)
);
CREATE VIEW TEST_VIEW AS
WITH a AS (
SELECT CONTENTID, count(*) AS amount
FROM TEST_2
GROUP BY CONTENTID
),
b AS (
SELECT CONTENTID, amount
FROM a
)
SELECT b.CONTENTID, b.amount, i.DOWNLOADDATE
FROM b /* error here */
JOIN TEST_1 i ON i.CONTENTID = b.CONTENTID
ORDER BY b.CONTENTID;
However, it fails with the following error:
[42501][-5501] user lacks privilege or object not found: JOIN in statement [CREATE VIEW TEST_VIEW AS......
The same query runs fine when used as a SELECT (without CREATE VIEW...AS).
Also, the view is created successfully if there is only one table expression in WITH...AS statement, like below:
CREATE VIEW TEST_VIEW AS
WITH a AS (
SELECT CONTENTID, count(*) AS amount
FROM TEST_2
GROUP BY CONTENTID
)
SELECT a.CONTENTID, a.amount, i.DOWNLOADDATE
FROM a
JOIN TEST_1 i ON i.CONTENTID = a.CONTENTID
ORDER BY a.CONTENTID;
It looks like in the first statement the DB engine tries to parse "JOIN" as a table alias for table "b".
Is there a syntax error I have not noticed, or does HSQLDB not support multiple table expressions in WITH...AS inside of CREATE VIEW?
Edit: Updated example query to include table DDL for completeness.
HSQLDB supports creating this type of view.
As you haven't provided table definitions, I tried with a similar query with the test tables that are generated by DatabaseManager and it was successful. Please report the tables.
CREATE VIEW REPORT_LINKED_IDS AS
WITH a AS (
SELECT PRODUCTID, count(*) AS amount
FROM ITEM
GROUP BY PRODUCTID
),
b AS (
SELECT PRODUCTID, amount
FROM a
)
SELECT b.PRODUCTID, b.amount, i.NAME, i.PRICE
FROM b
JOIN PRODUCT i ON i.ID = b.PRODUCTID
ORDER BY b.PRODUCTID;
Thanks to a suggestion by #fredt, I have confirmed that the issue is with trying to use this query in IntelliJ IDEA (2020.1). The query worked fine and the view was created successfully in the same DB when another tool was used (DbVisualizer in my case). Furthermore, after having created the view in DB, IntelliJ IDEA throws an exception on the same word "JOIN" when trying to connect to this DB - the error is similar to this: The specified database user/password combination is rejected: org.hsqldb.HsqlException: unexpected token: NOT. Similarly to a comment in the above question, I have recovered from the error by manually editing the .script file.
There are at least 2 possible options to resolve the issue:
1st solution: Refactor SQL query to only have one table in WITH clause. In my case I just moved the first table to a select expression in FROM clause, like below:
CREATE VIEW TEST_VIEW AS
WITH b AS (
SELECT CONTENTID, amount
FROM (
SELECT CONTENTID, count(*) AS amount
FROM TEST_2
GROUP BY CONTENTID
)
)
SELECT b.CONTENTID, b.amount, i.DOWNLOADDATE
FROM b
JOIN TEST_1 i ON i.CONTENTID = b.CONTENTID
ORDER BY b.CONTENTID;
2nd solution: Use a different tool to work with the DB, or have the issue fixed in IDEA.
I have a strange issue with a query.
Here is a visual explanation of what happens, following is the textual description and the code to reproduce the problem.
a simple query containing the following inner join:
TABLE 1 TABLE 2
id year month inner join id year month
'2020.05' 2020 5 (on id) '2020.05' 2020 5
'2020.05' 2020 5 '8888.88' 8888 88
'2020.05' 2020 5
This query returns the three records with id '2020.05'
example :
SELECT table2.year, table2.month from QueryAbove
returns 3 times 2020,5 :
2020,5
2020,5
2020,5
the problem occurs if I add in the select the function:
SELECT datefromparts(year, month, 1), table2.year, table2.month from QueryAbove
Instead of returning 3 times 2020,5 it will fail because there is the unvalid value 88 for the datefromparts function in the month column of table2....(??) and although this record is not in the result.
This problem occurs to me starting with 3 records in table 1, with 2 or 1 it works fine.
The original query I have that experiences this problem has a lot more data and starts failing with 50 records, so if it works for you try adding more data in table 1 until it fails.
I could reproduce the problem with simple data, please find the code below.
I created a view that returns the result of the inner join query (but the problem still occurs without the view)
This looks like memory related, but I can't explain why and how this is occurring, and I would be very interested to understand this.
If someone knows what is going on, I thank you in advance for the information.
please tell me if more information is needed or if something is not clear in my explanation.
------ create tables -----
if OBJECT_ID('dbo.test_view') is not null
begin
drop view dbo.test_view
end
IF OBJECT_ID(N'dbo.temp_fact') IS NOT NULL
BEGIN
DROP TABLE dbo.temp_fact
END
GO
IF OBJECT_ID(N'dbo.temp_dim') IS NOT NULL
BEGIN
DROP TABLE dbo.temp_dim
END
GO
create table temp_fact
(
submission_bk varchar(30) not null
)
create table temp_dim
(
submission_bk varchar(30) not null,
[Submission_Year] int not null,
[Submission_Month] int not null
)
insert into temp_dim
select '2020.05', 2020, 5 union all
select '8888.88', 8888, 88
insert into temp_fact
select '2020.05' union all
select '2020.05' union all
-- select '2020.05' union all
select '2020.05'
---- create view ----------
create view test_view as (
select
FACT.submission_bk as submission_id,
s.Submission_Year,
s.Submission_Month
from temp_fact as FACT
inner join temp_dim as s on s.Submission_BK = FACT.Submission_BK
)
------ query the view -------
select
[submission_id],
[Submission_Year],
[Submission_Month],
datefromparts(Submission_Year, Submission_Month, 1) as bdate
from test_view
The logical evaluation of the query has nothing to do with this. The "logical evaluation" really refers to the scoping rules used during the compilation phase. Unfortunately, this part of the documentation has not bee updated in decades to clarify this point.
The SQL query itself is run as a directed acyclic graph (DAG). The compilation and optimization phase constructs the graph from the original query. And there is little similarity between the two. That is, there is no "group by" node in the DAG; no "where" node in that DAG.
One of the consequences is that SQL Server moves operations around. It often finds that running simple expressions before filtering is more efficient than running them after filtering. And this results in errors such as the one you find.
Personally, I think this is a bug. Your code should not generate an error, because it is valid on the data that you choose. Alas, Microsoft does not agree with that interpretation.
Unfortunately, there is no try_datefromparts() function. But you can use another try_ function. I would probably use:
try_convert(date, convert(varchar(100), year*10000 + month*100 + 1))
The interesting in such cases is that sometimes the statement will not rise an error.
From the docs, the Logical Processing Order of the SELECT statement is as follows:
FROM
ON
JOIN
WHERE
GROUP BY
WITH CUBE or WITH ROLLUP
HAVING
SELECT
DISTINCT
ORDER BY
TOP
But sometimes, the engine may start performing an operation in the SELECT before other clauses are finished in order to optimize the query. This is also, pointed in the docs:
The preceding sequence is usually true. However, there are uncommon
cases where the sequence may differ.
For example, suppose you have a clustered index on a view, and the
view excludes some table rows, and the view's SELECT column list uses
a CONVERT that changes a data type from varchar to integer. In this
situation, the CONVERT may execute before the WHERE clause executes.
Uncommon indeed. Often there is a way to modify your view to avoid the
different sequence, if it matters in your case.
In your case, the following should solve the issue:
select
[submission_id]
,[Submission_Year]
,[Submission_Month]
,datefromparts(Submission_Year,Submission_Month,1) as bdate
from test_view
WHERE TRY_CAST(CONCAT(Submission_Year, '-', Submission_Month, '-01') AS DATE) IS NOT NULL
I have this sql view, this is not my code:
SELECT
`view_combined_rev_data`.`date` AS `date`,
`view_combined_rev_data`.`book_title` AS `book_title`,
`view_combined_rev_data`.`marketplace` AS `marketplace`,
`view_combined_rev_data`.`amazon_kdp_avg_list_price` AS `amazon_kdp_avg_list_price`,
`view_combined_rev_data`.`amazon_kdp_royalty_type` AS `amazon_kdp_royalty_type`,
`view_combined_rev_data`.`amazon_kdp_revenue_in_usd` AS `amazon_kdp_revenue_in_usd`,
`view_combined_rev_data`.`amazon_kdp_royalty_in_usd` AS `amazon_kdp_royalty_in_usd`,
`view_combined_rev_data`.`amazon_kdp_paid_downloads` AS `amazon_kdp_paid_downloads`,
`view_combined_rev_data`.`amazon_kdp_free_downloads` AS `amazon_kdp_free_downloads`,
`view_combined_rev_data`.`amazon_ku_pages_read` AS `amazon_ku_pages_read`,
`view_combined_rev_data`.`amazon_ku_revenue_in_usd` AS `amazon_ku_revenue_in_usd`,
`view_combined_rev_data`.`create_space_revenue_in_usd` AS `create_space_revenue_in_usd`,
`view_combined_rev_data`.`create_space_royalty_in_usd` AS `create_space_royalty_in_usd`,
`view_combined_rev_data`.`create_space_paperbacks_sold` AS `create_space_paperbacks_sold`,
(
(
`view_combined_rev_data`.`amazon_kdp_revenue_in_usd` + `view_combined_rev_data`.`amazon_ku_revenue_in_usd`
) + `view_combined_rev_data`.`create_space_revenue_in_usd`
) AS `daily_total_revenue`,
(
(
`view_combined_rev_data`.`amazon_kdp_royalty_in_usd` + `view_combined_rev_data`.`create_space_royalty_in_usd`
) + `view_combined_rev_data`.`amazon_ku_revenue_in_usd`
) AS `daily_total_royalty`
FROM
`view_combined_rev_marketplace_data` `view_combined_rev_data`
My question is simple:
Why view_combined_rev_marketplace_data is used in this line. I can't find the code using it anywhere else, so can I simply remove it?
FROM
`view_combined_rev_marketplace_data` `view_combined_rev_data`
This is your FROM clause:
FROM `view_combined_rev_marketplace_data` `view_combined_rev_data`
The first name, view_combined_rev_marketplace_data is the name of a table or view (presumably a view) that exists in the database.
The second name, view_combined_rev_data, is a table alias. This is how the table/view is referred to in the query.
I recommend that you use table/view aliases that are abbreviations for the table/view name, something like this:
FROM `view_combined_rev_marketplace_data` vcrmd
Then the references to columns would look like:
SELECT vcrmd.`date` AS `date`,
vcrmd.`book_title` AS `book_title`,
. . .
And this would further simplify to:
SELECT vcrmd.`date`,
vcrmd.`book_title`,
. . .
The column alias (name given after the as) is unnecessary in this case, because it defaults to the column name. Note, though, that local coding styles may recommend having explicit column aliases.
FROM
`view_combined_rev_marketplace_data` `view_combined_rev_data`
These are not two views, but one view view_combined_rev_marketplace_data with an alias view_combined_rev_data.
When an alias is used to reference a table/view/function, then it must be used in the statement instead of the object's name. Usually aliases are meant to provide a shorter or more readable reference to the SQL object. In this case it is relatively long.
I get that I should add alias with all the columns and I'm doing so but I'm still getting error.
CREATE TABLE MENTIONS AS SELECT
UM.USER_ID AS U_ID,
UM.SCREEN_NAME AS USER_SCREEN_NAME,
UM.MENTION_ID AS M_USER_ID,
(
SELECT
UI.USER_SCREEN_NAME AS MENTIONED_USER
FROM
USER_INFO UI
WHERE
UI.USER_ID = UM.MENTION_ID
AND ROWNUM = 1
)
FROM
USER_MENTION UM
USER_MENTION table
USER_ID SCREEN_NAME MENTION_ID
135846337 irisschrijft 774759032636727300
50117969 Chjulian 13769472
14411827 thenriques45 13769472
26681613 ahenotri 252074645
26681613 ahenotri 9796472
158378782 SpringerOpen 9796472
144241914 Kumarappan 252074645
User_INFO table:
USER_ID USER_SCREEN_NAME
22553325 jasonesummers
23435691 QRJAM false
67421923 inTELEgentMSP
97393397 knauer0x
85303739 MarriageTheorem
3842711 seki
3036414608 Bayes_Rule
838677852 BOLIGATOR
I'm still getting the above mentioned error, what am I doing wrong?
Lookup the Oracle Error Message Manual of the current Oracle version. Here the error is mentioned but without additional information.
In such a case look up the
Oracle Error Message Manual of version 9i
For reasons I don't know a lot of error messages have a description in the 9i manual but not in the manuals of higher versions. 9i is a rather old version so the description may be out of date. But it may contain valuable hints.
ORA-00998 must name this expression with a column alias
Cause: An expression or function was used in a CREATE VIEW statement, but no corresponding column name was specified. When expressions or functions are used in a view, all column names for the view must be explicitly specified in the CREATE VIEW statement.
Action: Enter a column name for each column in the view in parentheses after the view name.
We don't have a view but a a table that was created by a select. And actually the last expression of the select list is an expression without an alias. So try your statement using an alias for the last expression. So try
CREATE TABLE MENTIONS AS SELECT
UM.USER_ID AS U_ID,
UM.SCREEN_NAME AS USER_SCREEN_NAME,
UM.MENTION_ID AS M_USER_ID,
(
SELECT
UI.USER_SCREEN_NAME
FROM
USER_INFO UI
WHERE
UI.USER_ID = UM.MENTION_ID
AND ROWNUM = 1
) AS MENTIONED_USER
FROM
USER_MENTION UM
The column alias in the inner select list is useless and can be removed.
The problem with your query is that each column in the create table needs to have a name. You think you are assigning a name in the sub-select. However, you are not.
The subquery is just returning a value -- not a value with a name. So, the AS MENTIONED_USER in your version does nothing. This is a bit tricky, I guess. One way to think of the scalar subquery is that it is just another expression or function call. Things that happen inside it don't affect the outer query -- except for the value being returned.
The correct syntax is to put the column alias outside the subselect, not inside it:
CREATE TABLE MENTIONS AS
SELECT UM.USER_ID AS U_ID, UM.SCREEN_NAME AS USER_SCREEN_NAME, UM.MENTION_ID AS M_USER_ID,
(SELECT UI.USER_SCREEN_NAME
FROM USER_INFO UI
WHERE UI.USER_ID = UM.MENTION_ID AND ROWNUM = 1
) AS MENTIONED_USER
FROM USER_MENTION UM;