Creating a DB2 sequence with a specific START WITH value - db2

In Oracle we can do it like this:
declare current_max_value NUMBER;
begin select last_number+1 into current_max_value from USER_SEQUENCES where sequence_name = 'HIBERNATE_SEQUENCE';
execute immediate 'CREATE SEQUENCE SEQ__NEW_SEQUENCE MINVALUE 1 MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH '||current_max_value|| ' CACHE 20 NOORDER NOCYCLE';
Is there a DB2 equivalent?

DB2 has vaugely equivalent functionality.
If you just need to generate uninque keys then:-
CREATE TABLE MYTABLE (
GENERATED_KEY BIGINT
GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1, CACHE 100),
MY_DATA VARCHAR(1000) ...........
On the create table statement will accomplish this without too much fuss. Anytime a null value is encountered on an insert an new number will be generated.
If you need an actual sequence number to be used over several tables then:
CREATE SEQUENCE ORG_SEQ
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO CYCLE
CACHE 24
will define a sequence you then use the "NEXTVAL" keyword anywhere you want the next number in you sql:
NEXTVAL FOR ORG_SEQ

After a great difficulty I was able to figure this out with DB2 syntax and here we go
CREATE PROCEDURE SEQ_NAME
LANGUAGE SQL
DYNAMIC RESULT SETS 1
BEGIN ATOMIC
DECLARE MAX_VAL_NO INTEGER;
SELECT MAX(COL_NAME)+1 INTO MAX_VAL_NO FROM TABLE_NAME;
execute immediate 'CREATE SEQUENCE SEQ_NAME NO MAXVALUE NO CYCLE START WITH '|| MAX_VAL_NO;
END
GO
Could any one tell me why should we use LANGUAGE SQL and DYNAMIC RESULT SETS 1
And what is the syntax used here, frankly speaking I really dont have an Idea but I hit it through trial and error method. Eagerly waiting to know what is the syntax is it either ANSI C or some other.
Appreciate if you could answer this. Also provide some links for good study.(Not regular IBM links)

Related

What is the error type when PostgreSQL exhausts a sequence?

I want to generate primary keys within my database using a PostgreSQL sequence. Rather than having one big sequence, it's broken up into little chunks (key series) though (this has to do with clients working offline and syncing their work later).
I have written a table that holds the next key series to be issued and a function that will issue a new series and update the key sequence. I'm now making a trigger to attach primary keys to inserted rows if none is already set.
How can I catch when the key sequence is exhausted? What exception do I need to catch? I want to do something like this:
create or replace function generate_key() returns trigger as
$$
begin
if new._id is null then
begin
new._id = nextval(key_sequence);
exception when SEQUENCE_EXHAUSTED then
perform update_key_sequence();
new._id = nextval(key_sequence);
end;
end if;
return new;
end;
$$
language plpgsql;
I've googled unsuccessfully and tried it out on a mini sequence, but all that did was give an unspecific "Error"
Pretty easy to test this out by starting a sequence at the maximum value of a 64-bit signed integer:
regress=> CREATE SEQUENCE xx START WITH 9223372036854775807;
CREATE SEQUENCE
regress=> \set verbosity verbose
regress=> SELECT nextval('xx');
nextval
---------------------
9223372036854775807
(1 row)
regress=> SELECT nextval('xx');
ERROR: 55000: nextval: reached maximum value of sequence "xx" (9223372036854775807)
LOCATION: nextval_internal, sequence.c:644
so, SQLSTATE 55000, which is object_not_in_prerequisite_state. Perhaps not the most useful error in the world.
The same error is raised with an explicit MAXVALUE for the sequence, again easily tested.
I would say sqlstate 55000 object_not_in_prerequisite_state
Tried on 9.2:
CREATE SEQUENCE "seq_try_max_100"
INCREMENT BY 10
MAXVALUE 100
START WITH 99 NO CYCLE;
SELECT nextval('seq_try_max_100');
SELECT nextval('seq_try_max_100');
-- shows:
ERROR: nextval: reached maximum value of sequence "seq_try_max_100" (100)
SQL state: 55000
CREATE SEQUENCE "seq_try_no_max"
INCREMENT BY 5000000000000000000
START WITH 5000000000000000000 NO CYCLE;
SELECT nextval('seq_try_no_max');
SELECT nextval('seq_try_no_max');
-- shows:
ERROR: nextval: reached maximum value of sequence "seq_try_no_max" (9223372036854775807)
SQL state: 55000
Since Postgres 10, the error code in this scenario has been changed to the more informative 2200H: sequence_generator_limit_exceeded.
mydb=> \set VERBOSITY verbose
mydb=> INSERT INTO test_table VALUES ('x');
ERROR: 2200H: nextval: reached maximum value of sequence "test_id_seq" (4)
LOCATION: nextval_internal, sequence.c:707

