Sequence and Trigger, PL/SQL - sql

I'm using Oracle for the first time, much more used to sql server and their identitys. But now I'm trying to use a sequence and trigger. But keep getting this error I can't fix.
identifiers may not start with any ASCII character other than
letters and numbers. $#_ are also allowed after the first
character. Identifiers enclosed by doublequotes may contain
any character other than a doublequote. Alternative quotes
(q'#...#') cannot use spaces, tabs, or carriage returns as
delimiters. For all other contexts, consult the SQL Language
Reference Manual.
Can anyone help fix it, here is my code.
EXECUTE IMMEDIATE' CREATE SEQUENCE stagechardata_stagecharid
START WITH 1
INCREMENT BY 1;';
EXECUTE IMMEDIATE' CREATE OR REPLACE TRIGGER stagechardata_stagecharid_TRG
BEFORE INSERT
ON stage_char_data
FOR EACH ROW
BEGIN
IF NEW.stage_char_id IS NULL THEN
SELECT stagechardata_stagecharid.NEXTVAL INTO NEW.stage_char_id
FROM DUAL;
END IF;
END;';

Long shot, but looks like you're missing a space after IMMEDIATE and before the quote that starts the statement.

A sequence is an object which contains SQL satements, but doesn't store data.
Triggers are SQL blocks that execute when a manipulation occurs on a table.

First of all, there is no visible reason to use EXECUTE IMMEDIATE. Is there any invisible? It looks like you should just remove it and execute these statements directly in the SQL mode.
Next, it looks like you forgot to use colon: NEW.stage_char_id IS NULL should be :NEW.stage_char_id IS NULL and so on.

Related

What is the purpose of the #SET TERMINATOR statement

Specifically for SQL stored procedures. Am I supposed to include it at the beginning of every stored procedure such as
--#SET TERMINATOR #
CREATE PROCEDURE Name
LANGUAGE SQL
BEGIN
SELECT * FROM Table
END
#
It's not a statement, it's a directive to change the statement terminator.
You must use another statement terminator different from the default one (;), if a statement you want to run contains a compound statement (with BEGIN ... END) containing other "simple" statements delimited by ;. The statement delimiter inside a compound statement can't be changed, so you have to help the DB2 Command Line Processor to understand, where your whole "complex" statement ends.
BTW, your statement contains a number of mistakes. Each statement (including the last one) inside the BEGIN ... END block must be separated by ;, and you can't "SELECT to nowhere" in a routine.

Inserting the text of a stored procedure into a record

