Oracle: how to "unalter" a session parameter? - oracle

I'm doing a case-insensitive query with
alter session set NLS_COMP=LINGUISTIC;
alter session set NLS_SORT=BINARY_CI;
Is there a way to easily capture the session state prior to altering it so that I can restore the session to its original state?

You can obtain the current values using:
select *
from nls_session_parameters;
before you change your session. To restore it, you just use the saved values.
I am not aware of any statement that resets the session parameters to the default value.

The NLS parameters are exposed through a series of views, starting with NLS_. In your case you need NLS_SESSION_PARAMETERS. There are equivalent views for Instance and Database.
This is neater than using v$parameter, although that view does allow us to tell whether a paarmeter is changed from the default value.

You can get the value of a given session parameter by:
SELECT value
FROM nls_session_parameters
WHERE parameter = 'NLS_SORT'; -- replace NLS_SORT with parameter of your choice
This answer demonstrates other means of doing a case insensitive search.
Using UPPER()/LOWER() functions with a function based index.
Regular expressions: REGEXP_LIKE()

You can see the parameter values initially :
SQL> SHOW PARAMETER NLS_SORT;
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
nls_sort string BINARY
SQL> SHOW PARAMETER NLS_COMP;
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
nls_comp string BINARY
And then set the session parameter accordingly :
SQL> alter session set nls_comp='LINGUISTIC';
Session altered
SQL> alter session set nls_sort='BINARY_CI';
Session altered
In PL/SQL, you can do the following to fetch the parameter value and store it in session variable :
SQL> DECLARE
2 VAR_NLS_SORT VARCHAR2(10);
3 var_nls_comp VARCHAR2(10);
4 BEGIN
5 SELECT VALUE
6 INTO VAR_NLS_SORT
7 FROM NLS_SESSION_PARAMETERS
8 WHERE PARAMETER = 'NLS_SORT';
9 SELECT VALUE
10 INTO VAR_NLS_COMP
11 FROM NLS_SESSION_PARAMETERS
12 WHERE PARAMETER = 'NLS_COMP';
13 DBMS_OUTPUT.PUT_LINE('NLS_SORT = '||VAR_NLS_SORT);
14 DBMS_OUTPUT.PUT_LINE('NLS_COMP = '||VAR_NLS_COMP);
15 END;
16 /
NLS_SORT = BINARY
NLS_COMP = BINARY
PL/SQL procedure successfully completed.
For more information, you can have a look at Oracle – Case Insensitive Sorts & Compares

Related

What is the best data type for the field of format "YYYY-MM-DD" in oracle 11g?

I'm creating tables in Oracle 11g table and came across one date field of format "YYYY-MM-DD".
I don't want to use varchar2 for this and when I use number(5), it's still accepting the input. Then what's the meaning of limit 5 here?
Please suggest me the best datatype I can use here.
This is, obviously, a date format mask. If you're about to store dates into that column, you should use the DATE datatype, such as
SQL> create table test
2 (datum date);
Table created.
Don't use VARCHAR2 (put strings into it, not dates) nor NUMBER (put numbers into it, not dates) datatypes for that. You'll regret it sooner than you think.
I'm going to enter some values into the table, showing different ways of how you could do that - it is important that you insert dates, not strings into it. Never rely on Oracle, implicitly converting strings you might provide to dates. Sooner or later, it'll produce an error.
SQL> insert into test values (date '2018-12-25');
1 row created.
SQL> insert into test values (to_date('09.05.2018', 'dd.mm.yyyy'));
1 row created.
SQL> insert into test values (sysdate);
1 row created.
Now, several ways of selecting that value:
This one returns date in a format currently set by my database's NLS settings:
SQL> select * from test;
DATUM
--------
25.12.18
09.05.18
09.05.18
I'm forcing it to return values in desired format, using ALTER SESSION:
SQL> alter session set nls_date_format = 'yyyy-mm-dd';
Session altered.
SQL> select * from test;
DATUM
----------
2018-12-25
2018-05-09
2018-05-09
Yet another format; note that value inserted via the SYSDATE function (which returns DATE) contains date and time component. It was "invisible" in previous examples:
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> select * from test;
DATUM
-------------------
25.12.2018 00:00:00
09.05.2018 00:00:00
09.05.2018 08:03:50
Using TO_CHAR function with some format (such as dd-mon-yyyy). I'm also requesting Oracle to "translate" month name into English (as my database works in Croatian):
SQL> select to_char(datum, 'dd-mon-yyyy', 'nls_date_language = english') datum from test;
DATUM
-----------
25-dec-2018
09-may-2018
09-may-2018
SQL>
[EDIT]
Oracle doesn't store DATE values in any "human" readable format (there's more to read on the Internet, Google for it). It is a format mask that represents that value to you.
I strongly suggest you NOT to store dates into any datatype column but DATE. It's a time bomb, waiting to explode (and then it'll hurt). Nobody stops you from entering a value as '1234-99-66' or '12-345-678'; what will you do with it, then?
Consider creating a view on a top of the table which uses TO_CHAR function and returns the value in a format you want ('yyyy-mm-dd'). DATE datatype column in a table makes sure that values are valid, and the view will let the third-party application to accept values it finds appropriate.
For example:
SQL> create view v_test as
2 select to_char(datum, 'yyyy-mm-dd') datum
3 from test;
View created.
SQL> select * from v_test;
DATUM
----------
2018-12-25
2018-05-09
2018-05-09
SQL>
So: you wouldn't let the third-party application to access the table, but the view instead.

