Oracle SQL script running from Linux command line with alter session - sql

We have a Java app that will remotely query all the SQL files in a directory and output the CSV files. It works great if the SQL files have just the SELECT command. However, in order to get the datetimes in the right format, I want to use the ALTER session command. This produces an error in the Java app as it treats each command as a new file. Unfortunately, I don't have access to the code base of the Java app. Essentially, the SQL files each look like the following:
alter session set nls_date_format = 'yyyy-mm-dd hh24:mi:ss';
SELECT * from sample_table
Is there any way to run the edit a SQL file to run as a single executed query?

alter session set nls_date_format = 'yyyy-mm-dd hh24:mi:ss'; is a DDL statement. You cannot execute that as a DML statement. Your Java Statement class won't work to execute this ALTER SESSION ... query.
Moreover, if talking from the Database connection perspective, it is valid only up to that session in which it is applied, next time it won't hold still the same value.
This change can't be made permanently using this approach, there is a different approach, which is off-topic here (I know because once I also felt the same need, but came to know the things after struggling for a few days).
The way how you're trying to achieve your result is incorrect.
Format the content into whatever format you want your date-time to be displayed in, you don't need an ALTER SESSION command alongwith a SELECT query.
Use to_char(yourDate, 'YYYY-MM-DD HH24:MI:SS') as customDate and try adjusting to your main select query.

Related

Pentaho Kettle yells SQL Script error that Oracle doesn't

I have an ETL process which executes dozens of SQL query tasks.
One specifically keeps throwing an error: "ORA-01843: not a valid month" to one of my queries, however the very same query runs normally on PL/SQL. I have even created a procedure with a version of the same query, it also runs smoothly, but calling this procedure from pentaho keeps throwing the same error. Please, anyone have any idea why is pentaho presenting a query error that PL/SQL is not? Thanks in advance!
If you do:
SELECT TO_DATE('01-FEB-03', 'DD-MON-RR') FROM DUAL;
Then, on an English database with the default settings, the query works
Then you change your session settings:
ALTER SESSION SET NLS_DATE_LANGUAGE = 'FRENCH';
ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-RR';
And run the same query:
SELECT TO_DATE('01-FEB-03', 'DD-MON-RR') FROM DUAL;
You will get the error:
ORA-01843: not a valid month
There are three solutions to this:
Use the same settings for both queries - this is not a robust solution as you may specify the settings for some services and then it works for a while but then a new developer comes along and connects a new service and does not know of the required settings and suddenly everything is breaking.
Specify the settings to use in the query.
SELECT TO_DATE(
'01-FEB-03',
'DD-MON-RR', -- Specify the format
'NLS_DATE_LANGUAGE=English' -- Specify the language
)
FROM DUAL;
Use a date literal (which is agnostic of the settings):
SELECT DATE '2003-02-01' FROM DUAL;
db<>fiddle here

Change the database connection programmatically