PLS-00357 sequence.nextval not allowed

I'm trying to create a trigger and am getting the error "[Error] PLS-00357: PLS-00357: Table, View Or Sequence reference 'table_data_seq.nextval' not allowed in this context"
I have read a lot of information on the error and cannot find the difference between the PL/SQL that people say works and mine. Below is my code for creating the trigger ( keeping it as basic as possible to get it working ):
create or replace trigger tr_tabData
before insert on table_data
for each row
DECLARE
seq_value int;
begin
select table_data_sq.nextval into seq_value from dual;
end;
Oracle version is 10.2.0.5
As requested here it the script for the sequence:
DROP SEQUENCE DATA_ADMIN.TABLE_DATA_SQ;
CREATE SEQUENCE DATA_ADMIN.TABLE_DATA_SQ
START WITH 1000
MAXVALUE 999999999999999999999999999
MINVALUE 1
NOCYCLE
CACHE 20
NOORDER;
This is not possible before 11g. You can use sequence_name.NEXTVAL in regular assignments from 11g not before that, and that by the following:
select TABLE_DATA_SQ.NEXTVAL into :NEW.YourID from dual;
It turned out that this was a bug with the TOAD version and my Oracle database version. The same code in SQL*Plus and SQL Developer worked as expected.

How can I generate a unique string per record in a table in Postgres?

Say I have a table like posts, which has typical columns like id, body, created_at. I'd like to generate a unique string with the creation of each post, for use in something like a url shortener. So maybe a 10-character alphanumeric string. It needs to be unique within the table, just like a primary key.
Ideally there would be a way for Postgres to handle both of these concerns:
generate the string
ensure its uniqueness
And they must go hand-in-hand, because my goal is to not have to worry about any uniqueness-enforcing code in my application.
I don't claim the following is efficient, but it is how we have done this sort of thing in the past.
CREATE FUNCTION make_uid() RETURNS text AS $$
DECLARE
new_uid text;
done bool;
BEGIN
done := false;
WHILE NOT done LOOP
new_uid := md5(''||now()::text||random()::text);
done := NOT exists(SELECT 1 FROM my_table WHERE uid=new_uid);
END LOOP;
RETURN new_uid;
END;
$$ LANGUAGE PLPGSQL VOLATILE;
make_uid() can be used as the default for a column in my_table. Something like:
ALTER TABLE my_table ADD COLUMN uid text NOT NULL DEFAULT make_uid();
md5(''||now()::text||random()::text) can be adjusted to taste. You could consider encode(...,'base64') except some of the characters used in base-64 are not URL friendly.
All existing answers are WRONG because they are based on SELECT while generating unique index per table record. Let us assume that we need unique code per record while inserting: Imagine two concurrent INSERTs are happening same time by miracle (which happens very often than you think) for both inserts same code was generated because at the moment of SELECT that code did not exist in table. One instance will INSERT and other will fail.
First let us create table with code field and add unique index
CREATE TABLE my_table
(
code TEXT NOT NULL
);
CREATE UNIQUE INDEX ON my_table (lower(code));
Then we should have function or procedure (you can use code inside for trigger also) where we 1. generate new code, 2. try to insert new record with new code and 3. if insert fails try again from step 1
CREATE OR REPLACE PROCEDURE my_table_insert()
AS $$
DECLARE
new_code TEXT;
BEGIN
LOOP
new_code := LOWER(SUBSTRING(MD5(''||NOW()::TEXT||RANDOM()::TEXT) FOR 8));
BEGIN
INSERT INTO my_table (code) VALUES (new_code);
EXIT;
EXCEPTION WHEN unique_violation THEN
END;
END LOOP;
END;
$$ LANGUAGE PLPGSQL;
This is guaranteed error free solution not like other solutions on this thread
Use a Feistel network. This technique works efficiently to generate unique random-looking strings in constant time without any collision.
For a version with about 2 billion possible strings (2^31) of 6 letters, see this answer.
For a 63 bits version based on bigint (9223372036854775808 distinct possible values), see this other answer.
You may change the round function as explained in the first answer to introduce a secret element to have your own series of strings (not guessable).
The easiest way probably to use the sequence to guarantee uniqueness
(so after the seq add a fix x digit random number):
CREATE SEQUENCE test_seq;
CREATE TABLE test_table (
id bigint NOT NULL DEFAULT (nextval('test_seq')::text || (LPAD(floor(random()*100000000)::text, 8, '0')))::bigint,
txt TEXT
);
insert into test_table (txt) values ('1');
insert into test_table (txt) values ('2');
select id, txt from test_table;
However this will waste a huge amount of records. (Note: the max bigInt is 9223372036854775807 if you use 8 digit random number at the end, you can only have 922337203 records. Thou 8 digit is probably not necessary. Also check the max number for your programming environment!)
Alternatively you can use varchar for the id and even convert the above number with to_hex() or change to base36 like below (but for base36, try to not expose it to customer, in order to avoid some funny string showing up!):
PostgreSQL: Is there a function that will convert a base-10 int into a base-36 string?
Check out a blog by Bruce. This gets you part way there. You will have to make sure it doesn't already exist. Maybe concat the primary key to it?
Generating Random Data Via Sql
"Ever need to generate random data? You can easily do it in client applications and server-side functions, but it is possible to generate random data in sql. The following query generates five lines of 40-character-length lowercase alphabetic strings:"
SELECT
(
SELECT string_agg(x, '')
FROM (
SELECT chr(ascii('a') + floor(random() * 26)::integer)
FROM generate_series(1, 40 + b * 0)
) AS y(x)
)
FROM generate_series(1,5) as a(b);
Use primary key in your data. If you really need alphanumeric unique string, you can use base-36 encoding. In PostgreSQL you can use this function.
Example:
select base36_encode(generate_series(1000000000,1000000010));
GJDGXS
GJDGXT
GJDGXU
GJDGXV
GJDGXW
GJDGXX
GJDGXY
GJDGXZ
GJDGY0
GJDGY1
GJDGY2

