How can I store sql statements in an oracle table? - sql

We need to store a select statement in a table
select * from table where col = 'col'
But the single quotes messes the insert statement up.
Is it possible to do this somehow?

From Oracle 10G on there is an alternative to doubling up the single quotes:
insert into mytable (mycol) values (q'"select * from table where col = 'col'"');
I used a double-quote character ("), but you can specify a different one e.g.:
insert into mytable (mycol) values (q'#select * from table where col = 'col'#');
The syntax of the literal is:
q'<special character><your string><special character>'
It isn't obviously more readable in a small example like this, but it pays off with large quantities of text e.g.
insert into mytable (mycol) values (
q'"select empno, ename, 'Hello' message
from emp
where job = 'Manager'
and name like 'K%'"'
);

How are you performing the insert? If you are using any sort of provider on the front end, then it should format the string for you so that quotes aren't an issue.
Basically, create a parameterized query and assign the value of the SQL statement to the parameter class instance, and let the db layer take care of it for you.

you can either use two quotes '' to represent a single quote ' or (with 10g+) you can also use a new notation:
SQL> select ' ''foo'' ' txt from dual;
TXT
-------
'foo'
SQL> select q'$ 'bar' $' txt from dual;
TXT
-------
'bar'

If you are using a programming language such as JAVA or C#, you can use prepared (parametrized) statements to put your values in and retrieve them.
If you are in SQLPlus you can escape the apostrophe like this:
insert into my_sql_table (sql_command)
values ('select * from table where col = ''col''');

Single quotes are escaped by duplicating them:
INSERT INTO foo (sql) VALUES ('select * from table where col = ''col''')
However, most database libraries provide bind parameters so you don't need to care about these details:
INSERT INTO foo (sql) VALUES (:sql)
... and then you assign a value to :sql.

Don't store SQL statements in a database!!
Store SQL Views in a database. Put them in a schema if you have to make them cleaner. There is nothing good that will happen ever if you store SQL Statements in a database, short of logging this is categorically a bad idea.
Also if you're using 10g, and you must do this: do it right! Per the FAQ
Use the 10g Quoting mechanism:
Syntax
q'[QUOTE_CHAR]Text[QUOTE_CHAR]'
Make sure that the QUOTE_CHAR doesnt exist in the text.
SELECT q'{This is Orafaq's 'quoted' text field}' FROM DUAL;

Related

FOR loop in Oracle SQL or Apply SQL to multiple Oracle tables

My SQL is a bit rusty, so I don't know whether the following is even possible:
I have multiple tables t_a, t_b, t_c with the same column layout and I want to apply the same operation to them, namely output some aggregation into another table. For a table t_x this would look like this:
CREATE TABLE t_x_aggregate (
<here the col definitions which are the same for all new tables t_[abc]_aggregate>
);
INSERT INTO t_x_aggregate(id, ...)
SELECT id, SUM(factor*amount)
FROM t_x
WHERE some fixed condition
GROUP BY id;
I now want to execute something like a FOR loop around this:
for t_x in t_a, t_b, t_c
CREATE TABLE ...
INSERT INTO ...
end for
Is this possible in SQL? Or would I need to build a wrapper in another language for this?
So, the result of that operation would be 3 new tables? T_A_AGGREGATE, T_B_AGGREGATE and T_C_AGGREGATE?
I think that the fastest way is to write 3 separate CREATE TABLE statements, e.g.
create table t_a_aggregate as
select id, sum(factor * amount) suma
from t_a
where some_condition
group by id;
create table t_b_aggregate as
select id, sum(factor * amount) suma
from t_b
where some_condition
group by id;
create table t_c_aggregate as
select id, sum(factor * amount) suma
from t_c
where some_condition
group by id;
OK; I understand that queries aren't that simple, but nothing much changes - only table names in CREATE and FROM (perhaps somewhere else, but that's more or less "it"). Any decent text editor's search/replace capabilities should be able to do it quickly.
If you want to do it dynamically in a loop (read: PL/SQL), you can - but dynamic SQL doesn't scale, is difficult to maintain, is painful to debug. Therefore, if you're doing it only once, consider running 3 separate statements.
How to do it dynamically?
You'd have to create a string (we usually put them into a locally declared variable) which contains the whole DDL statement. Why? Because you can't execute DDL from a PL/SQL otherwise.
If there are multiple tables and/or columns involved, you'll have to combine "fixed" parts of the statement (like create table, select, from, order by) concatenated with "dynamic" parts - such as column names. Note that in between you have to concatenate commas as separators. Pay attention to usage of multiple single quotes as you have to escape them (or use the q-quoting mechanism).
Also, for multiple columns you'll probably have to do it in a loop, concatenating each new column to previously composed string.
It (the statement stored into the varirable) is the executed by EXECUTE IMMEDIATE. If it is correctly written, it'll succeed. Otherwise, it'll fail, but it won't tell you why it failed (that's why I said difficult debugging").
So, instead of executing it, we usually display that string (using dbms_output.put_line) so that we see how it looks like and - using copy/paste - try to execute it.
Basically, it can be quite complex and - as I said - difficult to maintain and debug.
For the FOR loop you need to use PL/SQL like this:(*)
declare
type array_t is table of varchar2(10);
array array_t := array_t('a', 'b', 'c');
lo_stmt varchar2(2000);
begin
lo_stmt :=
'CREATE TABLE t_'||array(i)||'_aggregate ('||
' <here the col definitions which are the same for all new tables t_[abc]_aggregate>'||
');'||
''||
'INSERT INTO t_'||array(i)||'_aggregate(id, ...)'||
'SELECT id, SUM(factor*amount)'||
'FROM t_'||array(i)||
'WHERE some fixed condition'||
'GROUP BY id;'||
execute immediate lo_stmt;
end loop;
end;
/
Look also at this SO question: How to use Oracle PL/SQL to create...
(*) #Littlefoot describes in the 2nd part of his answer valuable background to this program.

