Is the semicolon necessary in SQL? - sql

Sometimes it works anyway if I forget the ;. But sometimes it doesn't.
And in JDBC and Android SQLite, it seems that I don't need ; at all. I am confused.
When should I use a semicolon?

semicolon indicates end of a statement, so if there are multiple statements then you should use semicolon else it will work fine.
I generally use semicolon as a practice, it can be useful even when you are running queries on sql client e.g. in Sql Developer using semicolon is very helpful if you have multiple statements on worksheet, as you can simply go to that particular statement and use F9 to execute that, without semicolon this is not possible.

It is not mandatory if you run a single query at time, it comes necessary instead if you want to run multiple query with a single command.
However in most of JDBC drivers out there it is not possible to add multiple query separated with semicolon in a single JDBC Command, it exist however the addBatch method that allow you to add multiple statements :
java.sql.Statement stmt=con.createStatement();
stmt.addBatch(insert_query1); //insert_query1
stmt.addBatch(insert_query2); //insert_query2
As a rule of thumb, in JDBC semicolon is not necessary at all, if you need multiple statement use addBatch.

Usually the semicolon is not part of the actual syntax of a statement (as most database internal APIs execute a single statement at a time). Instead the semicolon is an 'end-of-statement' marker or statement separator that is - usually - defined in CLI or scripting tools for the database. This allows that tool to know when a statement ends, so it can send that single statement to the database for execution.
On the other hand, the JDBC API is intended to execute a single(!) statement at a time, therefore you don't need such a separator (the statement is the whole string). This means that a semicolon is not needed, and as it is not part of the actual statement syntax for a lot of database it is also a syntax error to include it. Some JDBC drivers will strip the last ; from a statement to 'fix' that, some drivers don't.
Some drivers allow - contrary to the JDBC specification - multiple statements to be executed as a single string, this usually has to be enabled with a connection property, for example for MySQL it is the option allowMultiQueries (see the MySQL properties for details).

Depends on the DBMS and version number. Semicolons are often optional at the end of a single statement. But if you are going to execute a script with more than one statement, they need to be terminated by a semicolon.
Except maybe the last one. But it seems bad form to be inconsistent.

Related

next:jdbc How to allow multiple statements for SQL Server

I want to run multiple statements on a single execution against SQL Server. I do it with Node.js but I cannot run the same query using next.jdbc
For example, if I run this:
(def db {:jdbcUrl "jdbc:jtds:sqlserver://localhost:1433/TESTDB;user=sa;password=passwd"})
(def ds (jdbc/get-datasource db))
(jdbc/execute! ds ["select * from EMPLOYEE;select FIRST_NAME from EMPLOYEE;"])
I have also tried to wrap the statement within a transaction with the same result
(jdbc/execute! ds ["BEGIN TRANSACTION select * from EMPLOYEE;select FIRST_NAME from EMPLOYEE; COMMIT"])
I always get the first query.
I have tried Microsoft's JDBC driver also.
Sean Corfield says that if the database supports it, then next.jdbc should support it. next-jdbc: execute multiple statements?
But I cannot make it work
Solution
As indicated by Sean Corfield
(jdbc/execute! ds ["BEGIN select * from EMPLOYEE;select FIRST_NAME from EMPLOYEE; END"] {:multi-rs true})
Yes, you can run multiple statements and multiple result sets back but you have to tell next.jdbc that's the behavior you want.
Take a look at the tests for MS SQL Server running multiple statements: https://github.com/seancorfield/next-jdbc/blob/develop/test/next/jdbc_test.clj#L560-L572
This is mentioned (briefly) in the Getting Started guide: "If you pass the :multi-rs true option to execute!, you will get back a vector of results sets, instead of just one result set: a vector of zero or more vectors."
As far as I know, SQL Server's JDBC driver does not support multiple statements. But, even if it did, you should probably not be using it, as it opens a potential security hole for injection type attacks. Instead, if you really need to execute multiple SQL statements, either refactor your current SQL into a single statement, or else use multiple statements wrapped in a single transaction.
For reference, some other JDBC drivers, such as MySQL, might support multiple statements.