In Oracle SQL Developer, I need to switch the active database connection manually. Is there a command that will connect to a different database programmatically, assuming that the login credentials are already saved? I'm trying to avoid clicking on the drop-down menu at the top right of the window which selects the active connection.
Perhaps I should rather have a single SQL file per database? I could understand that argument. But this to prepare to migrate some tables from one database to another and so it's nice to have all of the context in one file.
On database1, run a query on table1 which is located in schema1.
-- manually switch to database1 (looking for a command to replace this step)
ALTER SESSION SET CURRENT_SCHEMA = schema1
SELECT * FROM table1;
On database2, run a query on table2 which is located in schema2.
-- manually switch to database2
ALTER SESSION SET CURRENT_SCHEMA = schema2
SELECT * FROM table2;
Looks like this is well documented here
Use this command
CONN[ECT] [{<logon>| / |proxy} [AS {SYSOPER | SYSDBA | SYSASM}] [edition=value]]
You need a DDL TRIGGER to perform an event after your presql
CREATE TRIGGER sample
ON TABLE
AFTER
Event
........
THEN
ALTER SESSION SET
CURRENT_SCHEMA = schema2
SELECT * FROM table2;
I don't know of a way in which to change your selected connection in SQL Developer, but there is a programmatic method for temporarily changing the connection under which the script commands are run, as #T.S. pointed out. I want to give a few examples, which might be helpful to people (as they would have been for me).
So let's say your script has part A and part B and you want to execute them one after the other but from different connections. Then you can use this:
CONNECT username1/password1#connect_identifier1;
-- Put commands A here to be executed under this connection.
DISCONNECT; -- username1
CONNECT username2/password2#connect_identifier2;
-- Put commands B here to be executed under this connection.
DISCONNECT; -- username2
The connect_identifier part identifies the database where you want to connect. For instance, if you want to connect to a pluggable database on the local machine, you may use something like this:
CONNECT username/password#localhost/pluggable_database_name;
or if you want to connect to a remote database:
CONNECT username/password#IP:port/database_name;
You can omit the password, but then you will have to input it in a prompt each time you run that section. If you want to consult the CONNECT command in more detail, this reference document may be useful.
In order to execute the commands, you would then select the code that you are interested in (including the relevant CONNECT commands) and use Run Script (F5) or just use Run Script (F5) without selecting anything which will execute the entire script file. SQL Developer will execute your commands, put the output into the Script Output tab and then stop the connection. Note that the output of SELECT commands might be unpleasant to read inside Script Output. This can be mitigated by running the following command first (just once):
SET sqlformat ansiconsole;
There is also Run Statement (Ctrl+Enter), but do note that Run Statement (Ctrl+Enter) does not seem to work well with this workflow. It will execute and display each SELECT statement into a separate Query Result tab, which is easier to read, BUT the SELECT query will always be executed from the context of the active connection in SQL Developer (the one in the top right), not the current code connection of the CONNECT statement. On the other hand, INSERT commands, for instance, DO seem to be executed in the context of the current code connection of the CONNECT statement. This (rather inconsistent) behaviour is probably not what you want, so I recommend using Run Script (F5) as described above.

Access to a session in SQL Server

I have a session created in my vb.net codes and running some SQL queries, there are some local temp tables like #T1, #T2 , ...
Execution process has some steps and I need to know which data changes in my local tables in each step.
Currently I use this to view the data in my code:
select * into ##T1 from #T1
I can't use sp_getbindtoken because there is no active transaction. I can not use DBCC because I don't have permission.
I can run sys.dm_exec_sessions view and therefor I have active session_id,
I also have connection Index of active sql connection
is there any way to connect to a active session and access local temp tables?
or is there any way to get those data of #T1, #T2,...?
EDIT1:
according to the comment which commented by #SeanLange
I have some temp tables as I said, and in the steps mentioned before I do some calculations on these temp tables, for tracing these calculations I need to know what happens in these steps, and I want to execute a simple select statement on these temp tables. what I wanted to do was connect to the active session created in my source code from an external project called Tracer, and perform select statements while my source is on the fly and meanwhile trace the data created in these session
You can't do it. Sorry. (at least without sa privileges).
Run your queries from within a stored procedure and add code to log whatever you need to a table, then query the log table as needed.
Execution process has some steps and I need to know which data changes in my local tables in each step.
If you have permission, you can create a trigger to do the logging for you

How to pass a bash variable to sqlplus and then pass that output to another variable