How can I insert into a record the text of a procedure stored in ALL_SOURCE.TEXT ?
This part of code gives me error: "missing comma"
execute immediate '
insert into results(SrcProcedure) values(' ''
|| tabela_temporare(1).text ||
'' ')';
I think this is due to the unescaped characters contained in the text of the stored procedure, but I can't find a way to fix it.
If you want to have the string delimiting character (apostrophe: ') inside a Varchar, you must use two consecutive apostrophes and then another one to end the string. It gives you an error because you ended the string first.
Try this piece of code:
EXECUTE IMMEDIATE 'INSERT INTO results(SrcProcedure) values(''' || tabela_temporare(1).text || ''')';
EDIT:
Better use Bind Variables, see my sample Code:
CREATE TABLE RESULTS (SRCPROCEDURE VARCHAR2 (300));
DECLARE
v_SQL VARCHAR2(4000) := 'INSERT INTO results(SrcProcedure) VALUES(:1)';
BEGIN
EXECUTE IMMEDIATE v_SQL USING 'something2';
END;
I hope it works now! :)
What about simply doing this in your PL/SQL:
INSERT INTO results(SrcProcedure) VALUES (tabela_temporare(1).text);
Internally it will use bind variables to pass your PL/SQL variable into the INSERT.
Note that it is highly advised to stay away from dynamic SQL (EXECUTE IMMEDIATE and the likes), because that code will be prone to SQL injection.
[UPDATE]
I don't know what more to tell. However consider these things for using a dynamically built SQL within a FOR loop using string search and replace:
It will be terribly slow, because for each loop iteration, you recompile the dynamic SQL.
The SQL itself will execute slower because it cannot be cached.
You have the danger of SQL injection that can lead to bugs and security issues. You think you fixed it by search and replace quotes, but I bet there might be scenario's you did not take into account.
The process itself of search and replace for quotes is also terribly slow.
There are good uses of dynamic SQL, but that is just not one of them, and it is also against all possible advice to 'concatenate' parameters vs 'binding' them.
If that text field contains actual stored pl/sql code, the only character likely to cause problems is the single quote.
So replace each instance with two single quotes which will then get parsed as a properly escaped single quote. Of course, you have to escape the quote in the replace statement to get it to work, but try this:
execute immediate '
insert into results(SrcProcedure) values(' ''
|| replace(tabela_temporare(1).text,'''','''''') ||
'' ')';

Compound Statement unable to change the delimiter

I am attempting to run a simple compound statement within the Query Editor of DB Solo 4.2.2
It appears I am unable to properly change the end of line delimiter. I am using DB2. Here is a simple example that gives the error:
--#SET TERMINATOR #
BEGIN ATOMIC
DECLARE id INT;
SET id = 10;
END #
--#SET TERMINATOR ;
Error is:
An unexpected token "INT" was found following "N ATOMIC DECLARE id". Expected tokens may include: "END-OF-STATEMENT"
Thanks in advance
DB2 only allows the semicolon to be used as a delimiter in Compound SQL. The syntax you are using appears to only be valid when using the db2batch utility (which comes with DB2 Linux/Unix/Windows).
Here is some relevant information from the Information Center (this is from the z/OS IC):
How to code multiple statements in an SQL procedure
Use a semicolon
character to separate SQL statements within an SQL procedure.
The procedure body has no terminating character. Therefore, if the
procedure contains only one statement, you do not need to put a
semicolon after that statement. If the procedure consists of a set of
nested statements, you do not need to put a semicolon after the
outermost statement.

In SQL Server, when should you use GO and when should you use semi-colon ;?

I’ve always been confused with when I should use the GO keyword after commands and whether a semi-colon is required at the end of commands. What is the differences and why/when I should use them?
When I run the Generate-script in SQL Server Management Studio, it seems to use GO all over the place, but not the semi-colon.
GO only relates to SSMS - it isn't actual Transact SQL, it just tells SSMS to send the SQL statements between each GO in individual batches sequentially.
The ; is a SQL statement delimiter, but for the most part the engine can interpret where your statements are broken up.
The main exception, and place where the ; is used most often is before a Common Table Expression Statement.
The reason why you see so many GO's in Generated DDL scripts is because of the following rule about batches.
CREATE DEFAULT, CREATE FUNCTION,
CREATE PROCEDURE, CREATE RULE, CREATE
TRIGGER, and CREATE VIEW statements
cannot be combined with other
statements in a batch. The CREATE
statement must begin the batch. All
other statements that follow in that
batch will be interpreted as part of
the definition of the first CREATE
statement.
One of the use cases for Generated DDL is to generate multiple objects in a single file. Because of this a DDL generator must be able to generate batches. As others have said the GO statement ends the batch.
GO
Go is a batch separator. This means that everything in that batch is local to that particular batch.
Any declarations of Variables, Table Variables, etc do not go across GO statements.
#Temp tables are local to a connection, so they span across GO statements.
Semicolon
A Semicolon is a statement terminator. This is purely used to identify that a particular statement has ended.
In most cases, the statement syntax itself is enough to determine the end of a statement.
CTE's however, demand that the WITH is the first statement so you need a semicolon before the WITH.
You should use a semi-colon to terminate every SQL statement. This is defined in the SQL Standards,
Sure, more often than not SQL Server allows you to omit the statement terminator but why get into bad habits?
As others have pointed out, the statement preceding a common table expression (CTE) must be terminated with a semi-colon. As a consequence, from folk who have not fully embraced the semi-colon terminator, we see this:
;WITH ...
which I think looks really odd. I suppose it makes sense in an online forum when you can't tell the quality of code it will be pasted into.
Additionally, a MERGE statement must be terminated by a semi-colon. Do you see a pattern here? These are a couple of the newer additions to TSQL which closely follow SQL Standards. Looks like the SQL Server team are going down the road of mandating the use of the semi-colon terminator.
GO is a batch terminator, a semi-colon is a statement terminator.
you will use GO when you want to have multiple create proc statements in 1 script because create proc has to be the first statement in a batch. If you use common table expressions then the statement before it needs to be terminated with a semi-colon

What does DELIMITER // do in a Trigger?

DELIMITER //
What is the of use of it?
It changes the statement delimiter from ; to //. This is so you can write ; in your trigger definition without the MySQL client misinterpreting that as meaning you're done with it.
Note that when changing back, it's DELIMITER ;, not DELIMITER; as I've seen people try to do.
In SQL you close each statement with a delimiter, which is by default a semicolon (;). In a trigger you need to write multiple statements, each ending in a semicolon. To tell MySQL that those semicolons are not the end of your trigger statement, you temporarily change the delimiter from ; to //, so MySQL will know that the trigger statement only ends when it econunters a //.
Add an example:
When working with mysql shell command, we used ; delimiter to close each statement. However, in case, we want to build the store procedures and triggers, we need to add the semicolon ; in these statements also.
delimiter //
create trigger log_students after insert on students
for each row
begin
insert into log_students(change_by, change_at) values(USER(), NOW());
end//
delimiter ;
Simple sets the end of statement delimiter (; semi-colon in standard, default SQL).
Changing the character could be useful if you want to use ; in your SQL, or you are using embedded SQL (where it might lead to confusion). similarly the // in your example could lead to confusion in embedded SQL, or you might want to use it in your SQL. So imply use DELIMITER to set the delimiter that is appropriate for your application and needs.
Read the (ummmm) mysql documentation.
delimiter is the marker for the end of each command you send to the mysql command line client.
delimiter is not only related to triggers, but defining triggers and stored procedures is one strong use case as you wish them to contain semicolons (;) which are otherwise the default delimiter.