perl execute sql file (DBI oracle)

I have the following problem, i have a SQL file to execute with DBI CPAN module Perl
I saw two solution on this website to solve my problem.
Read SQL file line by line
Read SQL file in one instruction
So, which one is better, and what the real difference between each solution ?
EDIT
It's for a library. I need to retrieve output and the return code.
Kind of files passed might be as following:
set serveroutput on;
set pagesize 20000;
spool "&1."
DECLARE
-- Récupération des arguments
-- &2: FLX_REF, &3: SVR_ID, &4: ACQ_STT, &5: ACQ_LOG, &6: FLX_COD_DOC, &7: ACQ_NEL, &8: ACQ_TYP
VAR_FLX_REF VARCHAR2(100):=&2;
VAR_SVR_ID NUMBER(10):=&3;
VAR_ACQ_STT NUMBER(4):=&4;
VAR_ACQ_LOG VARCHAR2(255):=&5;
VAR_FLX_COD_DOC VARCHAR2(30):=&6;
VAR_ACQ_NEL NUMBER(10):=&7;
VAR_ACQ_TYP NUMBER:=&8;
BEGIN
INSERT INTO ACQUISITION_CFT
(ACQ_ID, FLX_REF, SVR_ID, ACQ_DATE, ACQ_STT, ACQ_LOG, FLX_COD_DOC, ACQ_NEL, ACQ_TYP)
VALUES
(TRACKING.SEQ_ACQUISITION_CFT.NEXTVAL, ''VAR_FLX_REF'',
''VAR_SVR_ID'', sysdate, VAR_ACQ_STT, ''VAR_ACQ_LOG'',
''VAR_FLX_COD_DOC'', VAR_ACQ_NEL, VAR_ACQ_TYP);
END;
/
exit;
I have another question to ask, again with DBI Oracle module.
May i use the same code for SQL file and for Control file ?
(Example of SQL Control file)
LOAD DATA
APPEND INTO TABLE DOSSIER
FIELDS TERMINATED BY ';'
(
DSR_IDT,
DSR_CNL,
DSR_PRQ,
DSR_CEN,
DSR_FEN,
DSR_AN1,
DSR_AN2,
DSR_AN3,
DSR_AN4,
DSR_AN5,
DSR_AN6,
DSR_PI1,
DSR_PI2,
DSR_PI3,
DSR_PI4,
DSR_NP1,
DSR_NP2,
DSR_NP3,
DSR_NP4,
DSR_NFL,
DSR_NPG,
DSR_LTP,
DSR_FLF,
DSR_CLR,
DSR_MIM,
DSR_TIM,
DSR_NDC,
DSR_EMS NULLIF DSR_EMS=BLANKS "sysdate",
JOB_IDT,
DSR_STT,
DSR_DAQ "CASE WHEN :DSR_DAQ IS NOT NULL THEN SYSDATE ELSE NULL END"
)
Reading a table one row at a time is more complex, but it can use less memory - provided you structure your code to make use of the data per item and not need it all later.
Often you want to process each item separately (e.g. to do work on the data), in which case you might as well use the read line-by-line approach to define your loop.
I tend to use single-instruction approach by default, but as soon as I am concerned about number of records (especially in long-running batch processes), or need to loop through the data as the first task, then I read records one-by-one.
In fact, the two answers you reference propose the same solution, to read and execute line-by-line (but the first is clearer on the point). The second question has an optional answer, where the file contains a single statement.
If you don't execute the SQL line-by-line, it's very difficult to trap any errors.
"Line by line" only makes sense if each SQL statement is on a single line. You probably mean statement by statement.
Beyond that, it depends on what your SQL file looks like and what you want to do.
How complex is your SQL file? Could it contain things like this?
select foo from table where column1 = 'bar;'; --Get foo; it will be used later.
The simple way to read an SQL file statement by statement is to split by semicolons (or whatever the statement delimiter is). But this method will fail if you might have semicolons in other places, like comments or strings. If you split this statement by semicolons, you would try to execute the following four "commands":
select foo from table where column1 = 'bar;
';
--Get foo;
it will be used later.
Obviously, none of these are valid. Handling statements like this correctly is no simple matter. You have to completely parse SQL to figure out what the statements are. Unfortunately, there is no ready-made module that can do this for you (SQL::Script is a good start on an SQL file processing module, but according to the documentation it just splits on semicolons at this point).
If your SQL file is simple, not containing any statement delimiters within statements or comments; or if it is predictable in some other way (such as having one statement per line), then it is easy to split the file into statements and execute them one by one. But if you have to handle arbitrary SQL syntax, including cases such as above, this will be a complex task.
What kind of task?
Do you need to retrieve the output?
Is it important to detect errors in any individual statement, or is it just a batch job that you can run and not worry about it?
If this is something that you can just run and forget about, you could just have Perl execute a system command, telling Oracle to process the file. This will be simpler than handling all of the statements yourself. But if you need to process the results or handle errors within Perl, doing it yourself statement by statement will be a necessity.
Update: based on your response, you want to write a library that can handle arbitrary SQL statements. In that case, you definitely need to parse the SQL and execute the statements one at a time. This is do-able, but not simple. The possibility of BEGIN...END blocks means that you have to be able to correctly handle semicolons within a statement.
The SQL::Statement class of modules may be helpful.

