insert a multiline string in Oracle with sqlplus - sql

I have a SQL script that will insert a long string into a table. The string contains a new line (and this new line is absolutely necessary), so when it is written in a text file, the query is split to multiple lines. Something like:
insert into table(id, string) values (1, 'Line1goesHere
Line2GoesHere
blablablabla
');
This runs ok in Toad, but when I save this as a .sql file and run it using sqlplus, it considers each line a separate query, meaning that each line will fail (beacuse insert into table(id, string) values (1, 'Line1goesHere, Line2GoesHere aren't well-formated scripts.
SP2-0734: unknown command beginning "Line2GoesHere" - rest of line ignored.
Is there a way to fix this?

Enable SQLBLANKLINES to allow blank lines in SQL statements. For example:
SET SQLBLANKLINES ON
insert into table(id, string) values (1, 'Line1goesHere
Line2GoesHere
blablablabla
');
The premise of this question is slightly wrong. SQL*Plus does allow multi-line strings by default. It is only blank lines that cause problems.

You can also use not-well-known feature of Oracle's SQL: Perl style quoted strings.
SQL> select q'[f dfgdfklgdfkjgd
2 sdffdslkdflkgj dglk
3 glfdglkjdgkldj ]'
4 from dual;
Q'[FDFGDFKLGDFKJGDSDFFDSLKDFLKGJDGLKGLFDGLKJDGKLDJ]'
----------------------------------------------------
f dfgdfklgdfkjgd
sdffdslkdflkgj dglk
glfdglkjdgkldj

SQL*Plus Manual
You can end a SQL command in one of three ways:
with a semicolon (;)
with a slash (/) on a line by itself
with a blank line
A blank line in a SQL statement or script tells SQL*Plus that you have
finished entering the command, but do not want to run it yet. Press
Return at the end of the last line of the command.
Turning SQLBLANKLINES on in this situation may be the answer, but even with it you still have to worry about the following SQL*Plus commands.
# ("at" sign) (Start of line)
## (double "at" sign) (Start of line)
# SQLPREFIX (Start of line)
. BLOCKTERMINATOR (Start of line and by itself)
/ (slash) (Start of line and by itself)
; SQLT[ERMINATOR] (Start of line and by itself, or at the end)
SQLPREFIX is something that you cannot turn off; it's a feature of SQL*Plus. BLOCKTERMINATOR can be activated or disabled. Slash on the other hand if it appears at the start of a new line will cause it to execute the contents in the buffer. SQL[TERMINATOR] has a similar behavior.

Another way of inserting newlines to a string is concatenating:
chr(13)||chr(10)
(on windows)
or just:
chr(10)
(otherwise)

Related

Pass quoted value sql plus param

I have a shell script script.sh, and a sql script modify_database.sql
In script.sh, I launch the sql script with some param using :
sqlplus user/password ... #modify_database.sql « param_id » « param_newValue »
And in the sql script, I get the parameters value with :
UPDATE T_TEST SET C1 = &param_newValue WHERE ID = &param_id
But I have a lot of problem with the « param_newValue » parameter.
In fact, this parameter could contain some spaces, slash, single quote and double quote character.
For example : L’avion du pilote était surnommé le « Redoutable »
I have a bunch of values to update.
Each new values are stored in a txt file, like that :
id;value
1; L’avion du pilote était surnommé le « Redoutable »
2; Another example of a « test » that’s it
How can I do to pass this param to sqlplus and set the value like that ? The quoted part is giving me a hard time :/
EDIT :
Example, in the input file I have :
123;;;"aaaa/vvvv/COD_039/fff=Avion d'office";"aaaa/vvvv/COD_039/fff=Hello d'orien";
I get this line, I do a cut command to get the first column (ID), the 4th column (to replace), and the 5th column (replacement).
I have a XML node, with a node which contain the 4th column text, and need to replace by the 5th column content.
So I do :
sqlplus -s $DBUSER/$DBPASSWORD#$DBHOST:$DBPORT/$DBSCHEMA #majConfXML.sql "$id" "$newcode"
update T_TEST set XML = updatexml(xmltype(XML_CONF),
'//A[#name="XXX"]//B[#name="YYY"]//pkValue','&2').getClobVal()
But in the param, there is some quotes.
So when I do the update request with '&2', the request is running but it does not work properly.
How can I escape/pass the param value into the updateXML request ?
Thank you
Finally, I find a problem in my bash script before the sqlplus call.
In fact, it was xargs command which I use who interpret simple quote. I simply add double quotes around each string with slash and quote in my input file.
Next, before calling sqlplus, I replace all “ ‘ “ (quote) by “ ‘’ “ (quote quote)

How to Pass a String with Spaces From Command Line to SQL

I am using command line in Windows 7 to read rows of variables from a CSV, pass those variables into a SQL command, and execute that SQL command for each row in the CSV. This works fine, I believe. Where I am running into trouble is when my variables contain spaces, such as strings that need to be input into my database.
My code looks like this:
Command line:
C:\Users\me>(sqlcmd -S npl-sql01 -d OnBaseTEST -i "C:\Users\me\myquery.sql" -v var1="\Policy Term\Policy\" var2= 'REPORT' var3= 'Commercial' )
Where var1, var2, and var3 are variables in the SQL query that get their values from a CSV.
SQL query:
INSERT INTO testdb (column1, column2, column3)
SELECT $(var1), $(var2), $(var3), od.value
FROM otherdatabase AS od
WHERE od.identifier = 24
When I wrap the variable np in single quotes, the command line chokes up on the space in the path. When I wrap it in double quotes, SQL appears to be treating it as a column name rather than a value to be put into a column (based off of this question). I have also tried wrapping with two sets of quotes, e.g. "'a string'" and '"a string"', with no luck. How should I be writing out this string with spaces so that both command line and SQL can understand it?
Edit: For some reason, removing the trailing variable var3 allows the script to work as intended when the string is wrapped with "'two types of quotes'"

Sed - Fixing an sql insert stament with single quote in value

I am asked to help with a UNIX script that deploys database objects with or without data from 1 machine and/or environment with another. The problem is that some columns have CHAR data with single quotes. Only these single quotes need to be converted to 2 single quotes. I was thinking of using sed or awk, but I can't figure it out. Anyone got any ideas?
example:
INSERT INTO SQL_ERROR_MESSAGE (SQL_Error_Cd,Error_Text) VALUES (5492,'The argument for an INOUT/OUT parameter '%VSTR' is invalid.');
becomes
INSERT INTO SQL_ERROR_MESSAGE (SQL_Error_Cd,Error_Text) VALUES (5492,'The argument for an INOUT/OUT parameter ''%VSTR'' is invalid.');
Thanks for your support.
If you are rather certain about the format of your INSERT statement, this might work for you:
sed "s/\([^']\+'[^']\+\)\('\)\([^']\+\)'\(.*\)/\1\2\2\3\2\2\4/" INPUTFILE
But I'd recommend to check the output :-)
Basically it captures everything till the second(!) ' (in \1), then captures the 2nd ' (\2) - that's not needed, I just wrote it this way ... -, in \3 the string in between the 's which should be escaped, and finally the remaining part of the string (\4), and uses the saved entries in the replacement.
Exapmle output (Linux, GNU sed):
$ sed "s/\([^']\+'[^']\+\)\('\)\([^']\+\)'\(.*\)/\1\2\2\3\2\2\4/"
INPUT LINE #=> INSERT INTO SQL_ERROR_MESSAGE (SQL_Error_Cd,Error_Text) VALUES (5492,'The argument for an INOUT/OUT parameter '%VSTR' is invalid.');
OUTPUT LINE #=> INSERT INTO SQL_ERROR_MESSAGE (SQL_Error_Cd,Error_Text) VALUES (5492,'The argument for an INOUT/OUT parameter ''%VSTR'' is invalid.');

SQLPlus removes trailing spaces in clob field on insert

I'm using SQL Plus 11.1.0.6.0 to run a script that performs batch inserts into an Oracle 10g db.
The problem i noticed is when inserting some code string into a clob field that has some lines with trailing spaces such as:
....public void myMethod().... --trailing space here
....{
........int myVar = 1;
........ -- empty line with trailing spaces
........myVar+=1
....}
The string that gets inserted in the table looses those empty trailing spaces in the empty lines and becomes:
....public void myMethod() --trailing space is lost
....{
........int myVar = 1;
-- empty line without trailing spaces
........myVar+=1
....}
Although it makes no difference to the useful data, this is quite frustrating because it's causing the data to differ from the original and fails some tests.
All i could find was SET TRIMSPOOL/TRIMOUT OFF which doesn't change anything, does anyone have some other ideas?
Without posting your script it's hard to be sure, but you probably shouldn't be inserting text strings directly into a CLOB in SQLPlus. If you were to use a PL/SQL proc that pulled in your text from a file and call the PL/SQL from SQLPlus it should keep all the formatting.
But that may be an almighty PITA. But it's well documented in the O'Reilly PL/SQL texts.
In the end i solved it by a hack like this (considering original example):
declare
myLargeValue_2 clob;
begin
myLargeValue_2 := '....public void myMethod()'||'....
'||'....{
........int myVar = 1;
'||'........' -- empty line with trailing spaces
and so on
Basically concatenated explicitly all the whitespaces
You can try to enable following parameter:
SET SQLBLANKLINES ON

Bulk insert, SQL Server 2000, unix linebreaks

I am trying to insert a .csv file into a database with unix linebreaks. The command I am running is:
BULK INSERT table_name
FROM 'C:\file.csv'
WITH
(
FIELDTERMINATOR = ',',
ROWTERMINATOR = '\n'
)
If I convert the file into Windows format the load works, but I don't want to do this extra step if it can be avoided. Any ideas?
I felt compelled to contribute as I was having the same issue, and I need to read 2 UNIX files from SAP at least a couple of times a day. Therefore, instead of using unix2dos, I needed something with less manual intervention and more automatic via programming.
As noted, the Char(10) works within the sql string. I didn't want to use an sql string, and so I used ''''+Char(10)+'''', but for some reason, this didn't compile.
What did work very slick was: with (ROWTERMINATOR = '0x0a')
Problem solved with Hex!
Thanks to all who have answered but I found my preferred solution.
When you tell SQL Server ROWTERMINATOR='\n' it interprets this as meaning the default row terminator under Windows which is actually "\r\n" (using C/C++ notation). If your row terminator is really just "\n" you will have to use the dynamic SQL shown below.
DECLARE #bulk_cmd varchar(1000)
SET #bulk_cmd = 'BULK INSERT table_name
FROM ''C:\file.csv''
WITH (FIELDTERMINATOR = '','', ROWTERMINATOR = '''+CHAR(10)+''')'
EXEC (#bulk_cmd)
Why you can't say BULK INSERT ...(ROWTERMINATOR = CHAR(10)) is beyond me. It doesn't look like you can evaluate any expressions in the WITH section of the command.
What the above does is create a string of the command and execute that. Neatly sidestepping the need to create an additional file or go through extra steps.
I confirm that the syntax
ROWTERMINATOR = '''+CHAR(10)+'''
works when used with an EXEC command.
If you have multiple ROWTERMINATOR characters (e.g. a pipe and a unix linefeed) then the syntax for this is:
ROWTERMINATOR = '''+CHAR(124)+''+CHAR(10)+'''
It's a bit more complicated than that! When you tell SQL Server ROWTERMINATOR='\n' it interprets this as meaning the default row terminator under Windows which is actually "\r\n" (using C/C++ notation). If your row terminator is really just "\n" you will have to use the dynamic SQL shown above. I have just spent the best part of an hour figuring out why \n doesn't really mean \n when used with BULK INSERT!
One option would be to use bcp, and set up a control file with '\n' as the line break character.
Although you've indicated that you would prefer not to, another option would be to use unix2dos to pre-process the file into one with '\r\n' line breaks.
Finally, you can use the FORMATFILE option on BULK INSERT. This will use a bcp control file to specify the import format.
Looks to me there are two general avenues that can be taken: some alternate way to read the CSV in the SQL script or convert the CSV beforehand with any of the numerous ways you can do that (bcp, unix2dos, if it is a one-time king of a thing, you can probably even use your code editor to fix the file for you).
But you will have to have an extra step!
If this SQL is launched from a program, you might want to convert the line endings in that program. In that case and you decide to code the conversion yourself, here is what you need to watch out for:
1. The line ending might be \n
2. or \r\n
3. or even \r (Mac!)
4. good grief, it could be that some lines have \r\n and others \n, any combination is possible unless you control where the CSV came from
OK, OK. Possibility 4 is farfetched. It happens in email, but that is another story.
I would think "ROWTERMINATOR = '\n'" would work. I would suggest opening the file in a tool that shows "hidden characters" to make sure the line is being terminated like you think. I use notepad++ for things like this.
It comes down to this. Unix uses LF (ctrl-J), MS-DOS/Windows uses CR/LF (ctrl-M/Ctrl-J).
When you use '\n' on Unix, it gets translated to a LF character. On MS-DOS/Windows it gets translated to CR/LF. When the your import runs on the Unix formatted file, it sees only a LF. Hence, its often easier to run the file through unix2dos first. But as you said in you original question, you don't want to do this (I'll assume there is a good reason why you can't).
Why can't you do:
(ROWTERMINATOR = CHAR(10))
Probably because when the SQL code is being parsed, it is not replacing the char(10) with the LF character (because it's already encased in single-quotes). Or perhaps its being interpreted as:
(ROWTERMINATOR =
)
What happens when you echo out the contents of #bulk_cmd?