Renaming a table in cockroachdb with dynamic value - sql

In cockroachdb, I'm trying to rename a table with a dynamic value.
Current table name: bla
Wanted table name: bla_currentDay
I was trying something like this:
ALTER TABLE bla RENAME TO (SELECT concat('bla',extract('day', CURRENT_DATE)::STRING));
But I got an error.
invalid syntax: statement ignored: syntax error at or near "("
DETAIL: source SQL:
ALTER TABLE bla RENAME TO (SELECT concat('bla',extract('day', CURRENT_DATE)::STRING))
^
HINT: try \h ALTER TABLE
Is this actually possible with SQL?

At this time, it looks like that is unsupported. According to this comment responding to the question of dynamic sql feature support
...CockroachDB supports SQL with the expectation that it will be driven by an external application written in some other programming language (and you can construct dynamic SQL however you like in your external program). We don’t (yet) have a full in-database programming language like PL/SQL.
...implying that you need to obey the syntax & type constraints for the name identifier as specified in the RENAME TABLE docs.
If you construct your table rename externally to the sql shell, you can pass in the entire command via the --execute flag. You can use the same method to run & retrieve the initial query. For example...
newNameQuery="SELECT concat('bla',extract('day', CURRENT_DATE)::STRING);"
# tail to strip header from scalar, otherwise awk/grep to parse output
newName=`echo $newNameQuery | cockroach sql --certs-dir=$certsDir --host=$host1 | tail -1`
renameQuery="ALTER TABLE bla RENAME TO $newName;"
echo $renameQuery | cockroach sql --certs-dir=$certsDir --host=$host1
...if you fancy a quick'n'dirty bash example.
If however, you really want to do it all in the integrate shell session ... an adversarial reading of the client documentation will reveal the \! & \| utilities. These allow you to pass strings back to your client to execute in your initial shell and pass the results optionally back into the sql shell.
You could string together a long gross string within the sql client and use these flags to juggle back-and-forth as needed until an ALTER TABLE... string was found which the CockroachDB server could validly interpret. If I were pedantic enough to specify what that might look like in your case, I might provide an example like the following...
[1028 16:19:36+0000 ~]$ cockroach sql --certs-dir=$CERTS_DIR --host=$HOST_1
# Welcome to the cockroach SQL interface.
# All statements must be terminated by a semicolon.
# To exit: CTRL + D.
#
# Server version: CockroachDB CCL v19.1.4 (x86_64-unknown-linux-gnu, built 2019/08/06 15:34:13, go1.11.6) (same version as client)
# Cluster ID: deadbeef-dead-beef-dead-beefdeadbeef
#
# Enter \? for a brief introduction.
#
root#host1:26257/defaultdb> create table bla (i int);
CREATE TABLE
Time: 38.562ms
root#host1:26257/defaultdb> \| name=`cockroach sql --certs-dir=$CERTS_DIR --host=$HOST_1 --execute "SELECT concat('bla',extract('day', CURRENT_DATE)::STRING);" | tail -1` && echo "ALTER TABLE bla RENAME to $name ;"
RENAME TABLE
Time: 75.371ms
...where $CERTS_DIR and $HOST_1 are environment variables on my laptop.

Related

can't use postgresql function in bash script