Preventing sql injection - why should one escape the input if using prepared statements?

I am doing some research in web security, and the reviser of my article said:
"It should be clear that to avoid SQL Injection, the application should use prepared statements, stored procedures and escape input"
My question is: Is one of these methods isn't enough? Ok, prepared statements or stored procedures are better than a simple escape, but if I use PDO, why i should escape the input or have a stored procedure? Does this make sense?
I would change the reviser's wording to:
It should be clear that to avoid SQL Injection, the application should use prepared statements, escape input, or filter application data before interpolating into an SQL string.
It's not necessary to escape a value if you're going to pass as a parameter. In fact, you should not, because you'll insert literal backslashes into your data.
You need to interpolate strings into your SQL statement when you can't use a query parameter. Examples include:
Table names and column names, which have their own syntax for delimited identifiers. These must be part of the SQL query at prepare time, so the RDBMS can parse and validate them.
SQL keywords, which should be sanitized but cannot be escaped because they are not delimited.
Other syntax or expressions.
Some cases where literal values must be provided at prepare time, e.g. MySQL's fulltext functions do not support parameters for the search pattern.
Stored procedures are not a defense against SQL injection. You can prepare and execute unsafe dynamic SQL statements inside a stored procedure. See http://thedailywtf.com/Articles/For-the-Ease-of-Maintenance.aspx for a great story about that.
I cover all these cases in my presentation SQL Injection Myths and Fallacies. That may be a helpful resource for you.
I also cover SQL injection defense in a chapter of my book, SQL Antipatterns Volume 1: Avoiding the Pitfalls of Database Programming.
If i use PDO, why i should [es]scape the input or have a stored procedure?
As long as you always use PDO, I don't see a reason to bother with input escaping or SPs.
When in doubt, ask yourself: will this piece of plain input data be escaped by some API down the line? Most of the time they will, except when you manually build SQL sentences from input data.
You should not escape if you use PDO. You should not escape if you use JDBC Prepared Statements with parameters. Similarly, most other APIs also take care of this. Stored procedures are not even concerned with escaped data and using them will not magically avoid SQL injection security issues if the input data is not escaped in the SQL that runs the procedure.
Always SQL-Escape data that you put in SQL sentences. Never SQL-Escape data outside SQL sentences.

How does the "With" keyword work in SQL?