When or Why to use a "SET DEFINE OFF" in Oracle Database

I'm watching a Script in Oracle and I see something I don't recognize
REM INSERTING into database1."Users"
SET DEFINE OFF;
Insert into database1."Users" ("id","right") values ('1','R');
I'm looking for documentation about "set define off" and it's literally writing "disable the parsing of commands to replace substitution variable with their values"
I don't really understand what they want to say.
Can anyone help me?
By default, SQL Plus treats '&' as a special character that begins a substitution string. This can cause problems when running scripts that happen to include '&' for other reasons:
SQL> insert into customers (customer_name) values ('Marks & Spencers Ltd');
Enter value for spencers:
old 1: insert into customers (customer_name) values ('Marks & Spencers Ltd')
new 1: insert into customers (customer_name) values ('Marks Ltd')
1 row created.
SQL> select customer_name from customers;
CUSTOMER_NAME
------------------------------
Marks Ltd
If you know your script includes (or may include) data containing '&' characters, and you do not want the substitution behaviour as above, then use set define off to switch off the behaviour while running the script:
SQL> set define off
SQL> insert into customers (customer_name) values ('Marks & Spencers Ltd');
1 row created.
SQL> select customer_name from customers;
CUSTOMER_NAME
------------------------------
Marks & Spencers Ltd
You might want to add set define on at the end of the script to restore the default behaviour.
Here is the example:
SQL> set define off;
SQL> select * from dual where dummy='&var';
no rows selected
SQL> set define on
SQL> /
Enter value for var: X
old 1: select * from dual where dummy='&var'
new 1: select * from dual where dummy='X'
D
-
X
With set define off, it took a row with &var value, prompted a user to enter a value for it and replaced &var with the entered value (in this case, X).

Inserting date as dd-mon-yy in oracle