I am new to postgresql and I'm using postgresql 9.3 and postgis 2.1.
In pgadmin, I am able to use a function in database "AddGeometryColumn", but when I write that script in Ubuntu bash, it doesn't work. The error I got is
ERROR: function addgeometrycolumn(unknown, unknown, unknown, unknown, unknown, integer) does not exist
LINE 1: SELECT AddGeometryColumn('tiger_staging','al_place','the_geo...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Does anyone have similar experience?
Also how do you specify "use" database in postgresql? like a query in mysql "use mydatabase" to switch database?
I presume you are using "psql", so do just like this:
psql [databasename] -U [username] -t -e --command="select [function]"
As "Hint" says, you need to cast your param values with exact same types of your function's parameters:
psql [databasename] -U [username] -t -e --command="SELECT AddGeometryColumn(cast('tiger_staging' as character varying),..."
Also check if the number of params in your select matchs your function's parameters.
You are probably connected to a database that does not have the PostGIS extension installed (e.g. the default postgres database). In psql (the command-line client), check that the name coming before the =# prompt matches the database you want to use:
postgres=#
To switch to another database, use the \c command:
postgres=# \c mydatabase
...
mydatabase=#
To check that the PostGIS extension is correctly installed in your current DB, use the postgis_full_version() function:
SELECT postgis_full_version();
This should return information on the PostGIS version if the extension is enabled. If you get a No function matches the given name and argument types error, you will need to install the extension in your current DB:
CREATE EXTENSION postgis;
Note that the PostGIS package has to be installed in order to be able to enable the extension in a database.
You are tripping over CaMeL case names.
Identifier (like AddGeometryColumn) are folded to lower case (addgeometrycolumn) unless double-quoted ("AddGeometryColumn"). Details in the manual.
Unfortunately, PostGis functions follow a naming convention that requires double-quoting at all times.
For your bash-invocation, you probably need to use single quotes around your string to remove the special meaning of double-quotes. Or escape with backslash (\").
Where ever I can I stick to legal, lower-case names exclusively for all identifiers to prevent problems like the one at hand.

What does the "#" do in SQL*Plus

I found this line in a sql code:
#../../sql_scripts/create_tables.sql
What does it do? I know that ##file.sql means that file.sql is run and # could be used when we want to supply parameter values later, but here I have # followed by a filename. I know that there is a similar question but it covers only # in queries.
Here the # is not part of the SQL language. It is likely a command for the SQL interpreter which is probably Oracle SQL*Plus.
SQL*Plus has many single-character commands like # or / (which executes buffered SQL), ; which can be puzzling when you encounter them in an .sql file.
# is documented here in Oracle 9i documentation. There you will see the differences with ##.
documentation for Oracle 11g Release 2, click Next section for ## reference.
The # allows you to import another script into the sql script you're running in SQL*Plus.
For example, this executes the contents of otherscript.sql at the specified point:
PROMPT about to run other script
#otherscript.sql
PROMPT finished running other script
Another example, this inserts the contents of another file into the middle of a statement to be executed in SQL*Plus:
SELECT * FROM mytable WHERE
#predicates_for_mytable.sql
AND bla = 1;
The only condition is that # must appear at the 1st character on the line.

Informix SQL 11.5 storing query results in a file with a dynamic name

I am trying to store the results of a query in a file. The following command accomplishes this task:
UNLOAD TO '/usr/data/report.csv' DELIMITER ';'
SELECT COUNT(*) FROM table1;
Problem: I don't want to overwrite the file (report.csv) every time I execute the query.
Question: How can I include a timestamp or date in the UNLOAD TO filename parameter?
Already tried and not working:
UNLOAD TO ('/usr/data/report_' || (SELECT REPLACE(TODAY, '.', '_') FROM systables WHERE tabid = 1) || '.csv') DELIMITER ';'
SELECT COUNT(*) FROM table1;
Error message displayed:
#
# 809: SQL Syntax error has occurred.
#
Version: Informix SQL 11.50
The first thing to realize about the UNLOAD statement (also the LOAD statement — and the INFO and OUTPUT statements) is that it is (they are) implemented by the client programs such as DB-Access or I4GL or ISQL, and not by the Informix DBMS proper. That is, the DB-Access program reads the command and acts on it. In particular, the 'file related' part — the UNLOAD TO 'file' DELIMITER ';' part of the statement — is never seen by the database server; only the SELECT part is sent to the DBMS. You therefore cannot use SQL concatenation in it; in fact, you can only write literal file names in it (in DB-Access; I4GL allows a variable for the file name).
The way I'd do what you're after is:
#!/bin/sh
timestamp=$(date +'%Y%m%d.%H%M%S')
dbaccess ${DATABASE:-default_db} - << EOF
UNLOAD TO 'report-$timestamp.csv' DELIMITER ';'
SELECT COUNT(*) FROM table1;
EOF
This uses the date command to generate the timestamp in ISO 8601 (compact) notation. It then uses the shell 'here document' to generate the file name that's fed to DB-Access. The ${DATABASE:-default_db} notation uses the database named by the environment variable $DATABASE, but if it is unset, uses default_db as the database name.
In this example, there's nothing in the here document except the timestamp that will be expanded by the shell. In fact, SQL generally stays well away from the shell metacharacters that can cause trouble (dollar and back-quote, primarily). So it is not usually something you have to worry about.

How do I programmatically run a complex query on an as400?

I'm new at working on an as400 and I have a query the joins across 4 tables. The query itself is fine, it runs in STRSQL and displays the results.
What I am in struggling with is getting the query to be able to run programmatically (it will eventually be run from a scheduled CL script).
I tried have creating a physical file that contains the query running it with RUNQRY, but it simply displays the query itself, not the actual result set.
Does anyone know what I am doing wrong?
UPDATE
Thanks everyone for the direction and the resources, with them I was able to reach my goal. In case it helps anyone, this is what I ended up doing (all of this was done in it's own library, ALLOCATE):
Created a source physical file (using CRTSRCPF): QSQLSRC, and created a member named SQLLEAGSEA, with the type of TXT, that contains the SQL statement.
Created another source physical file: QCLSRC, and created a member named POPLEAGSEA, with the type of CLP, that changes the current library to ALLOCATE then runs the query using RUNSQLSTM (more detail on this below). Here is the actual command:
RUNSQLSTM SRCFILE(QSQLSRC) SRCMBR(SQLLEAGSEA) COMMIT(*NONE) NAMING(*SYS)
Added the CLP to the scheduled jobs (using ADDJOBSCDE), running the following command:
CALL PGM(ALLOCATE/POPLEAGSEA)
With regard to RUNSQLSTM, my research indicated that I wasn't going to be able to use this function, because it didn't support SELECT statements. What I didn't indicate in my question was what I needed to do with the the result - I was going to be inserting the resultant data into another table (had I done that I'm sure the help could have figured that out a lot quicker). So effectively, I wasn't going to be doing an SELECT, my end result is actually an INSERT. So my SQL statement (in SQLLEAGSEA) begins with:
INSERT INTO
ALLOCATE/LEAGSEAS
SELECT
...
BLAH BLAH BLAH
...
From my research, I gather that RUNSQLSTM doesn't support SELECT because it doesn't have a mechanism to do anything with the results. Once I stopped taking baby steps and realized I needed to SELECT AND INSERT in the same statement, it solved my main problem.
Thanks again everyone!
The command is RUNSQLSTM to run a static SQL statement in a physical file member or stream file.
It is a non-interactive command so it will not execute sql statements that attempt to return a result set.
If you want more control, including the ability to run interactive statements, see the Qshell db2 utility.
For example:
QSH CMD('db2 -f /QSYS.LIB/MYLIB.LIB/MYSRCFILE.FILE/MYSQL.MBR')
Note that the db2 utility only accepts the *SQL naming convention.
QM Query
If all the SQL you need is the single complex SQL statement, and this is what it sounds like, then your best bet is to use Query Management Query (see QM Query manual here).
The results can be directed to a display, a spool file, or a physical file (ie a DB2 table). The default output when run interactively is to the screen, but when run in a (scheduled) batch job it will default to a spool file report.
You can create the QM Query interactively via WRKQMQRY, in prompted mode (much like Query/400) or in SQL mode. Or you can compile the QM Query from source, with the CRTQMQRY command.
To run your QM Query, STRQMQRY command.
RUNSQL cmd
If you are using a system that has IBM i 7.1 fully up-to-date, and has Technology Refresh 4 (TR4) installed, then you could also use the new RUNSQL command to execute a single statement. (see discussion in developerWorks)
SQL Scripting w/ RUNSQLSTM cmd
From CL you can run SQL scripts of multiple SQL statements from a source file member. There is no standard default source file name for this, but QSQLSRC is commonly used. The source member can contain multiple non-interactive SQL statements. This means you cannot use a SELECT statement (directly) since theoretically it will not know where to send the results. CL commands are even allowed if given a CL: prefix. Both SQL and CL statements should be terminated with a semicolon ;. While the SQL statements cannot display data directly to the screen, the same restriction does not apply to the scripted CL commands.
The STRQMQRY command can be embedded in the RUNSQLSTM script, by placing the prefix "CL: " in front of the command. Since STRQMQRY can direct output to the screen, a report, or an output table, this can come in very useful.
Remember that to direct your output from a SELECT query to a file you can use either the INSERT or CREATE TABLE statements.
CREATE TABLE newtbl AS
( full-select )
WITH DATA;
Or, to put the results into a table you create in your job's QTEMP library:
DECLARE GLOBAL TEMPORARY TABLE AS
( full-select )
WITH DATA;
[Note: If you create the source to be used by CRTQMQRY, you are advised to create it as CRTSRCPF yourlib/QQMQRYSRC RCDLEN(91), since the compiler will only use 79 columns of your source data (adding 12 for sequence and change date =91). However for QM Forms, which can be used to provide additional formatting, the CRTQMFORM compiler will use 81 columns so RCDLEN(93) is advised for QQMFORMSRC.]
RUNQRY is a utility that lets you execute a query that was created by another utility named WRKQRY. If you really want to process SQL statements held in a file try RUNSQLSTM. It uses a source physical file to store the statements, not a database file. The standard name for that source physical file is QQMQRYSRC. To create that file, CRTSRCPF yourlib/QQMQRYSRC. Then you can use PDM to work with that source PF. WRKMBRPDM yourlib/QQMQRYSRC. Use F6 to create a new source member. Make it source type TXT. Then use option 2 to will start an editor called SEU. Copy/paste your SQL statements into this editor. F3 to save the source. Once the source is saved, use RUNSQLSTM to execute it.
It is (now) possible to run SQL directly in a CL program without using QM Query, RUNSQLSTM or QShell.
Here is an article that discusses the RUNSQL statement in CL programs...
http://www.mcpressonline.com/cl/the-cl-corner-introducing-the-new-run-sql-command.html
The article contains information on what OS levels are supported as well as clear examples of several ways to use the RUNSQL statement.
This will work in two steps:
RUNSQL SQL('CREATE TABLE QTEMP/REPORT AS (SELECT +
EXTRACT_DATE , SYSTEM, ODLBNM, SUM( +
OBJSIZE_MB ) AS LIB_SIZE FROM +
ZSYSCOM/DISKRPTHST WHERE ODLBNM LIKE +
''SIS%'' GROUP BY EXTRACT_DATE, SYSTEM, +
ODLBNM ORDER BY LIB_SIZE DESC) WITH +
DATA') COMMIT(*NONE) DATFMT(*USA) DATSEP(/)
RUNQRY QRYFILE((QTEMP/REPORT)) OUTTYPE(*PRINTER) +
OUTFORM(*DETAIL) PRTDFN(*NO) PRTDEV(*PRINT)
The first step creates a temporary table result in qtemp and the second step/line runs an adhoc query over just the temporary table to a spool file.
Thanks,
Michael Frilot
There is of course a totally different solution: You could write and compile a program containing the statement. It requires some longer reading into, especially if you are new to the platform, but it should give you most flexibility over what you do with results. You can use SQL in C, C++, RPG, RPG/LE, REXX, PL (of which I don't know, what it is) and COBOL. Doing that, you can react in any processable way on results from one query and start/create other queries based on what you get.
Although some oldfashioned RPG-programmers try everything to deny SQL in RPG exists, it is possible today for many cases, to write RPG-programs with SQL only and no direct file access (without F-Specs, for those who know RPG).
If your solution works for you, perfect. If you need to do something else, try a look into this pdf: http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/rzajp/rzajp.pdf
The integration into RPG is not too bad. It works with the normal program flow. Would look something like this (in free form):
/free
// init search values:
searchval = 'Someguy';
// so the sql query:
exec sql
SELECT colum1, colum2
INTO :var1, :var2
FROM somelib/somefile
WHERE keycol=:searchval;
// now do something with the values:
some_proc(var1);
/end-free
In this, var1, var2, and searchval are ordinary RPG-variables. No quoting needed. Works also with datastructures (externally defined e.g., the record format of the file itself fits well). You can work with cursors and loops, too, of course. I feel that RPG-programs tend to be easier to read with this.

How to indicate in postgreSQL command in which database to execute a script? (simmilar to SQL Server "use" command)

I have the following problem, I need to put in a script that is going to run before the new version is rolled the SQL code that enables the pgAgent in PostgreSQL. However, this code should be run on the maintenance database (postgres) and the database where we run the script file is another one.
I remember that in SQL Server there is a command "use " so you could do something like:
use foo
-- some code
use bar
-- more code
is there something similar in PostgreSQL?
You can put in your file something like:
\c first_db_name
select * from t; --- your sql
\c second_db_name
select * from t; --- your sql
...
Are you piping these commands through the psql command? If so, \c databasename is what you want.
psql documentation
You can't switch databases in Postgres in this way. You actually have to reconnect to the other database.
PostgreSQL doesn't have the USE command. You would most likely use psql with the --dbname option to accomplish this, --dbname takes the database name as a parameter. See this link for details on the other options you can pass in you will also want to check out the --file option as well. http://www.postgresql.org/docs/9.0/interactive/app-psql.html
well after looking on the web for some time I found this which was what I need it
http://www.postgresonline.com/journal/archives/44-Using-DbLink-to-access-other-PostgreSQL-Databases-and-Servers.html