So many times seen with and, so many times SQL Server ask that with has ; before it
How does ;with ... work??
;with coords(...) as (
SELECT * ...
)
Why must have ; before it?
The semicolon is used in SQL to end a query. Putting it before a query like that is just to make sure that the database understands that any previous query has ended.
Originally it was required after each query as they were entered line by line, so the database had to know when to run the query. When the entire query is sent in a single string, you only need semicolons in the case where the SQL syntax is not enough to determine where a query ends. As the with keyword has different uses a semicolon is sometimes needed before it to make sure that it's not part of the previous query.
Using WITH for CTEs requires the previous statement to be terminated with ;. Using it at the start like this guarantees correct syntax
So does MERGE in SQL Server 2008
See this SO question: Incorrect syntax near the keyword 'with'...previous statement must be terminated with a semicolon
It is best practise to terminate every SQL statement with a semicolon. The SQL Server docs (for example here) suggest doing so will be mandated in a future version to there's really no excuse for not getting into the habit now.
To answer the question: you see ;WITH... on Stackoverflow because EITHER the person answering is a sloppy coder OR the person answering assumes the person asking the question is a sloppy coder (and they'll claim it is the latter when it is the former :) The definition of "sloppy coder" here is someone who only uses a semicolon when they are forced to do so.
The use of WITH is for common table expressions (CTEs). They were trying to force the CTE to be defined as the first statement (i.e. cannot be linked with other parts of the query hence the ;)

Mysql change delimiter for better SQL INJECTION handling?

I am using mysql and trying to block unwanted queries injection of people who will try to use my single query to run several ones. ie, for example when i have the parameter "?id=3", people can try to run it with ="id=3;drop table users"
Now, i know that the best way to avoid this is by parsing and checking the parameter, but is there a way to change the concatenated queries delimiter from ";" to something like "%^#$%##$^$"?
Security through obscurity is useless. Take the time to write the proper code to protect against the SQL injection attacks. Doing it up front will cost you a lot less than doing it after you've had a successful attack run against your code!
The best way to defend against injection attacks is to use Prepared Statements.
By using Prepared Statements, you are immune to most injection attacks (which of course aren't the only security vulnerability you need to think about, but they're a pretty major one.)
The statement DELIMITER configuration is a built-in command only in the mysql client tool. You can't change the delimiter for multi-statements. It's always semicolon.
Also, the MySQL API allows execution of only one statement at a time, by default. The example you're talking about doesn't work unless you explicitly enable multi-statements.
Furthermore, multi-statements isn't the only vector for SQL injection. Even if you could change the statement delimiter, it wouldn't do anything to protect against SQL injection that modifies a single given statement.
UPDATE Accounts SET PASSWORD = '...' WHERE account_id = $id
In this example, if $id has a value of "1234 OR 1=1" then the attacker has changed the password for all accounts, including probably a privileged user. And yet no multi-statements were involved.
You still need to be mindful of security issues when you write code. There's no silver bullet to protect against SQL injection.
Even query parameters aren't a cure-all for SQL injection. Parameters take the place only of values in SQL expressions. There are many common cases where it's still necessary to interpolate application variables into an SQL string. For example, when parameterizing an IN() predicate, or when choosing ORDER BY expressions. Don't listen to people who say prepared queries are 100% proof against security flaws.
See also my presentation SQL Injection Myths and Fallacies, or the chapter on SQL Injection in my book, SQL Antipatterns Volume 1: Avoiding the Pitfalls of Database Programming.
When you call mysql_query or mysql_real_query, it won't run multiple statements anyway, so the statement delimiter doesn't really matter. You can enable multiple statements per query when you connect, but since you're trying to avoid that ability, simply don't enable it.
An even better option for avoid SQL injection is to use prepared statements. Start with mysql_stmt_init and mysql_stmt_prepare with placeholders for your statement's parameters, and then fill in the parameters with mysql_stmt_bind_param before mysql_stmt_execute. If you're not calling the API directly, then whatever wrapper library you have should also provide support for prepared statements. (If it doesn't support them, then consider switching to a better wrapper.)