So what I'm trying to do is to clear the audit logs of the PDB in an Oracle database. The name of the PDB can be different each time, so I cannot use tnsnames to sqlplus directly into the PDB to do this. I'm passing commands into bash and then passing those into a SQLPLUS command. Each of these work except for one and I can't seem to figure out how to get it to work.
My code is
AUDIT="DELETE FROM SYS.AUD$ WHERE NTIMESTAMP# < sysdate-30;"
FINDPDB="select pdb_name from dba_pdbs where pdb_name != 'PDB\$SEED';"
ALTER="alter session set container=$FINDPDB;"
sqlplus -S /nolog <<EOF1
connect / as sysdba
set echo off feedback off head off pages 0
set serveroutput on
$FINDPDB
$ALTER
$AUDIT
exit;
EOF1
The error I keep getting is
alter session set container=select pdb_name from dba_pdbs where pdb_name != 'PDB$SEED';
*
ERROR at line 1:
ORA-65015: missing or invalid container name
This tells me that it's not passing the output of the select statement to $FINDPDB, but rather the actual select statement itself.
Is there a way I can pass this value to the ALTER variable and have it alter the session and clear the sys.aud$ table?
The error I keep getting is
alter session set container=select pdb_name from dba_pdbs where pdb_name != 'PDB$SEED';
*
ERROR at line 1:
ORA-65015: missing or invalid container name
This tells me that it's not passing the output of the select statement to $FINDPDB, but rather the actual select statement itself.
I don't see why you would expect this to pass the output of the SELECT query into $FINDPDB. You're putting together a big long string which bash passes to the standard input of sqlplus and then writes to stdout the output from sqlplus. At no point is bash picking out certain lines of the sqlplus output and putting them into shell variables.
In fact, try adding echo $ALTER to your bash script before you call sqlplus. You will quite probably find that the output is
alter session set container=select pdb_name from dba_pdbs where pdb_name != 'PDB$SEED';
If so, then bash has already done the substitution you didn't want before you've even started sqlplus.
You seem to want bash and sqlplus to have some kind of back-and-forth dialog. I would give up on this approach. Instead of trying to put the PDB name into a shell variable, I would put it into a sqlplus substitution variable. I would try something like the following (not tested):
sqlplus -S /nolog <<"EOF1"
connect / as sysdba
set echo off feedback off head off pages 0
set serveroutput on
column pdb_name new_value pdb
select pdb_name from dba_pdbs where pdb_name != 'PDB\$SEED';
alter session set container = &pdb.;
delete from sys.aud$ where ntimestamp# < sysdate - 30;
exit;
EOF1
We use column pdb_name new_value pdb to set the substitution variable pdb to the next value to be selected from a column named pdb_name. We then run a select query to fetch the PDB name and hence store it in pdb. Once we've got this value in a substitution variable, we can then issue the alter session statement to change the PDB and finally the delete statement to delete data from the PDB.
I'm tempted to avoid the use of a PL/SQL block for this, as has been suggested in another answer. I would prefer that the delete statement is parsed after the PDB is changed as I would want to be sure that the data from the 'correct' PDB is being deleted. My concern with using PL/SQL for this is that the PL/SQL compiler would determine which table to delete from when the block is parsed, which would be before it runs the block, and hence before it executes the alter session statement to change the PDB. However, I don't know PDBs and CDBs in Oracle 12c well enough to say whether this is a genuine problem or unfounded nonsense.
I don't have access to a pluggable Oracle 12c database to run something like this against, so I can't tell you whether this script works. If not, hopefully it should give you an idea of where to go.
I have no Oracle instance at hand but I see two ways to do this :
Make many connections through SQL*Plus
First, to retrieve pdb_name.
Second, to set container and delete audits.
Uses a single SQL*Plus but uses two named pipes
One to send generated SQL commands
Second to read SQL*Plus output
As alternative way I should have used a "real" programming language (Ruby, Python, JavaScript) which are better dedicated to deal with data read from database.
EDIT: After some search, it mays be done in PL/SQL
DECLARE
v_pdb_name VARCHAR2(255);
BEGIN
SELECT pdb_name INTO v_pdb_name FROM dba_pdbs WHERE pdb_name != 'PDB\$SEED';
EXECUTE IMMEDIATE 'ALTER SESSION SET container='||v_pdb_name;
DELETE FROM sys.aud$ WHERE ntimestamp# < sysdate-30;
END;
/

Toad gives only date in sql

When I do a query SELECT t.NAME, t.SOME_DATE FROM MY_TABLE t in toad I get dates as 14-FEB-13 with no time information! In the table browser it gives full date and time. How can this be changed?
That is the default setting for a session. If you want to change it,
ALTER SESSION SET NLS_DATE_FORMAT='DD-MON-YYYY HH24:MI:SS';
Or, change your query to
SELECT t.NAME, to_char(t.SOME_DATE,'DD-MON-YYYY HH24:MI:SS') FROM MY_TABLE t
( the above is just an example, you can format whatever way you want in the format string, ie. 'MM/DD/YYYY, etc.)
If you want to see the same results as you see in the table browser when executing SQL directly (without changing your settings), use "Editor\Execute Statement (F9)" instead of "Editor\Execute as Script".
"Execute statement" displays data in a Toad grid, so the formatting will always be the same as the formatting you see in the table browser, while "Execute script" uses your session information, as explained in OldProgrammer's answer.
Execute statement:
Execute script: