In SQL*Plus, I want to execute multiple SQL queries in single line like
create table emp(name varchar2(20)); desc emp;
I tried executing this one but didn't work for me.
BEGIN OPEN :1 FOR SELECT * FROM table1; OPEN :2 FOR SELECT * FROM table2; END;
is there any way to accomplish this?
Thanks in advance!
SQL*Plus expects either:
A single SQL command, terminated by either a ";" character or a "/" on a line by itself.
A PL/SQL block
A SQL*Plus command
What you have entered is 2 queries on a single line, which SQL*Plus will send to the RDBMS - Oracle will then try and parse the string sent as a single query and fail because it is not valid SQL.
A quick workaround would be to have all your commands in a sql file and run them using #file.sql
Related
I am able to get the result as CSV in Oracle by using this simple query with a hint.
SELECT /*csv*/ * FROM dual;
This returns
"DUMMY"
"X"
Now I would like to use exactly the same hint in PL/SQL in order not to reinvent the wheel.
SET SERVEROUTPUT ON;
declare
cur sys_refcursor;
csv_line varchar2(4000);
begin
open cur for select /*csv*/ * from dual;
loop
fetch cur into csv_line;
exit when cur%NOTFOUND;
dbms_output.put_line(csv_line);
end loop;
close cur;
end;
Unfortunately this prints only
X
which seems to ignore the hint.
Any way to do it that simple or do I have to write a special piece of code for exporting the data as CSV?
The /*csv*/ hint is specific to SQL Developer and it's sibling SQLCl; and is somewhat superseded by the set sqlformat csv option.
It is not a hint recognised by the optimiser; those are denoted by a plus sign, e.g. /*+ full(...) */ or less commonly --+ full(...).
If you're creating the output in PL/SQL you will need to construct the string yourself, adding the double quotes and delimiters. You can either have the cursor query do that so you can select into a single string even when you have multiple columns; or have a 'normal' query that selects into a record and have PL/SQL add the extra characters around each field as it's output.
It would be more normal to use utl_file than dbms_output as the client may not have that enabled anyway, but of course that writes to a directory on the server. If you're writing to a file on the client then PL/SQL may not be appropriate or necessary.
If you need to do some manipulation of the data in PL/SQL then one other option is to use a collection type and have an output/bind ref cursor, and then have SQL Developer print that as CSV. But you don't normally want to be too tied to a single client.
I'm Facing below error:
An unexpected token "(" was found following " CURSOR ". Expected tokens may include: "CURSOR". SQLSTATE=42601
And I'm just trying to create a simple cursor, actually the example one found here in IBM documentation.
Cursor declaration looks something like:
DECLARE
CURSOR c1 (max_wage NUMBER) IS
SELECT * FROM emp WHERE sal < max_wage;
Not sure if this is do to the version of DB2 being used or not. Can anyone suggest maybe an alternative to creating a parameterized cursor?
You are trying to use PL/SQL syntax in DB2. This requires changes to the server environment. If you want to support the Oracle datatypes as well, the database must be created with the right settings, too. See this article for more details. The summary of that article is:
Open a DB2 Command Window (in Administrator mode)
Run db2start
Run db2set DB2_COMPATIBILITY_VECTOR=ORA
Run db2set DB2_DEFERRED_PREPARE_SEMANTICS=YES
Run db2stop
Run db2start
Execute your PL/SQL statements, e.g. in a DB2 CLP (run db2 -tv) command window.
Note that you should run
SET SQLCOMPAT PLSQL; in your DB2 CLP before trying PL/SQL. This enables using a forward slash (/) as a PL/SQL statement terminator. You should then obviously also then actually terminate your command with a forward slash :)
Here's an example taken from your link, modified to work with the default SAMPLE database in DB2:
SET SQLCOMPAT PLSQL;
DECLARE
my_record emp%ROWTYPE;
CURSOR c1 (max_wage integer) IS
SELECT * FROM employee WHERE salary < max_wage;
BEGIN
OPEN c1(40000);
LOOP
FETCH c1 INTO my_record;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Name = ' || my_record.firstnme || ', salary = '
|| my_record.salary);
END LOOP;
CLOSE c1;
END;
/
If you don't want to do all the above, then use the standard DB2 cursor syntax:
DECLARE [cursor name] CURSOR FOR [...]
...but that doesn't support parameterized cursors. To do so, I'd recommend creating a stored procedure taking the parameter. This stored procedure can then create a cursor using that parameter directly in the SQL.
I saw some CREATE statements I never thought could be parsed by SQLPLUS:
plus#PDB1> #create
2 or
3 replace procedure p as
4 begin
5 null;
6 end;
7 /
Procedure created.
plus#PDB1> #create
2 table t3(x int);
Table created.
So how the pound signs (#) were parsed here ? I cannot find any documentation for this. If there is a documentation to it, point me there.
This is the SQLPREFIX character. The manual describes it:
While you are entering a SQL command or PL/SQL block, you can enter a SQL*Plus command on a separate line, prefixed by the SQL*Plus prefix character. SQL*Plus will execute the command immediately without affecting the SQL command or PL/SQL block that you are entering.
An example use case of running a SQL*PlusĀ® command inside a SQL command:
SQL> SELECT *
# show release
release 1102000200
FROM dual;
D
-
X
While you would usually use this to run something immediately inside a larger command, since you can use it anywhere, you can actually use it on its own too.
SQL> # SELECT * FROM dual;
D
-
X
I need to execute a command string with using GO command at the end like
exec('SELECT * FROM tblTmp where Id = 1 GO')
After executing I have
Incorrect syntax near 'GO'.
If I execute exec('SELECT * FROM tblTmp GO') everything is OK
What's the issue here?
Thank you.
GO is not an SQL command, it is a batch separator understood by clients like osql, sqlcmd, and SSMS but not the engine itself.
If you write something like this in SSMS:
SELECT 1
GO
SELECT 2
GO
, the engine sends two batches with one statement in each instead of one batch with two statements.
In your second query, GO is treated as an alias to the table tblTmp.
Just remove GO from your query.
You do not need to use GO for a single SQL statement. Only when you're batching several statements into a single script do you need to use a separator. Also, if you're executing these programmatically you should be using the semicolon (;) statement terminator instead of GO to separate your SQL statement.
Here's a handy SQL Server Central article on the usage of GO and the semicolon.
I'm trying to run multiple ddl statements within one Execute Immediate statement.
i thought this would be pretty straight forward but it seems i'm mistaken.
The idea is this:
declare v_cnt number;
begin
select count(*) into v_cnt from all_tables where table_name='TABLE1' and owner = 'AMS';
if v_cnt = 0 then
execute immediate 'CREATE TABLE TABLE1(VALUE VARCHAR2(50) NOT NULL) ALTER TABLE TABLE1 ADD (MYVAL2 NVARCHAR2(10))';
end if;
end;
however this results in an error
ORA-00911: invalid character
ORA-06512: at line 10
Each of the statements within the batch run fine if i execute them by themselves. and if i take this statement and execute it, it will run fine (with the ; between the 2 statements). If i remove the ; between statements i get a different error about invalid option
the plan is that i'll be able to build a table, export the table schema for this table including all it's alter statements, and then run the batch against another system as part of an install/update process.
So, how do i batch these DDL statements within a single execute immediate? Or is there a better way to do what i'm needing?
I'm a bit of a Oracle newb, i must admit. Thank you all for your patience.
The semicolon is not part of Oracle's SQL syntax. SQL*Plus and other client side tools use semicolon to signal the end of a SQL Statement, but the server doesn't see it.
We can force SQL*Plus to pass the semicolon to the DB:
SQL> set sqlterminator off
SQL> select * from user_tables;
2 /
select * from user_tables;
*
ERROR at line 1:
ORA-00911: invalid character
If i take this statement and execute it, it will run fine (with the ; between the 2 statements) The client tool you are using, breaks it into two calls to the DB.
So, I don't think it is possible to pass multiple statements inside an execute immediate.
I suppose one could call execute immediate with a string containing an anonymous PL/SQL block, with individual calls to execute immediate inside it ... and I don't know what the point of doing that would be. ;)
Why do you need a single EXECUTE IMMEDIATE call? Surely just do it as 2 calls?
Bear in mind that each DDL statement contains an implicit COMMIT, so there's no concurency benefit to doing it as a single call.
Also, why not just set up the table correctly in the first call? You could do...
CREATE TABLE TABLE1(VALUE VARCHAR2(50) NOT NULL, MYVAL2 NVARCHAR2(10))
...instead of needing 2 calls.
Also, have you looked at DBMS_METADATA... it can generate DDL for objects such as tables for you.