ORACLE: Cannot bind parameter to create table AS subquery - oracle

CREATE PRIVATE TEMPORARY TABLE ORA$PTT_collection_ids
ON COMMIT PRESERVE DEFINITION AS (
SELECT
DISTINCT cms3_dc_language.collection_id AS "collection_id"
FROM
cms3_dc_language
WHERE
cms3_dc_language.language = :language)
$sth->bindParam(":language", $language);
Gives an error when trying to bind :language...
OCIBindByName: ORA-01036: illegal variable name/number
The bind works if the bound parameter is not part of the create table AS subquery e.g.
SELECT
DISTINCT cms3_dc_language.collection_id AS "collection_id"
FROM
cms3_dc_language
WHERE
cms3_dc_language.language = :language
$sth->bindParam(":language", $language);

If you do the same thing using execute immediate you can see the real issue:
ORA-01027: bind variables not allowed for data definition operations
Although a bind variable is allowed as part of a query (obviously), here the query is a secondary factor, and it's the DDL that is the problem. You'd get the same error with a normal, non-temporary, table or a view, for instance.

Related

Creating a Snowflake View with a Sequence

Is it possible to use a Sequence inside a View?? I am using the following query:
CREATE VIEW < VIEW_NAME > (ID, VALUE1, VALUE2,...) AS
SELECT
SEQ1.NEXTVAL,
VAL1,
VAL2,
...
FROM
< TABLE >
But it is giving me the following error:
invalid identifier 'SEQ1.NEXTVAL'
The query works when not creating the view:
use the full qualified name for the SEQ object, because if I am in a different DB/Schema, that is the scope used to look for SEQ
basically everything in a view should be fully qualified, tables, views, functions, sequences.
CREATE DATABASE test;
create SCHEMA test.test;
use SCHEMA test.test;
create SEQUENCE seq1;
create view test_v as SELECT seq1.nextval;
select * from test.test.test_v;
gives:
NEXTVAL
2
create SCHEMA test.not_test;
use SCHEMA test.not_test;
select * from test.test.test_v;
and now you get:
SQL compilation error: error line 1 at position 29 invalid identifier 'SEQ1.NEXTVAL'
Here SEQ1 is not defined, that is the reason why you see the error. Documentation for Sequences is here:
https://docs.snowflake.com/en/sql-reference/sql/create-sequence.html
Is the Sequence existing? Looks like you accidentally missed to create it.

Create Type based on an exiting Table

As the title said : I want to create a type in oracle based on an existing Table.
I did as follow :
create or replace type MY_NEW_TYPE as object( one_row EXISTING_TABLE%rowtype);
The Aim is to be able to use this into a function which will return a table containing sample row of the table EXISTING_TABLE :
create or replace function OUTPUT_FCT() return MY_NEW_TYPE AS
...
If you only need to create a function that returns a row from your table, you could try something like the following, without creating types.
setup:
create table EXISTING_TABLE( a number, b varchar2(100));
insert into EXISTING_TABLE values (1, 'one');
function:
create or replace function OUTPUT_FCT return EXISTING_TABLE%rowtype AS
retVal EXISTING_TABLE%rowType;
begin
select *
into retVal
from EXISTING_TABLE
where rownum = 1;
--
return retVal;
end;
function call
SQL> begin
2 dbms_output.put_line(OUTPUT_FCT().a);
3 dbms_output.put_line(OUTPUT_FCT().b);
4 end;
5 /
1
one
However, I would not recommend such an approach, because things like select * can be really dangerous; I would much prefer defining a type with the fields I need, and then explicitly query my table for the needed columns.
No, you can't do that, you'll get a compilation error:
create or replace type my_new_type as object(one_row t42%rowtype);
/
Type MY_NEW_TYPE compiled
Errors: check compiler log
show errors
Errors for TYPE STACKOVERFLOW.MY_NEW_TYPE:
LINE/COL ERROR
-------- -----------------------------------------------------------------------
0/0 PL/SQL: Compilation unit analysis terminated
1/36 PLS-00329: schema-level type has illegal reference to MYSCHEMA.T42
You will need to specify each field in the object type, and you will have to specify the data types manually too - you can't use table.column%type either.
You could create the type dynamically based on column and data type information from the data dictionary, but as this will (hopefully) be a one-off task and not something you'd do at runtime, that doesn't really seem worth it.
You can create a PL/SQL table type based on your table's rowtype, but you would only be able to call a function returning that from PL/SQL, not from plain SQL - so you couldn't use it in a table collection expression for example. If you were only returning a single sample row you could return a record rather than a table, but the same applies. You can also have a function that returns a ref cursor which could match the table's structure, but you wouldn't be able to treat that as a table either.
Read more about object type creation in the documentation. Specifically the attribute and datatype sections.

Oracle - PLS-00642: local collection types not allowed in SQL statements

