Running Pro*C on Oracle 10g.
I am looking to do a subquery within an insert statement values clause. This sql query is fully valid and runs within TOAD with no problems, but Pro*C fails to parse the query.
EXEC SQL INSERT INTO TARGET_ATTACHMENT
(
TARGET_ID
FILENAME
)
VALUES (
:targetID,
( SELECT CREATED_FLAG from TARGET t where t.TARGET_ID = :targetID ) || '.tif'
)
If I remove:
( SELECT (CREATED_FLAG || DISPLAY_ID) from TARGET t where t.TARGET_ID = :targetID ) ||**".
The Pro*C compiler works and everything compiles and runs as expected.
If I DO NOT remove:
The Pro*C compiler throws a syntax error.
1>Syntax error at line 128, column 12, file d:\SVN\...\TA.pc:
1>Error at line 128, column 12 in file d:\SVN\...
1>...\TA.pc
1> ( select CREATED_FLAG from target t where t.TARGET_ID = :targetID )
1>...........1
1>PCC-S-02201, Encountered the symbol "CREATED_FLAG" when expecting one of the fol
1>lowing:
1> ( ) * + - / . # | at, day, hour, minute, month, second, year,
This is a problem, as I expect Pro*C to be able to compile subquerys within a values caluse:
ie.
INSERT into table1 (col1) values ( (select t2.singleCol from table2 t2 where t2.priKey = :priKey) )
Is this expected behaviour of Pro*C? or Should it support subqueries within the values clause?
Possibly change the subquery to:
( SELECT CREATED_FLAG || '.tif' from TARGET t where t.TARGET_ID = :targetID )
I dont think I have ever seen something appended to a subquery the way you were attempting.
The amount of SQL the Pro*C preprocessor is able to parse in static SQL statements is quite limited. For example it can't even parse explicit inner joiner/outer left join etc. notation.
As a workaround you can just prepare a dynamic SQL statement and execute it - even if your SQL statement is not really dynamic.
The code you have posted is logically identical to this:
INSERT INTO TARGET_ATTACHMENT
( TARGET_ID , FILENAME )
select :targetID, CREATED_FLAG|| '.tif'
from TARGET t
where t.TARGET_ID = :targetID )
Is there a particular reason why you need to use scalar cursors in a VALUES clause?
Related
WITH LAYER AS (
SELECT
SPLIT(de_nest, '|')[OFFSET(1)] AS product,
....
FROM `table`,
UNNEST(SPLIT(LOWER(REPLACE(variable, '^', '-')), '-')) AS de_nest
)
-- Filter out empty products
CREATE OR REPLACE TABLE `newtable` AS
SELECT * FROM LAYER WHERE product is NOT NULL
This leads me to the following error.
Syntax error: Expected "(" or "," or keyword SELECT but got keyword CREATE at [25:1]
But I cannot seem to find a sensible way of resolving this. My first workload is doing the un-nesting of the first table and the second is doing some filtering on those columns generated from the un-nesting process.
You should try to put the CTE declaration after the CREATE statement:
CREATE OR REPLACE TABLE `new_table` AS
WITH layer AS ...
EDIT: a complete example
CREATE OR REPLACE TABLE
`your_project.your_dataset.your_table` AS
WITH
layer1 AS (
SELECT
'this is my CTE' AS txt),
another_cte AS (
SELECT
txt,
SPLIT(txt, ' ') AS my_array
FROM
layer1)
SELECT
*
FROM
another_cte
Creates the following table
I have a small sample query that creates a temp table with a WITH command, and then runs a SELECT.
I want to INSERT INTO another table the result of my SELECT statement, but I am getting an error
WITH testingINSERT AS
(
SELECT *
FROM Dashboard.test1
)
INSERT INTO Dashboard.test2 (number)
SELECT *
FROM Dashboard.test1
The WITH statement in this case isn't really doing anything. However, I am trying to solve for the issue.
If I remove the INSERT line, the query runs fine
ERROR: Syntax error: Expected "(" or keyword SELECT but got keyword INSERT at [6:1]
Tried to be more explicit as well, and see the same error.
WITH testingINSERT AS
(
SELECT *
FROM Dashboard.test1
)
INSERT INTO Dashboard.test2 (number)
SELECT number
FROM Dashboard.test1
Tried this as well:
WITH testingINSERT AS
(
SELECT number
FROM Dashboard.test1
)
INSERT INTO Dashboard.test2 (number)
SELECT number
FROM testingINSERT
If I removve that line INSERT INTO, everything works fine, however, I am trying to put the returned values into another table.
INSERT INTO Dashboard.test2 (number)
WITH testingINSERT AS
(
SELECT number
FROM Dashboard.test1
)
SELECT number
FROM testingINSERT
I have been mulling over a problem for the last few hours with a query which executes a decode statement as part of my WHERE CLAUSE.
The best Example I can come up with here is as follows:
--This variable is normally populated by a query.
--Debugger confirms this is set to 'US' with no leading or tailing characters
Str_MyVar varchar2(10) := 'US';
-- Query 1 returns 16 rows (incorrect)
Select *
From myTable, table2
Where myTable.value = decode(Str_MyVar, 'US', table2.value, 0)
-- Query 2 returns 1 rows (correct)
Select *
From myTable, table2
Where myTable.value = decode('US', 'US', table2.value, 0)
Now then, if I change the query which populates the Str_MyVar variable to instead convert the value 'US' to a 1 and all other values to a 0 and store it in a numeric variable things begin to work.
--This variable is normally populated by a query.
--Debugger confirms this is set to 1 with no leading or tailing characters
nbr_Myvar number := 1;
-- Query 1 returns 1 rows (correct)
Select *
From myTable, table2
Where myTable.value = decode(nbr_MyVar, 1, table2.value, 0);
This second example using a numeric data type for the variable in the decode works properly. The question is Why? Sure I've coded around the issue but I'd like to understand if this is an oracle bug or just a quirk of the DECODE function. Database is oracle 10.2.0.3
I am currently writing a SQL query which first creates a lot of temporary tables using the WITH operator along with SELECT statements and then joins all of the temporary statements at the end.
All of my SELECT statements that create temporary tables depend on certain filters... so my query looks something liek
WITH
table_1 as (
SELECT product_id
avg(price)
FROM daily_sales
WHERE product_category = 1
AND sell_date BETWEEN TO_DATE('2012/01/07','YYYY/DD/MM') AND TO_DATE('2012/30/09','YYYY/DD/MM')
GROUP BY ds.product_id
),
table_2 as (....
),
SELECT FROM table_1 JOIN table_2....
I would like to run this query for ranges of 'sell_date' (a date, or a string) and different values of 'product_category' (an integer value).
Currently, I am replacing these manually but I am wondering if I can just declare replace these hard-coded values with variables, which I set at the top of my query.
I understand that this might have been asked before - but I am confused since there are multiple solutions that depend on the exact version of SQL that you are using and the types of variables that you are declaring.
In this case, I am looking for a solution that works in Oracle SQL, and where I can specify the type variable.
It depends how you're running your query.
If you're using an interactive client like SQL*Plus or TOAD you should use substitution variables:
WITH
table_1 as (
SELECT product_id
avg(price)
FROM daily_sales
WHERE product_category = &product_cat
AND sell_date BETWEEN TO_DATE('&start_date','YYYY/DD/MM') AND TO_DATE('&end_date','YYYY/DD/MM')
GROUP BY ds.product_id
),
You will be prompted to supply values for these variables each time you run the query. If you want to use the same values in multiple places then declare all the occurrences of a variable with a double ampersand - &&product_category - and then you only be prompted for it once. The SQL*Plus documentation has additional information: find out more.
If you're going to run the queries in a stored procedure then define the values as parameters ...
procedure process_sales_details
( i_product_category in number
, i_start_date in date
, i_end_date in date )
... which you reference in your query (wherever you declare it) ...
WITH
table_1 as (
SELECT product_id
avg(price)
FROM daily_sales
WHERE product_category = i_product_cat
AND sell_date BETWEEN i_start_date AND i_end_date
GROUP BY ds.product_id
),
Further to APC's answer, in SQL*Plus or SQL Developer you can also declare variables that you can assign values to in an anonymous PL/SQL block and then reference as bind variables in your plain SQL query:
variable v_product_cat number;
variable v_start_date varchar2(10);
variable v_end_date varchar2(10);
begin
:v_product_cat := 1;
:v_start_date := '2012/01/07';
:v_end_date := '2012/30/09';
end;
/
WITH table_1 as (
SELECT product_id
avg(price)
from daily_sales
where product_category = :v_product_cat
AND sell_date BETWEEN TO_DATE(:v_start_date,'YYYY/DD/MM')
AND TO_DATE(:v_end_date,'YYYY/DD/MM')
group by ds.product_id
)
...
Note the : before the variable name denoting a bind variable, and that the strings are not enclosed in quotes with this form. Unfortunately you can't declare a date variable, which would make this even neater.
And if you use substitution variables you can define them at the start so you aren't prompted; in this case you don't need to use the && notation either:
define v_product_cat=1
define v_start_date=2012/01/07
define v_end_date=2012/30/09
...
where product_category = &v_product_cat
and sell_date between to_date('&v_start_date','YYYY/DD/MM')
AND TO_DATE('&v_end_date','YYYY/DD/MM')
...
... which is covered in the documentation APC linked to.
You can add one or more common table expressions to encapsulate these:
with
cte_sell_dates as (
select date '2012-07-01' from_date,
date '2012-09-30' to_date
from dual),
cte_products as (
select 1 id from dual union all
select 28 id from dual),
... as (
select ...
from ...
where sell_date between (select from_date from cte_sell_dates) and
(select to_date from cte_sell_dates) and
product_id in (select id from cte_products )
...
... or use joins directly, instead of subqueries, of course.
Go for an Anonymous PL/sql Block and use a for loop where you can loop through all the different values.
Following is the Structure of pl/sql block:
DECLARE
<constant name> CONSTANT <data type> := <value>;
<constant name> CONSTANT <data type> DEFAULT <value>;
BEGIN
<valid statement>;
EXCEPTION
<exception handler>;
END;
Also you can go for a parametrized cursor where you can pass your values.
I have simple query, but when I'm trying to execute this query I'm getting error:
Query input must contain at least one table or query. (Error 3067)
Query:
INSERT INTO FV_Ko ( FvId, OldPriceNetto )
SELECT [PFvId], (SELECT FV.PriceNetto1 FROM FV WHERE FV.FVnr = '123');
This should work - it should ask you for [PFvId]
INSERT INTO FV_Ko ( FvId, OldPriceNetto )
SELECT [PFvId], FV.PriceNetto1 FROM FV WHERE FV.FVnr = '123';
If PFvld is a parameter and the query (MyQuery) is saved (part of the MSAccess database), then you should be able to do:
Dim qdf As DAO.QueryDef
Set qdf = db.QueryDefs("MyQuery")
qdf.Parameters("[PFvld]") = myValue
If you compose the query on the fly and execute it, then you might just specify a value when composing the SQL code instead of a parameter (not that it is a better solution though).
The subquery is OK, but you aren't saying where PFvID is coming from. Your INSERT should be something like this:
INSERT INTO FV_Ko ( FvId, OldPriceNetto )
SELECT AnotherTable.PFvId,
(SELECT FV.PriceNetto1 FROM FV WHERE FV.FVnr = '123') FROM AnotherTable
...
SELECT [PFvId], --> you should define a FROM table at end of the query
(SELECT FV.PriceNetto1 FROM FV WHERE FV.FVnr = '123');