Is there an easy way to create auto increment field using Firebird? I have installed the FlameRobin admin tool, but the process of creating an auto increment field through the tool is complex. Can I not create such an identity field just by clicking a checkbox or using some other tool other than Flamerobin?
Firebird 3 and later
In Firebird 3 it is easy to create, as it introduced identity columns. In practice it is syntactic sugar for generating a sequence + trigger (as shown for Firebird 2.5) for you.
For example
create table t1 (
id integer generated by default as identity primary key
)
Firebird 3 only supports "generated by default", which means users are able to specify their own id values (which might lead to duplicate value errors); "generated always" has been added in Firebird 4.
See also the Firebird 3 release notes, section "Identity Column Type", and the Firebird 4.0 Language Reference, section "Identity Columns (Autoincrement)".
Firebird 2.5 and earlier
Firebird 2.5 and earlier do not have auto-increment fields. You need to create them yourself with a sequence (aka generator) and a trigger.
Sequence is the SQL standard term and generator is the historical Firebird term; both terms are available in the Firebird DDL syntax.
To create a sequence:
CREATE SEQUENCE t1_id_sequence;
To create a trigger to always generate the id on a table T1 with primary key ID:
set term !! ;
CREATE TRIGGER T1_AUTOINCREMENT FOR T1
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
NEW.ID = next value for t1_id_sequence;
END!!
set term ; !!
See also: How to create an autoincrement column?
Using FlameRobin
FlameRobin also provides tooling to create a sequence + trigger for you. If you have an existing table, you can follow these steps:
Open the table properties:
Open the column properties of the primary key column
Default column properties, select new generator and create trigger:
Generator (sequence) and trigger code generated by FlameRobin. Note that contrary to my example above this trigger allows a user to specify their own id value, with some logic to avoid future duplicates. Execute this (and don't forget to commit):
Related
I have an old application I am supporting that uses a Microsoft Access database. The original table design did not add primary keys to every table. I am working on a migration program that among other things is adding and filling in a new primary key field (GUID) when needed.
This is happening in three steps:
Add a new guid field with no constraints
Fill the field with new unique guids
Add the primary key constraints
My problem is setting the unique guids when the table has duplicate rows. Here is my code to set the guids.
Query.SQL.Add('SELECT * FROM ' + TableName);
Query.Open;
while Query.Eof = false do
begin
Query.Edit;
Query.FieldByName(NewPrimaryKeyFieldName).AsGuid := TGuid.NewGuid;
Query.Post;
Query.Next;
end;
FireDac generates an update statement that contains a where clause with all the original fields/values in the row (since there is no unique field for it to use). However, because the rows are complete duplicates the statement still updates two rows.
FireDac correctly errors with this message
Update command updated [2] instead of [1] record.
I can open up the database in Access and delete the duplicate records or assign them a unique guid by editing the table. I would like my conversion tool to automatically do this.
Is there some way to work with these duplicate rows in FireDac? Either to update just one at a time, or to delete just one of them?
In my opinion there is no way to do it with just one SQL Statement.
I would do this:
1. Copy the whole table without duplicates by using a new temp table
SELECT DISTINCT * FROM <TABLENAME>
Add the Keys
Delete old table content and copy new content from new table
Notes:
The DB Should be unavailable for everyone else for that Operation
2. Make BACKUP before
If my Question title is not clear,
Let me details it more:
In my rails application, in local(development) I am using PL-SQL as my databse, and there is a Customer table where the Primary ID starts from 1,2,3.......so on. Till I start using the same database in Local(development) & Production there was no problem in creating customers, so after I started running Local(development) & Production in parallel with same DB many of the time customer creations fails as ID's trying to create as Duplicate. So how can I set in my Local/Production to change the next Index to start with for the ID into another number to avoid this conflict. ?
Eg: I want to continue using(1,2.....etc) the ID in Local & in production I want to set the next Id from 50000 on wards and continuation.
If I understand your question correctly, you have development environment and live environment both linked to the same Database and same table (say the table name is customer_tab, and the primary id column is cus_id).
Although, this is highly not recommended practice, but if you want to have the primary id be in sequence regardless where the insert is coming from (live or dev), then you can use sequence and triggers. That is, insert statement will not insert the primary id, rather it will leave it null. However, on insert, you run the trigger that uses the sequence numbers. Something like this:
/*Create sequence*/
create sequence customer_tab_seq
start with 5000
increment by 1;
/*Create trigger*/
CREATE OR REPLACE TRIGGER customer_tab_tri
BEFORE INSERT ON customer_tab
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN
IF INSERTING THEN
IF :NEW.cus_id IS NULL THEN
SELECT customer_tab_seq.NEXTVAL INTO :NEW.cus_id FROM DUAL;
END IF;
END IF;
END;
/
In this case, first row inserted will be given 5000 (regardless if it is from live or dev), the second will be given 5001 (regardless if it is from live or dev). And it will save you future conflicts.
In my iOS app,I want to change the column data type in database.
ALTER TABLE XXX ALTER COLUMN myColumn INT.
I always get 'near ALTER Syntax error'
How to resolve the problem?
Thanks for your help.
You cannot change the column type. You can create a new table, using the correct data type for the column this time, and then select data from the old table and insert it into the new table. The full procedure is outlined in the ALTER TABLE documentation:
Remember the format of all indexes and triggers associated with table X. This information will be needed in step 7 below. One way to do this is to run a query like the following: SELECT type, sql FROM sqlite_master WHERE tbl_name='X'.
Use CREATE TABLE to construct a new table "new_X" that is in the desired revised format of table X. Make sure that the name "new_X" does not collide with any existing table name, of course.
Transfer content from X into new_X using a statement like: INSERT INTO new_X SELECT ... FROM X.
If foreign key constraints are enabled, disable them using PRAGMA foreign_keys=OFF.
Drop the old table X: DROP TABLE X.
Change the name of new_X to X using: ALTER TABLE new_X RENAME TO X.
Use CREATE INDEX and CREATE TRIGGER to reconstruct indexes and triggers associated with table X. Perhaps use the old format of the triggers and indexes saved from step 1 above as a guide, making changes as appropriate for the alteration.
If foreign key constraints were originally enabled (prior to step 4) then run PRAGMA foreign_key_check to verify that the schema change did not break any foreign key constraints, and run PRAGMA foreign_keys=ON to re-enable foreign key constraints.
If any views refer to table X in a way that is affected by the schema change, then drop those views using DROP VIEW and recreate them with whatever changes are necessary to accommodate the schema change using CREATE VIEW.
Note, SQLite uses type affinity (the column definition doesn't alter what type of data you insert into the table). So if you change the data type, you'll want to change the data, too.
ALTER TABLE table ADD newColumn INTEGER;
UPDATE table SET newColumn = oldColumn;
I'm searching a way to simulate "create table as select" in Firebird from SP.
We are using this statement frequently in another product, because it is very easy for make lesser, indexable sets, and provide very fast results in server side.
create temp table a select * from xxx where ...
create indexes on a ...
create temp table b select * from xxx where ...
create indexes on b ...
select * from a
union
select * from b
Or to avoid the three or more levels in subqueries.
select *
from a where id in (select id
from b
where ... and id in (select id from c where))
The "create table as select" is very good cos it's provide correct field types and names so I don't need to predefine them.
I can simulate "create table as" in Firebird with Delphi as:
Make select with no rows, get the table field types, convert them to create table SQL, run it, and make "insert into temp table " + selectsql with rows (without order by).
It's ok.
But can I create same thing in a common stored procedure which gets a select sql, and creates a new temp table with the result?
So: can I get query result's field types to I can create field creator SQL from them?
I'm just asking if is there a way or not (then I MUST specify the columns).
Executing DDL inside stored procedure is not supported by Firebird. You could do it using EXECUTE STATEMENT but it is not recommended (see the warning in the end of "No data returned" topic).
One way to do have your "temporary sets" would be to use (transaction-level) Global Temporary Table. Create the GTT as part of the database, with correct datatypes but without constraints (those would probably get into way when you fill only some columns, not all) - then each transaction only sees it's own version of the table and data...
I'm using Zeos 7, and Delphi 2009 and want to check to see if a value is already in the database under a specific field before I post the data to the database.
Example: Field Keyword
Values of Cheese, Mouse, Trap
tblkeywordKEYWORD.Value = Cheese
What is wrong with the following? And is there a better way?
zQueryKeyword.SQL.Add('IF NOT EXISTS(Select KEYWORD from KEYWORDLIST ='''+
tblkeywordKEYWORD.Value+''')INSERT into KEYWORDLIST(KEYWORD) VALUES ('''+
tblkeywordKEYWORD.Value+'''))');
zQueryKeyword.ExecSql;
I tried using the unique constraint in IBExpert, but it gives the following error:
Invalid insert or update value(s): object columns are
constrained - no 2 table rows can have duplicate column values.
attempt to store duplicate value (visible to active transactions) in unique index "UNQ1_KEYWORDLIST".
Consider to use UPDATE OR INSERT or MERGE statements:
update or insert into KEYWORDLIST (KEYWORD) values(:KEYWORD) matching(KEYWORD)
For details check the following documents in your Firebird installation folder:
doc\sql.extensions\README.update_or_insert.txt
doc\sql.extensions\README.merge.txt