I am new to programming in ORACLE and I am trying to compare a table column value to a passed in array and I am having a rather frustrating time in doing so.
Here is the Type Declaration from the package head.
TYPE T_STRING_ARRAY IS TABLE OF VARCHAR2(5);
and here is the the function that is using it.
create or replace PACKAGE BODY TEST_PACK IS
FUNCTION TEST_LOG_FN
(
PI_START_DATE IN VARCHAR2,
PI_END_DATE IN VARCHAR2,
PI_LOG_TYPE IN T_STRING_ARRAY
)
RETURN T_REF_CURSOR
AS
PO_RESULT T_REF_CURSOR;
BEGIN
OPEN PO_RESULT FOR
SELECT
EL.ENTRY_BASE_LOG_ID,
EL.APP_NAME,
EL.APP_MODULE,
EL.CREATION_DATE,
EL.APP_STATUS,
EL.LOG_TYPE
FROM
LG_ENTRY_BASE_LOG EL
WHERE
CREATION_DATE > PI_START_DATE AND
CREATION_DATE < PI_END_DATE AND
(EL.LOG_TYPE IN PI_LOG_TYPE OR PI_LOG_TYPE = NULL);
RETURN
PO_RESULT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN NULL;
END TEST_LOG_FN;
END;
The error I am getting is PLS-00642: local collection types not allowed in SQL statements. I have read online
"To avoid the PLS-00642, the collection will need to be defined at the schema level; therefore, you would need to define the varray table as a real table, using Oracle DDL with the CREATE TYPE syntax. "
http://www.dba-oracle.com/t_pls_00642_local_collection_types_not_allowed_in_sql_statement.htm
I am not sure how to do that nor have I found any references online that I could use. Can someone help me with that? If someone knows an easier way to see if a string exists in an array, that is a perfectly acceptable answer as well.
You can use types defined in the package spec in Oracle 12C or later.
This line:
(EL.LOG_TYPE IN PI_LOG_TYPE OR PI_LOG_TYPE = NULL)
Needs to be:
(EL.LOG_TYPE IN (select column_value from table(PI_LOG_TYPE))
OR (select count(*) from table(PI_LOG_TYPE)) = 0)
Prior to 12C you need to define the type in the database using CREATE TYPE. The syntax for the select is the same either way.
Rather than using IN you can use the MEMBER OF operator designed specifically for use with collections:
(PI_LOG_TYPE = NULL OR EL.LOG_TYPE MEMBER OF PI_LOG_TYPE);
As noted by #TonyAndrews If you are using Oracle 12c then you can use collections defined in a package in PL/SQL but in earlier versions you will need to define them in SQL using the CREATE TYPE statement.

ORA-22905 on setting Count(*) into out param

I've created a sample oracle function to returns the number of records in a table. Here is it
create or replace FUNCTION TEST_COUNT
RETURN NUMBER AS recCount NUMBER;
BEGIN
SELECT COUNT(*) INTO recCount FROM **tableName**;
return recCount;
END TEST_COUNT;
Its' being compiled successfully, but when I called this function in Oracle SQL-Developr using command
SELECT * FROM TABLE (TEST_COUNT());
it threw me the following error.
ORA-22905: cannot access rows from a non-nested table item
22905. 00000 - "cannot access rows from a non-nested table item"
*Cause: attempt to access rows of an item whose type is not known at
parse time or that is not of a nested table type
*Action: use CAST to cast the item to a nested table type
Error at Line: 1 Column: 22
I've followed Oracle error ORA-22905: cannot access rows from a non-nested table item but can't reach the solution. Please suggest what should I do?
Well, you're just calling it wrong. The TABLE() table collection expression is used when the function returns a collection (e.g. from create type x as table of number) that you want to treat as a table so you can join against it, which isn't the case here; you're returning a simple NUMBER.
So just do:
SELECT TEST_COUNT FROM DUAL;

Oracle PL/SQL - Bulk Collection usage into WHERE and FROM clause inside conditions and inner views

I have a strange problem using bulk collection as element of FROM clause.
When I execute this code example, I get, just at run-time, the error "invalid table name".
If I replace the collection with a table everything works well.
Is there any restriction about bulk collection that I'm missing?
Maybe I cannot use anonymous block in FROM clause?
In the sql debugger I see that l_vol(i) has values but l_vol(i).FIELD doesn't exists.
Thanks.
TYPE t_bulk_vol is table of vol%ROWTYPE;
l_vol t_bulk_vol;
...
cursor cur is SELECT * FROM vol where ... ;
OPEN CUR;
LOOP
FETCH CUR BULK COLLECT INTO l_vol;
....
insert into dest
select col1, col2, ... from
(inner view with some pivot, unpivot and l_vol(i).FIELD ...) src where l_vol(i).FIELD = src.FIELD;
PS: I cannot paste original code.
TYPE t_bulk_vol is a PL/SQL type. That means you can only use it in PL/SQL constructs. You cannot use it in SQL, even if it's SQL in a PL/SQL program.
If you want to use a nested table in the FROM clause of a SELECT you will need to define a SQL TYPE. This is a pain, because it means you can't use the %ROWTYPE definition (that's a PL/SQL only keyword). So you'll have to create an object whose signature matches the projection of the table, and then create nested table of that type. Find out more.
Your cursor is defined wrongly. It should just be a SELECT statement.
cursor cur is SELECT * FROM vol where ... ;
Save the BULK COLLECT INTO l_vol for the actual fetch.
Although presumably this is just a artefact of you faking some PL/SQL because you "cannot paste original code."
I have created the type as you said, but I get the same error at the same point (ORA-00903 - invalid table name).
This is an example of what I've done:
CREATE TYPE REC_VOL AS OBJECT (
FIELD1 VARCHAR2(25),
...
);
create TYPE T_BULK IS TABLE OF REC_VOL;
....
l_vol t_bulk;
...
This is the way I collect the records (I don't use the cursor anymore):
SELECT REC_VOL(FIELD1, ...) BULK COLLECT INTO l_vol
FROM vol where ...;
The exception is still raised at the insert-select statement.

Resources