How to separate SQL variable inside a string - sql

In my SQL script I can define variable like:
DEFINE x=100;
and use it like:
CREATE TABLE A&x AS ...;
the result will be CREATE TABLE A100 AS ... (concatenated string).
But I'd like to get CREATE TABLE A100B AS ... in similar query (B suffix):
CREATE TABLE A&xB AS ...;
But Oracle/SQL understands there is xB variable
How to separate variable (name) inside SQL:
CREATE TABLE A&{x}B AS ...;
This does not work!
(e.g. like ${x} i PHP)

It is just a tiny, little dot.
SQL> define x=100
SQL> create table a&x.b as select * from dual;
old 1: create table a&x.b as select * from dual
new 1: create table a100b as select * from dual
Table created.
SQL> select * from a100b;
D
-
X
SQL>
Here, in case you missed it:
create table a&x.b
^
|
here
What's the point? The SQLPlus concatenation character. By default, it is a dot. It tells SQLPlus where the variable name ends.
If you ask for more help:
SQL> help set
SET
---
Sets a system variable to alter the SQL*Plus environment settings
for your current session. For example, to:
- set the display width for data
- customize HTML formatting
- enable or disable printing of column headings
- set the number of lines per page
SET system_variable value
where system_variable and value represent one of the following clauses:
APPI[NFO]{OFF|ON|text} NEWP[AGE] {1|n|NONE}
ARRAY[SIZE] {15|n} NULL text
AUTO[COMMIT] {OFF|ON|IMM[EDIATE]|n} NUMF[ORMAT] format
<snip>
---------------------
CON[CAT] {.|c|ON|OFF} [FOR[MAT] {WRA[PPED] |
---------------------
Here it is!

Related

Create table with a variable name

I need to create tables on daily basis with name as date in form at (yyMMdd), I tried this :
dbadmin=> \set table_name 'select to_char(current_date, \'yyMMdd \')'
dbadmin=> :table_name;
to_char
---------
150515
(1 row)
and then tried to create table with table name from the set parameter :table_name, but got this
dbadmin=> create table :table_name(col1 varchar(1));
ERROR 4856: Syntax error at or near "select" at character 14
LINE 1: create table select to_char(current_date, 'yyMMdd ')(col1 va...
Is there a way where i could store a value in a variable and then use that variable as table name or to assign priority that the inner select statement has execute first to give me the name i require.
Please suggest!!!
Try this
for what ever reason the variable stored comes with some space and i had to remove it and also cannot start naming table starting with numbers so i had to add something in form like tbl_
in short you just need to store the value of the exit so you need to do some extra work and execute the query.
\set table_name `vsql -U dbadmin -w d -t -c "select concat('tbl_',replace(to_char(current_date, 'yyMMdd'),' ',''))"`
Create table:
create table :table_name(col1 varchar(1));
(dbadmin#:5433) [dbadmin] *> \d tbl_150515
Schema | public
Table | tbl_150515
Column | col1
Type | varchar(1)
Size | 1
Default |
Not Null | f
Primary Key | f
Foreign Key |

Table name alias in netezza

I use the following commands in netezza SQL to define table name alias while running a query through command line NZSQL
\set catgtable 'table_a'
\echo table name is :catgtable
and I use the table name alias catgtable wherever required as in:
select *
from :catgtable where col1 is not NULL
My problem is how to use the alias name in these 2 situations:
select ':catgtable' as table_name, col1,col2
from table_x
This gives me an error, since it requires the actual table name.
select table_name, column_name
from _v_sys_columns
where table_name = ':catgtable' and column_name like '%merch_cat_%'
Here again the alias: catgtable doesn't work and it requires the actual table name.
Let me know if there is a workaround.
When you want to use the contents of a variable as a literal in nzsql you need to include an additional set of single quotes, escaped with backslashes, around the literal text when you set the variable.
TESTDB.ADMIN(ADMIN)=> \set tvar '\'BLAH\''
TESTDB.ADMIN(ADMIN)=> select :tvar col_alias;
COL_ALIAS
-----------
BLAH
(1 row)

Oracle NLS_SORT not working via ALTER SESSION?

Using 'alter session set nls_sort' does not seem to be working for me. I am using SQLPlus v11.2.0.3.0 x64 and trying to apply the simple steps for 'Example 9-10 NLS_SORT Affects Linguistic Sort Order' found in the Oracle documentation at http://docs.oracle.com/cd/E18283_01/appdev.112/e10766/tdddg_globalization.htm#CACJEJIB
CREATE TABLE temp (name VARCHAR2(15));
INSERT INTO temp (name) VALUES ('laguna');
INSERT INTO temp (name) VALUES ('llama');
INSERT INTO temp (name) VALUES ('loco');
SELECT * FROM nls_session_parameters WHERE parameter = 'NLS_SORT';
Result: BINARY
SELECT * FROM temp ORDER BY name;
Result:
NAME
---------------
laguna
llama
loco
ALTER SESSION SET NLS_SORT=SPANISH_M;
SELECT * FROM nls_session_parameters WHERE parameter = 'NLS_SORT';
Result: SPANISH_M
SELECT * FROM temp ORDER BY name;
Results are the same:
NAME
---------------
laguna
llama
loco
According to the doco, the sort order above should have changed but it did not. But, if I apply the NLS_SORT as part of the query itself I get the correct resutls:
SELECT * FROM temp ORDER BY NLSSORT(name, 'NLS_SORT=SPANISH_M');
Result:
NAME
---------------
laguna
loco
llama
What am I missing here? Thx in advance.
This was resolved whe I uninstalled Oracle v11.2.0.3.0 and installed v12.1.0.1.0. Truth be told, I can't rule out that it may have just been a problem with our wrapper/configuration of the v11.2.0.3.0 Oracle installer or Oracle itself. Thx for all the post just the same.
The solution is:
1) Go to the REGISTRY (run regedit)
2) Find HKEY_LOCAL_MACHINE/Software/ORACLE
3) Change NLS_LANG
I changed it to
AMERICAN_AMERICA.AR8MSWIN1256
dont forget that you must change all the NLS_LANG in part 2.
now you can login to your database and test it.

Informix: Select null problem

Using Informix, I've created a tempory table which I am trying to populate from a select statement. After this, I want to do an update, to populate more fields in the tempory table.
So I'm doing something like;
create temp table _results (group_ser int, item_ser int, restype char(4));
insert into _results (group_ser, item_ser)
select
group_ser, item_ser, null
from
sometable
But you can't select null.
For example;
select first 1 current from systables
works but
select first 1 null from systables
fails!
(Don't get me started on why I can't just do a SQL Server like "select current" with no table specified!)
You don't have to write a stored procedure; you simply have to tell IDS what type the NULL is. Assuming you are not using IDS 7.31 (which does not support any cast notation), you can write:
SELECT NULL::INTEGER FROM dual;
SELECT CAST(NULL AS INTEGER) FROM dual;
And, if you don't have dual as a table (you probably don't), you can do one of a few things:
CREATE SYNONYM dual FOR sysmaster:"informix".sysdual;
The 'sysdual' table was added relatively recently (IDS 11.10, IIRC), so if you are using an older version, it won't exist. The following works with any version of IDS - it's what I use.
-- #(#)$Id: dual.sql,v 2.1 2004/11/01 18:16:32 jleffler Exp $
-- Create table DUAL - structurally equivalent to Oracle's similarly named table.
-- It contains one row of data.
CREATE TABLE dual
(
dummy CHAR(1) DEFAULT 'x' NOT NULL CHECK (dummy = 'x') PRIMARY KEY
) EXTENT SIZE 8 NEXT SIZE 8;
INSERT INTO dual VALUES('x');
REVOKE ALL ON dual FROM PUBLIC;
GRANT SELECT ON dual TO PUBLIC;
Idiomatically, if you are going to SELECT from Systables to get a single row, you should include 'WHERE tabid = 1'; this is the entry for Systables itself, and if it is missing, the fact that your SELECT statement does return any data is the least of your troubles. (I've never seen that as an error, though.)
This page says the reason you can't do that is because "NULL" doesn't have a type. So, the workaround is to create a sproc that simply returns NULL in the type you want.
That sounds like a pretty bad solution to me though. Maybe you could create a variable in your script, set it to null, then select that variable instead? Something like this:
DEFINE dummy INT;
LET dummy = NULL;
SELECT group_ser, item_ser, dummy
FROM sometable
SELECT group_ser, item_ser, replace(null,null) as my_null_column
FROM sometable
or you can use nvl(null,null) to return a null for your select statement.
Is there any reason to go for an actual table? I have been using
select blah from table(set{1})
select blah from table(set{1})
is nice when you are using 10.x database. This statement doesn't touch database. The amount of read/write operations is equal to 0,
but
when you're using 11.x it will cost you at least 4500 buffer reads because this version of Informix creates this table in memory and executes query against it.
select to_date(null) from table;
This works when I want to get a date with null value
You can use this expression (''+1) on the SELECT list, instead of null keyword. It evaluates to NULL value of type DECIMAL(2,0).
This (''+1.0001) evaluates to DECIMAL(16,4). And so on.
If you want DATE type use DATE(''+1) to get null value of type DATE.
(''+1)||' ' evaluates to an empty string of type VARCHAR(1).
To obtain NULL value of type VARCHAR(1) use this expression:
DATE(''+1)||' '
Works in 9.x and 11.x.

How do you use script variables in psql?

In MS SQL Server, I create my scripts to use customizable variables:
DECLARE #somevariable int
SELECT #somevariable = -1
INSERT INTO foo VALUES ( #somevariable )
I'll then change the value of #somevariable at runtime, depending on the value that I want in the particular situation. Since it's at the top of the script it's easy to see and remember.
How do I do the same with the PostgreSQL client psql?
Postgres variables are created through the \set command, for example ...
\set myvariable value
... and can then be substituted, for example, as ...
SELECT * FROM :myvariable.table1;
... or ...
SELECT * FROM table1 WHERE :myvariable IS NULL;
edit: As of psql 9.1, variables can be expanded in quotes as in:
\set myvariable value
SELECT * FROM table1 WHERE column1 = :'myvariable';
In older versions of the psql client:
... If you want to use the variable as the value in a conditional string query, such as ...
SELECT * FROM table1 WHERE column1 = ':myvariable';
... then you need to include the quotes in the variable itself as the above will not work. Instead define your variable as such ...
\set myvariable 'value'
However, if, like me, you ran into a situation in which you wanted to make a string from an existing variable, I found the trick to be this ...
\set quoted_myvariable '\'' :myvariable '\''
Now you have both a quoted and unquoted variable of the same string! And you can do something like this ....
INSERT INTO :myvariable.table1 SELECT * FROM table2 WHERE column1 = :quoted_myvariable;
One final word on PSQL variables:
They don't expand if you enclose them in single quotes in the SQL statement.
Thus this doesn't work:
SELECT * FROM foo WHERE bar = ':myvariable'
To expand to a string literal in a SQL statement, you have to include the quotes in the variable set. However, the variable value already has to be enclosed in quotes, which means that you need a second set of quotes, and the inner set has to be escaped. Thus you need:
\set myvariable '\'somestring\''
SELECT * FROM foo WHERE bar = :myvariable
EDIT: starting with PostgreSQL 9.1, you may write instead:
\set myvariable somestring
SELECT * FROM foo WHERE bar = :'myvariable'
You can try to use a WITH clause.
WITH vars AS (SELECT 42 AS answer, 3.14 AS appr_pi)
SELECT t.*, vars.answer, t.radius*vars.appr_pi
FROM table AS t, vars;
Specifically for psql, you can pass psql variables from the command line too; you can pass them with -v. Here's a usage example:
$ psql -v filepath=/path/to/my/directory/mydatafile.data regress
regress=> SELECT :'filepath';
?column?
---------------------------------------
/path/to/my/directory/mydatafile.data
(1 row)
Note that the colon is unquoted, then the variable name its self is quoted. Odd syntax, I know. This only works in psql; it won't work in (say) PgAdmin-III.
This substitution happens during input processing in psql, so you can't (say) define a function that uses :'filepath' and expect the value of :'filepath' to change from session to session. It'll be substituted once, when the function is defined, and then will be a constant after that. It's useful for scripting but not runtime use.
FWIW, the real problem was that I had included a semicolon at the end of my \set command:
\set owner_password 'thepassword';
The semicolon was interpreted as an actual character in the variable:
\echo :owner_password
thepassword;
So when I tried to use it:
CREATE ROLE myrole LOGIN UNENCRYPTED PASSWORD :owner_password NOINHERIT CREATEDB CREATEROLE VALID UNTIL 'infinity';
...I got this:
CREATE ROLE myrole LOGIN UNENCRYPTED PASSWORD thepassword; NOINHERIT CREATEDB CREATEROLE VALID UNTIL 'infinity';
That not only failed to set the quotes around the literal, but split the command into 2 parts (the second of which was invalid as it started with "NOINHERIT").
The moral of this story: PostgreSQL "variables" are really macros used in text expansion, not true values. I'm sure that comes in handy, but it's tricky at first.
postgres (since version 9.0) allows anonymous blocks in any of the supported server-side scripting languages
DO '
DECLARE somevariable int = -1;
BEGIN
INSERT INTO foo VALUES ( somevariable );
END
' ;
http://www.postgresql.org/docs/current/static/sql-do.html
As everything is inside a string, external string variables being substituted in will need to be escaped and quoted twice. Using dollar quoting instead will not give full protection against SQL injection.
You need to use one of the procedural languages such as PL/pgSQL not the SQL proc language.
In PL/pgSQL you can use vars right in SQL statements.
For single quotes you can use the quote literal function.
I solved it with a temp table.
CREATE TEMP TABLE temp_session_variables (
"sessionSalt" TEXT
);
INSERT INTO temp_session_variables ("sessionSalt") VALUES (current_timestamp || RANDOM()::TEXT);
This way, I had a "variable" I could use over multiple queries, that is unique for the session. I needed it to generate unique "usernames" while still not having collisions if importing users with the same user name.
Another approach is to (ab)use the PostgreSQL GUC mechanism to create variables. See this prior answer for details and examples.
You declare the GUC in postgresql.conf, then change its value at runtime with SET commands and get its value with current_setting(...).
I don't recommend this for general use, but it could be useful in narrow cases like the one mentioned in the linked question, where the poster wanted a way to provide the application-level username to triggers and functions.
I've found this question and the answers extremely useful, but also confusing. I had lots of trouble getting quoted variables to work, so here is the way I got it working:
\set deployment_user username -- username
\set deployment_pass '\'string_password\''
ALTER USER :deployment_user WITH PASSWORD :deployment_pass;
This way you can define the variable in one statement. When you use it, single quotes will be embedded into the variable.
NOTE! When I put a comment after the quoted variable it got sucked in as part of the variable when I tried some of the methods in other answers. That was really screwing me up for a while. With this method comments appear to be treated as you'd expect.
I really miss that feature. Only way to achieve something similar is to use functions.
I have used it in two ways:
perl functions that use $_SHARED variable
store your variables in table
Perl version:
CREATE FUNCTION var(name text, val text) RETURNS void AS $$
$_SHARED{$_[0]} = $_[1];
$$ LANGUAGE plperl;
CREATE FUNCTION var(name text) RETURNS text AS $$
return $_SHARED{$_[0]};
$$ LANGUAGE plperl;
Table version:
CREATE TABLE var (
sess bigint NOT NULL,
key varchar NOT NULL,
val varchar,
CONSTRAINT var_pkey PRIMARY KEY (sess, key)
);
CREATE FUNCTION var(key varchar, val anyelement) RETURNS void AS $$
DELETE FROM var WHERE sess = pg_backend_pid() AND key = $1;
INSERT INTO var (sess, key, val) VALUES (sessid(), $1, $2::varchar);
$$ LANGUAGE 'sql';
CREATE FUNCTION var(varname varchar) RETURNS varchar AS $$
SELECT val FROM var WHERE sess = pg_backend_pid() AND key = $1;
$$ LANGUAGE 'sql';
Notes:
plperlu is faster than perl
pg_backend_pid is not best session identification, consider using pid combined with backend_start from pg_stat_activity
this table version is also bad because you have to clear this is up occasionally (and not delete currently working session variables)
Variables in psql suck. If you want to declare an integer, you have to enter the integer, then do a carriage return, then end the statement in a semicolon. Observe:
Let's say I want to declare an integer variable my_var and insert it into a table test:
Example table test:
thedatabase=# \d test;
Table "public.test"
Column | Type | Modifiers
--------+---------+---------------------------------------------------
id | integer | not null default nextval('test_id_seq'::regclass)
Indexes:
"test_pkey" PRIMARY KEY, btree (id)
Clearly, nothing in this table yet:
thedatabase=# select * from test;
id
----
(0 rows)
We declare a variable. Notice how the semicolon is on the next line!
thedatabase=# \set my_var 999
thedatabase=# ;
Now we can insert. We have to use this weird ":''" looking syntax:
thedatabase=# insert into test(id) values (:'my_var');
INSERT 0 1
It worked!
thedatabase=# select * from test;
id
-----
999
(1 row)
Explanation:
So... what happens if we don't have the semicolon on the next line? The variable? Have a look:
We declare my_var without the new line.
thedatabase=# \set my_var 999;
Let's select my_var.
thedatabase=# select :'my_var';
?column?
----------
999;
(1 row)
WTF is that? It's not an integer, it's a string 999;!
thedatabase=# select 999;
?column?
----------
999
(1 row)
I've posted a new solution for this on another thread.
It uses a table to store variables, and can be updated at any time. A static immutable getter function is dynamically created (by another function), triggered by update to your table. You get nice table storage, plus the blazing fast speeds of an immutable getter.