Error 28 "Out of Stack Space" executing a huge query with VB6 & ADO 2.8

Scenario:
Executing an SQL command from a Visual Basic 6 application using ADO Connection.Execute method through PostgreSQL OLEDB Provider to a PostgreSQL 9.2 database.
Query:
It's a simple EXECUTE prepared_statement_name (x, y, z), though it involves a PostGIS geometry type, thus it becomes something like:
EXECUTE prepared_statement_name (1, ST_GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 900001));
Problem:
When the geometry is a huge and complex MULTIPOLYGON which contains many vertexes, the query becomes very lengthy (a few thousands characters) and the Connection.Execute method causes a Error 28: "Out Of Stack Space".
There is no recursion or nested loops involved in the process, it's quite clear the error is due to the excessive length of the query.
I think I could avoid the error if I passed the huge query in "chunks" to the provider before executing it, but this is just an idea and I don't know wether it is possible or not and how.
I have no clue, any help is appreciated.
Since it sounds like this is a VB6 level problem and you're already on current Pg versions I fear you may have to use some specacularly ugly workarounds.
If at all possible, try to find a way to increase the VB6 query buffer size, send the query in chunks via the VB6 ODBC interface, etc. Consider the following an absolute last resort.
Maybe this will give you some saner clues. I don't speak VB6 (thankfully) so I can't evaulate it: http://www.mrexcel.com/forum/excel-questions/61340-error-28-out-stack-space.html
Use the following only as a last resort if all else fails:
Create a TEMPORARY table like CREATE TEMPORARY TABLE my_query(id integer, text querychunk).
INSERT INTO the temporary table your statement, chunk by chunk, using parameterised queries to avoid quoting issues.
Create a wrapper PL/PgSQL function that does a RETURN QUERY EXECUTE format('EXECUTE stm_name(...)', passing the string_agg of the temp table as a parameter. Yes, that's amazingly ugly.
Here's a demo, some of the most horrible code I've ever written:
CREATE TABLE real_table (blah text);
PREPARE test_stm2(text) AS INSERT INTO real_table VALUES ($1);
CREATE TEMPORARY TABLE data_chunks(datord integer, datchunk text);
PREPARE chunk_insert(integer, text) AS INSERT INTO data_chunks(datord,datchunk) VALUES ($1,$2);
-- You'll really want to do this via proper parameterised statements
-- to avoid quoting nightmares; I'm using dollar-quoting as a workaround
EXECUTE chunk_insert(0, $val$POLYGON((0 0, 0 1, 1 1,$val$);
EXECUTE chunk_insert(1, $val$ 1, 1 0, 0 0))$val$);
DO
$$
BEGIN
EXECUTE 'EXECUTE test_stm2($1);'
USING
(SELECT string_agg(datchunk,'' ORDER BY datord) FROM data_chunks);
END;
$$ LANGUAGE plpgsql;
Result:
regress=> SELECT * FROM real_table ;
blah
---------------------------------------
POLYGON((0 0, 0 1, 1 1, 1, 1 0, 0 0))
(1 row)
A similar approach is possible for SELECT. You'd use RETURN QUERY EXECUTE within a function defined by CREATE OR REPLACE FUNCTION since DO blocks can't return a result. For example, for a query that returns a SETOF INTEGER you might write:
CREATE OR REPLACE FUNCTION test_wrapper_func() RETURNS SETOF integer AS $$
BEGIN
RETURN QUERY EXECUTE format('EXECUTE test_stm(%L);', (SELECT string_agg(datchunk,'' ORDER BY datord) FROM data_chunks));
END;
$$ LANGUAGE plpgsql;
You'll note the two-level EXECUTE. That's because the PL/PgSQL EXECUTE is quite a different statement to SQL-level EXECUTE. PL/PgSQL EXECUTE runs a string as dynamic SQL, wheras the SQL EXECUTE runs a prepared statement. Here we're running a prepared statement via dynamic SQL. Ick.
Wondering why I'm using PL/PgSQL? Because you can't use a subquery as an EXECUTE parameter. You can avoid the PL/PgSQL wrapper for the query if you don't run it as a prepared statement.
regress=> EXECUTE test_stm2( (SELECT string_agg(datchunk,'' ORDER BY datord) FROM data_chunks) );
ERROR: cannot use subquery in EXECUTE parameter

Updating generator value issue

I'm currently working on modifying a Firebird v. 1.5 database.
The database structure will be modified running queries from a delphi application using interbase components, the problem I'm facing is that I need to run a lot of queries, some of which include creating generators and updating the generator value, the problem is that I need to achieve this in as few queries as possible, but it seems(at least to me) that this is not really possible, what I'm trying to do is the following:
/* this command creates a generator to be used for table TABLENAME */
CREATE GENERATOR GEN_TABLENAME;
So I've created a generator, now I need to set it's value at the current max id from table TABLENAME, like so:
/* one would expect that the following command would work, well it doesn't */
SET GENERATOR GEN_TABLENAME TO (SELECT MAX(ID) FROM TABLENAME);
Now, is there any workaround for this, or am I forced to:
create the generator
get the max id
update the generator value
and repeat process for every table?
I also expected that
SELECT
SELECT MAX(ID) AS ID_TABLENAME_1 FROM TABLENAME_1,
...
SELECT MAX(ID) AS ID_TABLENAME_N FROM TABLENAME_N
would be a workaround to get the max id's from every table in one command, but it doesn't.
Statement
SET GENERATOR GEN_TABLENAME TO (SELECT MAX(ID) FROM TABLENAME);
mixes DDL (SET GENERATOR) and DML (SELECT), AFAIK this is not generally supported and Firebird doesn't support it for sure.
If you can upgrade to the latest version of Firebird then you could use EXECUTE BLOCK and / or EXECUTE STATEMENT to do it all "in one statement" and server side, but with Firebird 1.5 you have to settle for the long way (one statement to get the current max, then another one update the generator).
With the following trick you can set the generator value to the maximum ID value of a table with one SQL statement in Firebird:
SELECT GEN_ID( GEN_TABLENAME,
(SELECT MAX(ID) FROM TABLENAME) - GEN_ID(GEN_TABLENAME, 0)) FROM RDB$DATABASE;
That works, because GEN_ID( <GeneratorName>, <increment>) gets the generator value and increments it by <increment>. This should work in Firebird 1.5 as well as in newer versions.
You could create a stored procedure and call it from Delphi:
create procedure update_generators
as
declare variable max_id integer;
declare variable table_name char(31);
declare variable generator_name char(31);
begin
/* assuming generator naming convention GEN_XXX -> table name XXX */
for select
trim(g.rdb$generator_name),
substring(trim(g.rdb$generator_name) from 5)
from rdb$generators g
where (coalesce(g.rdb$system_flag, 0) = 0)
into
:generator_name,
:table_name
do
begin
/* assuming that the field name is always ID */
execute statement 'select max(id) from ' || :table_name into :max_id;
execute statement 'set generator ' || :generator_name || ' to ' || :max_id;
end
end^
It looks like execute statement is supported by Firebird 1.5 already.
In Firebird 2.0 and later, you could also wrap the code in a execute block and avoid creating a stored procedure.