I am trying to insert date value as dd-mon-yy but the database is storing it as dd/mm/yy.
For example: INSERT INTO tablename VALUES (to_date('01-mar-09', 'dd-mon-yy');
The DB stores it as 01/03/09. Why is that? Whay can't I just store it as 01-mar-09?
Please help.
Date is a raw datatype. It doesn't have a format to be saved. It's upto you or the environment/session to decide how to display it.. use NLS_DATE_FORMAT parameter as required... using alter session or use to_char() function
alter session set nls_date_format = 'DD-MON-YY';
select sysdate from dual;
28-OCT-15
alter session set nls_date_format = 'MM/DD/YY';
select sysdate from dual;
10/28/15
The NLS parameters precedence is decided as below, if not set on session level then use instance level, if not set at instance level then use which is present at database level. Below are the views which provide set values at each level
NLS_SESSION_PARAMETERS => session level parameters
NLS_INSTANCE_PARAMETERS => instance level parameters
NLS_DATABASE_PARAMETERS => database level parameters
Oracle doesn't store a date as any format .. it just stores "a date". you are viewing it/displaying it as a different format. Check your nls_date settings.
SQL> select sysdate from dual;
SYSDATE
---------
28-OCT-15
SQL> alter session set nls_date_format='dd-mon-yyyy hh24:mi:ss'
Session altered.
SQL> select sysdate from dual;
SYSDATE
--------------------
28-oct-2015 11:00:56
SQL>

OCI: Determine length of text representation of query columns

My goal is to execute a query (SELECT), fetch results and output them as text. Query is given as a parameter and can be e.g. select * from t.
I use OCIStmtPrepare and OCIStmtExecute, then I can describe columns of the query by OCIParamGet and series of OCIAttrGet. Suppose I get OCI_ATTR_DATA_TYPE = 12 (DATE) for one of the columns. Then OCI_ATTR_DATA_SIZE = 7 -- this is size of internal DATE representation.
I want to get this DATE as text, with respect to currect NLS settings. For that I use OCIDefineByPos with dty = SQLT_STR. It works alright, but I also need to supply a buffer for fetching. The question is: what size of buffer do I need?
Evidently it depends on NLS_DATE_FORMAT. I believe that Oracle knows this value:
SQL> create table x as select to_char(sysdate) d from dual;
Table created.
SQL> select value from nls_session_parameters where parameter='NLS_DATE_FORMAT';
VALUE
----------------------------------------
DD.MM.RR
SQL> select data_length from dba_tab_columns where table_name='X';
DATA_LENGTH
-----------
8
This is the exact length. Only when date format is masked from Oracle (by a function, for example), it uses absolute maximum (?) value of 75:
SQL> create or replace function get_date_format return varchar2 is
2 begin
3 return 'DD.MM.RR';
4 end;
5 /
Function created.
SQL> create table x as select to_char(sysdate,get_date_format) d from dual;
Table created.
SQL> select data_length from dba_tab_columns where table_name='X';
DATA_LENGTH
-----------
75
All said above applies to NUMBER as well.
So, is it possible to get length of text representation of a column in OCI?
The maximum buffer size for any date is 75. The maximum buffer size for any number is 42.
I hope that helps.
You can determine needed buffer size by calling OCIAttrGet for OCI_ATTR_DISP_SIZE attribute. It returns 40 for NUMBER, 75 for DATE, N for VARCHAR2(N). Add 1 byte for Null-termination and you good to go.
Yes - the trick is that in C, a string is really a pointer to a character array, so you would say char* mystring = OCIStringPtr(envhp, x); where x is a pointer to an OCIString, which you can get back by connecting with OCI_OBJECT set and asking for a SQLT_VST instead of an SQLT_STR. The actual memory for the string is allocated for you in the global env by OCI behind the scenes.

A useful example of when to use vsize function instead of length function in Oracle?

It seems vsize() and length() return the same results. Does anyone know of a practical example of when to use vsize instead of length?
select vsize(object_name), length(object_name) from user_objects
Result:
/468ba408_LDAPHelper 20 20
/de807749_LDAPHelper 20 20
A4201_A4201_UK 14 14
A4201_PGM_FK_I 14 14
A4201_PHC_FK_I 14 14
Well, Length() takes a character argument (CHAR, VARCHAR2, NCHAR, NVARCHAR2, CLOB, or NCLOB) whereas VSize() takes just about any data type, so if you pass Length() a noncharacter data type there has to be an implicit conversion.
Length is also sensitive to to character sets.
drop table daa_test;
create table daa_test as select sysdate dt from dual;
alter session set nls_date_format = 'YYYY-MM-DD';
select vsize(dt) from daa_test;
select length(dt) from daa_test;
alter session set nls_date_format = 'YYYY-MM-DD HH24:mi:ss';
select vsize(dt) from daa_test;
select length(dt) from daa_test;
... giving ...
drop table daa_test succeeded.
create table succeeded.
alter session set succeeded.
VSIZE(DT)
----------------------
7
1 rows selected
LENGTH(DT)
----------------------
10
1 rows selected
alter session set succeeded.
VSIZE(DT)
----------------------
7
1 rows selected
LENGTH(DT)
----------------------
19
1 rows selected
VSize is really of use IMHO in understanding internal storage requirements of data.
see: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1897591221788

Resources