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.
I execute a SQL query (for PostgreSQL) via psql.exe inside a Windows batch. I get an error I can't explain, saying that a FROM clause is missing for a table that is not called within the query (see below). When I search in the batch file for geo_c3_0_3_mo table, the string is not found...
Any idea on this kind of issue?
EDIT :
If I copy-paste the query from the batch file into a pgAdminIII SQL query window, the query runs perfectly and no error message is returned.
When I remove one of the subqueries, the error either disappear or mention another badly written table name (for instance: missing FROM-clause for table "geoc__0_3_mo")... It seems more and more that the issue comes from the length of the line (19,413 characters!). To me, it is not possible to write the query on several lines within a batch file, like inside a pgAdminIII SQL query window. The solution would be to keep the query inside a *.sql file and to call that file from the batch file.
Write the query to a tempfile in your batch, then execute it with psql -f. This will bypass command-line length issues.
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.
I have an oracle script that I am trying to convert to valid db2 syntax. Within this sql file I have various calls to other sql files passing in a parameter using the '#' syntax.
e.g.
#script1 param1
#script2 param2
Can anyone help me with valid db2 equivalent statements? Is there an equivalent run command in db2? is it possible to pass parameters to a sql script in db2?
thanks,
smauel
The thing you are after is the DB2 Command Line Processor (CLP).
If you want to execute a script, you would execute in the CLP:
db2 -vtf script1
-f tells the CLP to run command input from the given file.
Here's the full list of options.
Unfortunately db2 doesn't support passing parameters to a script. You would have to combine your db2 -vtf commands with other scripting commands (such as sed) to generate the scripts for you, as in this example.
1) place the filename.sql file in SQLLIB/BIN
2) run db2cmd
3) execute this to connect to the required db
db2 connect to *dbname* user *userid* using *password*
4) excute this command
db2 -vtf *filename.sql*
This should execute the sql statements in the file one by one. The sql statements must be ending with a semicolon
There is an easier way for passing in parameters, that works fine for us (it might not work with (complex) multiline sql statements).
Convert your sql-script into a shell script by adding 'db2 ' at the beginning of each line. Than you can use the standard variable replacement syntax from your shell in your scripts.
so instead of
insert ...
update ...
you will have
db2 insert ...
db2 update ...
Place file in one directory.
Open db2cmd.exe as administrator
Navigate to directory where you have place the script
type db2 -vtf `
I write:
CREATE TABLE Person (
name CHAR(10),
ssn INTEGER);
and save it to a file "a.sql".
If I then run it by typing "#a" in the SQL*Plus command prompt, it will tell me that the line starting with "ssn" is not recognized as a command, and is ignored.
From what I gather, it seems that sqlplus terminates a command if it encounters multiple newline characters in a row. Is this an accurate statement? If so, does anyone know if this is necessary/ why it chooses to do this?
I don't know about the why, but a completely blank line terminates a command in SQL*Plus.
Quote from the SQL*Plus docs :
Ending a SQL Command:
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
You can also change how blank lines are treated with SET SQLBLANKLINES
SQLBL[ANKLINES] {ON|OFF}
Controls whether SQL*Plus allows blank lines within a SQL command or script. ON interprets blank lines and new lines as part of a SQL command or script. OFF, the default value, does not allow blank lines or new lines in a SQL command or script or script.
Enter the BLOCKTERMINATOR to stop SQL command entry without running the SQL command. Enter the SQLTERMINATOR character to stop SQL command entry and run the SQL statement.
By default, SQLPlus does terminate (but not execute) a statement when a blank line is entered. It has always done this. It probably seemed like a good idea in the days before screen editors and query tools.
You can change that default behaviour with
set SQLBLANKLINES on
In which case you'd have to enter a line with just a full stop to terminate (but not execute) a statement.
But if you are wanting to insert multiline text in a varchar2 or a clob field, you may use
chr(10)
insert into t values ('Hello,'||chr(10)||chr(10)||' How are you?');
insert into t values (
'Hello,
How are you');
will not work for reasons explained above.