Does DB2 Luw support CHAR semantic? - sqldatatypes

Oracle supports Byte and Char Semantic when creating table
Create table test(n varchar2(10 byte);
Create table test(n varchar2(10 char);
Does DB2 Luw support the second create statement with char Semantic?
What can we do in DB2 Luw if we know that some values in the column n may require more than one byte and i don't want to use nvarchar?

Currently supported versions of Db2-LUW when correctly configured to emulate Oracle will then accept the syntax:
Create table test(n varchar2(10 byte);
and
Create table test(n varchar2(10 char);
By default, Db2-LUW installations will not enable Oracle compatibility, but you can change this by following the documentation.
Remember that a new database has to be created after you set the registry variable DB2_COMPATIBILITY_VECTOR according to your needs. This configuration activity is normally done by a DBA.
If your Db2-database does not support this syntax, then Db2-LUW will report the error SQL0104N when you try to use Oracle syntax.

Related

SQL Plus converting Char to Byte for Oracle Copy Command

In Oracle SQL Plus, using Copy command while creating table/inserting record always converting Table CHAR /VARCHAR2 Columns to BYTE format and causing issue in length mismatch, so im not able to re copy to my original tables.
Tried below setting in SESSION and sqlnet.ora, but no help
ALTER SESSION SET NLS_LENGTH_SEMANTICS = CHAR;
connected.
SQL> DESC DDD1;
Name Null? Type
----------------------------------------- -------- ----------------------------
ROW_ID NOT NULL VARCHAR2(15 CHAR)
PRIV_FLG NOT NULL CHAR(1 CHAR)
SQL> COPY TO USER/PASS#DB CREATE DDD12 USING SELECT * FROM DDD1;
Array fetch/bind size is 15. (arraysize is 15)
Will commit when done. (copycommit is 0)
Maximum long size is 80. (long is 80)
Table DDD12 created.
5036 rows selected from DEFAULT HOST connection.
5036 rows inserted into DDD12.
5036 rows committed into DDD12 at USER/PASS#DB.
SQL> DESC DDD12;
Name Null? Type
----------------------------------------- -------- ----------------------------
ROW_ID NOT NULL VARCHAR2(60)
PRIV_FLG NOT NULL CHAR(4)
Actual should be replica of DDD1 Table.
The documentation for the COPY command says:
The COPY command is not being enhanced to handle datatypes or features introduced with, or after Oracle8i. The COPY command is likely to be made obsolete in a future release.
Character length semantics were introduced in Oracle 9i:
Oracle9i introduces character semantics. It is useful for defining the storage ...
So while it's maybe a bit disappointing, it maybe isn't surprising that COPY doesn't honour that 'new' feature; and it isn't something they're likely to add in now. You are creating a new connection/session to the remote DB, and that new session would have to have the alter session re-issued after the connection is made. As that isn't happening it's defaulting to the target's database initialisation parameter value, which is BYTE.
It's perhaps slightly more surprising that SQL Developer does apparently re-issue that alter session. Perhaps more usefully for you, if you want to use a command-line tool for this instead of a GUI, so does SQLcl. You'll have to use one of those rather than SQL*Plus if you want to utilise that command and preserve the source semantics.
Another option may be to start from your current target database, set the session parameter there, and copy from the current source database instead. Or, if you can't do that, you could perhaps have a DB trigger that issues an alter session, but that's probably getting a bit to complicated now...
It's also worth noting MoS document ID 2914.1 "Common SQL*Plus Questions and Answers" which says:
Q: What is the purpose of the COPY command ?
A: Copy command in SQL*Plus is useful when you want to transfer data between Oracle and NON-Oracle databases. If you want to copy Oracle table to another Oracle table, use "create table .. as select .." or "create table, insert into .. select .." statements. Columns may lose precision if you copy from Oracle rdbms to Oracle rdbms.
While that doesn't really give an alternative for copy to another database, you could use a database link; or export/import.

How to change size of varchar2 column of an Oracle database in liquibase

I have a simple need to increase the size of a VARCHAR2 column in an Oracle DB from VARCHAR2(20 CHAR) to VARCHAR2(35 CHAR).
The database is used by an existing application with production data though I will start with DEV first (of course).
You want to use the Liquibase refactoring "modifyDataType", which is documented here: http://www.liquibase.org/documentation/changes/modify_data_type.html
Here is an example:
<changeSet author="liquibase-docs" id="modifyDataType-example">
<modifyDataType
columnName="CODE"
newDataType="varchar2(35 char)"
tableName="PCF_PROGRAMME"/>
</changeSet>

Pass reference type across a DB Link

Am trying to pass a reference type over a DB link, but am getting an error telling me its an illegal reference to the DB link in the procedure. I have specified it in the body and spec of the package and am not sure how to resolve it after searching for a solution. Am using oracle 10g for that reference type to an 11g oracle DB.
Version:
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0
Oracle Database 10g Enterprise Edition Release 10.2.0.5.0
[Error] PLS-00331 (13: 43): PLS-00331: illegal reference to test.DATA_T#TESTDB('PARAMETERS')
And it seems to be an issue here in the spec of the package:
PROCEDURE SendCollection(o_data IN OUT data_t#TESTDB,
o_seq IN OUT seq_t#TESTDB,
i_flag IN CHAR);
I thought the above was correct, any pointers and advice would be welcome
The thread is still open so I will answer for whoever might need help later on.
If you want to pass an object, then that is forbidden by Oracle according to Oracle docs: Restriction on Using User-Defined Types with a Remote Database:
Objects or user-defined types (specifically, types declared with a SQL CREATE TYPE statement, as opposed to types declared within a PL/SQL package) are currently useful only within a single database.
However, you can send record or table types via DB link, but you will have to:
Either assign them an OID and create them with the same OID on both databases:
-- Obtain an OID
SELECT SYS_OP_GUID() FROM DUAL;
-- Result
SYS_OP_GUID()
----------------
D38A360CF86C41618DC2C40B551214C3
-- Create your type
create or replace type MY_TAB oid 'E8892B5D76E7419A951AEBA63A7AB3BF' as table of varchar2(50);
Or put them in a package on the remote database:
-- Create a DB link API package
create or replace package DBLINK_API as
type MY_TAB is table of varchar2(50);
end DBLINK_API;
-- And a function that uses that type
create or replace function getCount(myPar DBLINK_API.MY_TAB) return number is
begin
return myPar.count;
end getCount;
After that you can use it from your database. First let's create some test table with data.
create table TEST_TABLE
(
ID varchar2(50) not null
);
insert into TEST_TABLE values('Value 1');
insert into TEST_TABLE values('Value 2');
insert into TEST_TABLE values('Value 3');
insert into TEST_TABLE values('Value 4');
insert into TEST_TABLE values('Value 5');
And then finally use the local table to send a table of IDs to the remote function, that is very useful for counting for us:
declare
vals DBLINK_API.MY_TAB#MY_DBLINK;
begin
select ID bulk collect
into vals
from TEST_TABLE;
DBMS_OUTPUT.put_line(getCount#MY_DBLINK(vals));
end;
It looks like an overkill in this example and you may prefer to do the select from the TEST_TABLE in the remote procedure using a DB link to your database instead. I am not sure how would performance be affected, perhaps this approach would be better for larger tables or slow selects, but it would have the same result.
References to remote types are not allowed. The documentation implies this is not possible but is not 100% clear on the point.
(Using community wiki since this answer is a summary of the comments.)
Update: Remote Database Object References (works)
Oracle is terrible with some of their documentation. Sometimes one has to try it to really be sure. A Working Solution:
DECLARE
v_rec_sample sample_table#remotedb%ROWTYPE;
BEGIN
select *
into v_rec_sample
from doj_crime#remotedb
where rownum = 1;
dbms_output.put_line(v_rec_sample.crime_detail);
dbms_output.put_line(v_rec_sample.location);
END;
It works. One can use a dblink and a remotely defined object to create data type definitions on locally declared variables and collections.

Does Firebird Database support Schema? If so, how can I create a schema in Firebird DB through ISQL?

Does Firebird Database support Schema? If so, how can I create a schema in Firebird DB through ISQL? Please help me to create schemas in Firebird DB. I have tried to retrieve schema using
AbstractDatabaseMetaData.getSchemas()
But it is always retrieving empty resultset. Can anyone please help me in retrieving schemas? At least SYSTEM schema when there is no schema.
Firebird currently doesn't have schemas, and therefor Jaybird doesn't return any. This complies with the JDBC specification, which says:
If a given form of metadata is not available, an empty ResultSet will be returned.
Note that Firebird does have a CREATE SCHEMA, but that is simply an alias for CREATE DATABASE.
No, schema not supported, but you can create many databases files. Here manual for create database with Firebird tool. Also you can create database with IBExpert or similar tool.
Also, you can create sql-cript for automate it:
$ isql -q -i create-db.sql
Also you can run it from java code.
--Contents of create-db.sql
CREATE DATABASE '/my/path/my-db.fdb' page_size 8192 USER 'SYSDBA' PASSWORD 'masterkey';
CREATE EXCEPTION EX_SOME_EXCEPTION 'Some extension message';
CREATE TABLE ROOMS (
ID integer NOT NULL PRIMARY KEY,
Number char(10),
Name char(100),
Network char(100),
Memo char(100)
);
CREATE GENERATOR ROOMS_IDGEN;
SET TERM !! ;
CREATE TRIGGER ON_ROOMS_INS FOR ROOMS BEFORE INSERT AS
BEGIN
IF (NEW.ID IS NULL) THEN NEW.ID=GEN_ID(ROOMS_IDGEN, 1);
END !!
SET TERM ; !!
....

Standardized way of AUTO_INCREMENT

Is there a standardized way I can create a table in SQL with a column (lets call it ID) that is auto incremental so that I can basically use it in all databases?
(e.g. standardized in SQL-92)
If so - how? If not, why? I think auto_increment is a very often used property so I thought it would be very important to standardize it…
Nope, sorry. There is AUTO_INCREMENT in MySQL, but e.g. in MS SQL this is called IDENTITY and SERIAL in PGSQL. Many things are not really standardized in SQL - and most are in the schema creating area.
It's a mess, but you can use stuff like e.g. Hibernate/NHibernate to try to use a single code base.
Update: Few year later there is a more standard way that some DBMS support (e.g. PG SQL from version 10.0, so from October 2017):
GENERATED BY DEFAULT AS IDENTITY -- the value has a default auto incrementation, but you can insert your own.
GENERATED ALWAYS AS IDENTITY -- forbids inserting own values (in a standard query, might be overriden)
This is something that should work in PG SQL 10+, DB2, Oracle:
DROP TABLE IF EXISTS simple_test;
CREATE TABLE simple_test(
s_id int PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
);
Note however that this will not work in Microsoft SQL Server (not even in MS SQL Server 2022). MSSQL does not support the generated keyword. MySQL/MariaDb has generated columns, but MariaDb does not support the identity syntax.
So yeah, 10 years later the answer is kind of the same really -- it is still a mess and you should probably use a framework for that.
You can use so-called identity columns:
CREATE TABLE foo(id int GENERATED ALWAYS AS IDENTITY);
This is in the SQL standard and should be supported by PostgreSQL 10 and Oracle:
https://www.2ndquadrant.com/en/blog/postgresql-10-identity-columns/#comment-248607
In Oracle you need to create a SEQUENCE
SQLite uses it for rowid and a synonym of it e.g. RowIdSyn INTEGER PRIMARY KEY AUTOINCREMENT