How to store a string which has multiple quotes in a database

I want to store a ciphertext in an Oracle database, but I am getting an error:
identifier is too long.
Its probably because there are multiple quotes in the string. So, how do I store such a string?
For example, my ciphertext may look like:
b't\xb2\xb2\xd6\xab\xab[\x8d\xcc\xab\x1dK\xf7\xa4\xf5\x9a\xe5\xc7\xd2\x874\xbf\xb3\xd5\xf0\xc7\xcbL\xb1\x88\xd2\xae\xeeR\xe6\xd9f\xfc\x89\xfb\xc7\xeb\x0e\xca\xbe\x88\x1e\xa8\xcb\x12\x7f\xeaL\xe5o\x01\x0c\x9f\xd1\xfc\xc2Xe\xd9H6\xa4\x02\xde\xa8\xbb\x04\xf6\xa2\x81\xe8\xa4T\x17\xe5\x94\x1a\xd1\xf3\xca\xe8\xc4v\xb2\x94\xe0,\xb8v\x9c\x13m>W6\x1cL\x87\xde\xce-h\xcd"\xa66\xac&\x9b\xc4C\x9eK\x1fL\xff\nW\x06\x06\xc1\xe3\x7f\x1c{\xff\x93\xdb\t\xdb\x13&\x81\x0c\x06\xf1\x81\x99f\n\x7f\x99\x1e\xbd\xd4\x17\xe9\x05\xb7\x97\xf6\x1f\xd5\xb3\xffK/#6A\t\xa2\xba+\xfaxO\xb9\xa7\x86\xac\x10V\xc6\xe0\x96OfF\x9f\xaaM\xe3\xc9\xf6UNO\x15\x8e\r\x00\x07J)lZ\[]N\x181\xa3\xd4\'\x8a\x91\x81\x0c\xe4:\x88\xf8\xbe\xcc\xcc\xa18\xe2.o\xe5\xb4\xd9\xd3Fk\xf9\xff\x9a\xc8\x04\xaa\x9a\xff\xc2q&\xa7\xd2O\x8eh\xd7\xa9\x02\xc5V'
As you can see there is a single and a double quote in this.
So, how do I store such a string?
A simple option is to use the q-quoting mechanism, where you choose something (like a square bracket, curly bracket, ...) that doesn't exist in your string to enclose those values that have multiple single quotes. Otherwise you would have to escape them using double single quotes, but things get tricky once there are consecutive single quotes. It's just too complicated.
So, an example:
SQL> create table test (col varchar2(50));
Table created.
SQL> insert into test values (q'[that's a string and I'm "Little'foot"]');
1 row created.
SQL> select * From test;
COL
--------------------------------------------------
that's a string and I'm "Little'foot"
SQL>
how do I store such a string?
You appear to have binary data and not a "string"; so store it in a data type for binary data such as BLOB:
CREATE TABLE your_table (
ciphertext BLOB
);
Then when you insert it use a parameterised query and bind variables from whatever interface you are using to access the database (from the look of your data, I would guess it is a bytes data type in Python):
For a positional bind variable, you can use the syntax:
INSERT INTO your_table ( ciphertext ) VALUES ( ? );
For a named bind variable, you can use the syntax:
INSERT INTO your_table ( ciphertext ) VALUES ( :your_value );
Then, when you construct your prepared statement to insert the value, you can pass your data in as the bind variable and you do not need to worry about any quotes.

SQL Replace comma in results without using replace

I feel like this should be simple enough to do, but have not found any solutions that didn't use replace so far. I have the following select statement I am running, and for some of the columns there are commas separating the values. I would like to replace these commas with semicolons, however I only want to do it in the select statement. I don't want it to alter the values in the tables at all. This is not a one off statement either, or I'd just replace all the commas with semicolons and then revert back.
SELECT a.Category_Id, a.Category_Name, ISNULL(b.Category_Alias, '') as Category_Alias,
ISNULL(b.SUPPORT_NAMES, '') as SUPPORT_NAMES
FROM Categories a
INNER JOIN CategoryInfo b on b.Category_Id=a.Category_Id
For the Category_Alias column, the records are actually stored like CS, Customer Support and I want that to show up as CS; Customer Support just for the select statement.
I believe you may be confused as to what the REPLACE function is doing. You can use REPLACE within your SELECT statement without altering the data in the database:
SELECT REPLACE(MyField, ',', ';') AS NewFieldName
FROM MyTable
I believe you don't want to replace the value physically in the table, but ok to replace on select
So you can
Select REPLACE(ColumnName,',',';')
From TableName
Most SQL servers implement an inline replace function. Most of them are named replace(), and can also be used in a select statement.
Example from MySQL:
SELECT field, REPLACE(field,',',';') FROM my_table;

Oracle SQL -- remove partial duplicate from string

I have a table with a column with strings that looke like this:
static-text-here/1abcdefg1abcdefgpxq
From this string 1abcdefg is repeated twice, so I want to remove that partial string, and return:
static-text-here/1abcdefgpxq
I can make no guarantees about the length of the repeat string. In pure SQL, how can this operation be performed?
regexp_replace('static-text-here/1abcdefg1abcdefgpxq', '/(.*)\1', '/\1')
fiddle
If you can guarantee a minimum length of the repeated string, something like this would work:
select REGEXP_REPLACE
(input,
'(.{10,})(.*?)\1+',
'\1') "Less one repetition"
from tablename tn where ...;
I believe this can be expanded to meet your case with some cleverness.
It seems to me that you might be pushing SQL beyond what it is capable/designed for. Is it possible for you to handle this situation programmatically in the layer that lays under the data layer where this type of thing can be more easily handled?
The REPLACE function should be enough to solve the problem.
Test table:
CREATE TABLE test (text varchar(100));
INSERT INTO test (text) VALUES ('pxq');
INSERT INTO test (text) VALUES ('static-text-here/pxq');
INSERT INTO test (text) VALUES ('static-text-here/1abcdefgpxq');
INSERT INTO test (text) VALUES ('static-text-here/1abcdefg1abcdefgpxq');
Query:
SELECT text, REPLACE(text, '1abcdefg1abcdefg', '1abcdefg') AS text2
FROM test;
Result:
TEXT TEXT2
pxq pxq
static-text-here/pxq static-text-here/pxq
static-text-here/1abcdefgpxq static-text-here/1abcdefgpxq
static-text-here/1abcdefg1abcdefgpxq static-text-here/1abcdefgpxq
AFAIK the REPLACE function is not in the SQL99 standard, but most DBMSs support it. I tested it here, and it works with MySQL, PostgreSQL, SQLite, Oracle and MS SQL Server.

Joining SQL result with string

I have a MSSQL 2005 database with a lot of records that were added since last backup. I want to make another SQL script that puts result values into string representing INSERT statement that I will save for later use.
Something like:
SELECT 'Insert INTO tabname columns VALUES("+Column1"',')' FROM XY
Or simple example:
Column A,Row1=5
SELECT A+"BLAH" FROM X
should return "BLAH5"
Thank you
I'm not sure i understand, if you want to build a script (lets say PHP) just run over the records and either print out or to file something like:
echo 'INSERT INTO tablename (field1,field2) VALUES('.$row['field1'].','.$row['field2'].');';
if you want that string in the result directly from the SQL you could use CONCAT:
SELECT CONCAT('INSERT INTO...VALUES(',field1,',',field2,')') FROM yourtable;
Hope that helps...
You should really mention what SQL database system you're using.
For MySQL, what you want is the CONCAT function.
SELECT CONCAT('INSERT INTO table (columns) VALUES ("', column1, '");') FROM xy;
what version of sql?
for ms sql, you can use + for concatenation and single quotes for strings
for mysql/oracle, use concat(column, 'string')