Is it possible to add an autogenerated primary key column ( timestamp) to the existing table with alter table?
Something like this but it doesn't compile
ALTER TABLE DB2ADMIN.xxxyyyy ADD COLUMN ID TIMESTAMP NOT NULL WITH DEFAULT timestamp(generate_unique())#
Error during Prepare
42601(-104)[IBM][CLI Driver][DB2/AIX64] SQL0104N An unexpected token "timestamp" was found following "OT NULL WITH DEFAULT". Expected tokens may include: "CHECK". SQLSTATE=42601
It is unwise to use a fake (from generate_unique) timestamp datatype as a primary key because it makes setting values for pre-existing rows more awkward, and makes date arithmetic impossible.
The datatype TIMESTAMP is better suited for real dates/times because then you can use date arithmetic, which is practical for business. If the values in your fake timestamp-column are from generate-unique then you cannot sensibly use date arithmetic.
If you try to use a real timestamp value , (instead of generate_unique) , such as current timestamp then you are likely to get collisions, depending on the insert-rate. Usually that's a bad idea. Also this makes setting values for any pre-existing rows more difficult.
It is usually much easier and faster to use an autogenerated identity column as a surrogate primary key, especially if the table already has existing data.
Here is a typical way to do this which works with Db2-LUW and also on older versions of Db2. Other ways are possible with later versions of Db2.
Firs you need to verify that the table does not already have a primary key, as there can only be at most one of these per table.
Next, check if the table already has a unique index on a NOT NULL column, because if such a column exists then it can be promoted to be the primary key column.
If neither of the above exist, then you can use logic like this below to add an autgenerated column, set unique values in any existing rows, and ensure that any future inserts automatically get a unique value in the column without application intervention.
alter table myschema.mytab add column id bigint not null default 0 ;
alter table myschema.mytab alter column id drop default ;
alter table myschema.mytab alter column id set generated always as identity ;
update myschema.mytab set id = default ;
alter table myschema.mytab add constraint pkey primary key(id) ;
reorg table myschema.mytab ;
runstats on table myschema.mytab with distribution and detailed indexes all;
You can use CURRENT_TIMESTAMP instead of timestamp(generate_unique())
ALTER TABLE sellers ADD COLUMN ID TIMESTAMP NOT NULL WITH DEFAULT CURRENT_TIMESTAMP
You can test here
Related
I have the following table in an SQLite database
CREATE TABLE `log` (
`time` REAL NOT NULL DEFAULT CURRENT_TIMESTAMP,
`data` BLOB NOT NULL
) WITHOUT ROWID;
CREATE INDEX `time_index` ON `log`(`time`);
The index is created because the most frequent query is going to be
SELECT * FROM `log` WHERE `time` BETWEEN ? AND ?
Since the time is going to be always the current time when the new record is added, the index is not really required here. So I would like to "tell" the SQLite engine something like "The lines are going to be added with the 'time' column always having increasing value (similar to AUTO_INCREMENT), and if something goes wrong I will take all responsibility".
Is it possible at all?
You don't want a separate index. You want to declare the column to be the primary key:
CREATE TABLE `log` (
`time` REAL NOT NULL DEFAULT CURRENT_TIMESTAMP PRIMARY KEY,
`data` BLOB NOT NULL
) WITHOUT ROWID;
This creates a single b-tree index for the log based on the primary key. In other databases, this structure would be called a "clustered index". You have probably already read the documentation but I'm referencing it anyway.
You would have an issue, or not depending upon how you consider that you cannot use :-
CREATE TABLE `log` (
`time` REAL NOT NULL DEFAULT CURRENT_TIMESTAMP,
`data` BLOB NOT NULL
) WITHOUT ROWID;
because :-
Every WITHOUT ROWID table must have a PRIMARY KEY. An error is raised
if a CREATE TABLE statement with the WITHOUT ROWID clause lacks a
PRIMARY KEY.
Clustered Indexes and the WITHOUT ROWID Optimization
So you might as well make the time column the PRIMARY KEY.
but the problem is that the precision of REAL is not enough to handle
microsecond resolution, and thus two adjacent records may have the
same time value which would violate the PRIMARY KEY constraint.
Then you could use a composite PRIMARY KEY where the precision required is satisfied by multiple columns (a second column would likely more than suffice) perhaps along the lines of :-
CREATE TABLE log (
time_datepart INTEGER,
time_microsecondpart,
data BLOB NOt NULL,
PRIMARY KEY (time_datepart,time_microsecondpart)
) WITHOUT ROWID;
The time_microsecondpart column needn't necessarily be microseconds it could be a counter derived from another table similar to how the sqlite_sequence table is utilised when AUTOINCREMENT is utilised (less the need for the column that holds the name of the table that a row is attached to).
I want to design primary key for my table with row versioning. My table contains 2 main fields : ID and Timestamp, and bunch of other fields. For a unique "ID" , I want to store previous versions of a record. Hence I am creating primary key for the table to be combination of ID and timestamp fields.
Hence to see all the versions of a particular ID, I can give,
Select * from table_name where ID=<ID_value>
To return the most recent version of a ID, I can use
Select * from table_name where ID=<ID_value> ORDER BY timestamp desc
and get the first element.
My question here is, will this query be efficient and run in O(1) instead of scanning the entire table to get all entries matching same ID considering ID field was a part of primary key fields? Ideally to get a result in O(1), I should have provided the entire primary key. If it does need to do entire table scan, then how else can I design my primary key so that I get this request done in O(1)?
Thanks,
Sriram
The canonical reference on this subject is Effective Timestamping in Databases:
https://www.cs.arizona.edu/~rts/pubs/VLDBJ99.pdf
I usually design with a subset of this paper's recommendations, using a table containing a primary key only, with another referencing table that has that key as well change_user, valid_from and valid_until colums with appropriate defaults. This makes referential integrity easy, as well as future value insertion and history retention. Index as appropriate, and consider check constraints or triggers to prevent overlaps and gaps if you expose these fields to the application for direct modification. These have an obvious performance overhead.
We then make a "current values view" which is exposed to developers, and is also insertable via an "instead of" trigger.
It's far easier and better to use the History Table pattern for this.
create table foo (
foo_id int primary key,
name text
);
create table foo_history (
foo_id int,
version int,
name text,
operation char(1) check ( operation in ('u','d') ),
modified_at timestamp,
modified_by text
primary key (foo_id, version)
);
Create a trigger to copy a foo row to foo_history on update or delete.
https://wiki.postgresql.org/wiki/Audit_trigger_91plus for a full example with postgres
I have added a new column, called Ordinal, to a table called Activity. The problem is that I gave it a UNIQUE constraint, set it to allow NULL (though this I won't want in the end.. I just needed to set it to that to get a little farther with the script), and did not give it a default value. I'm now running a RedGate SQL Compare script that was generated by comparing this table to a version of the Activity table that does not have the column. But I'm getting the following error:
The CREATE UNIQUE INDEX statement terminated because a duplicate key was found for the object name 'iwt.Activity' and the index name 'IX_Activity'. The duplicate key value is (1).
So based on my research, it's trying to create a unique key constraint on the Ordinal column, but NULL is not unique. So my next step was to give it a unique value of 1 just to let the script pass. But 1 isn't going to be unique either. So, finally, my question:
Preferably in SQL Server Management Studio, how do I set a column as having a unique default value? Isn't that what I would need to create this constraint?
Thanks.
try this:
NULL will be the first constraint when you create the column.
UNIQUE will be as add constraint, you should add the second constraint.
they can run on this order with no problem (tested):
--first constraint
alter table Table_Name
add Column_Name int null
--second constraint
alter table Table_Name
add constraint Constraint_Name unique (Column_Name)
In my example :
PaymentGatewayHash is column
Cart is a table
--first query
alter table Cart
add PaymentGatewayHash NVARCHAR(20) null
--second query
CREATE UNIQUE INDEX PaymentGatewayHashUnique
ON Cart (PaymentGatewayHash)
WHERE PaymentGatewayHash IS NOT NULL
I just tested that :D
I have a oracle repository up and running and has say 10 million records. One of the table is say
CREATE TABLE TABLE_A
NAME VARCHAR2(128),
VER VARCHAR2(128),
TYPE VARCHAR2(32),
DESCRIPTION VARCHAR2(256),
CONSTRAINT TABLE_A_PK PRIMARY KEY ("NAME","VERSION");
This table is being used for long and now say I have a requirement to change the primary key constraint. Now I have the requirement to have another column say ID and primary key to be combination of NAME, VER, TYPE and LANG.
In the upgrade script I can have something like
EXECUTE IMMEDIATE
ALTER TABLE TABLE_A ADD LANG VARCHAR2(32);
EXECUTE IMMEDIATE
UPDATE TABLE TABLE_A SET LANG ='|| 'en_US';
EXECUTE IMMEDIATE
UPDATE TABLE TABLE_A SET TYPE='||'n/a'||' WHERE TYPE IS NULL;
Before TYPE can have values and sometimes null. Since after upgrade its part of primary key it cannot be null so making it n/a if its null.
But doing above thing for 10 million records requires upgrade downtime of 5 hours atleast. Is there any other way I can make a previous column as primary key and still won't require much downtime.
Kindly also suggest me if I am wrong with my approach. Thanks in Advance
First of all, I don't understand why using EXECUTE IMMEDIATE.
Then, what about creating a PK using Enabled Novalidated Constraints, it will apply to the new inserted rows but not to the old ones. Like that you can run batch to modify existing data to commit the new PK.
Find out more :
http://download.oracle.com/docs/cd/B19306_01/server.102/b14211/data_acc.htm#i6516
For LANG column, you could also give default value :
ALTER TABLE TABLE_A ADD LANG VARCHAR2(32) default 'en_US';
then
ALTER TABLE TABLE_A MODIFY LANG VARCHAR2(32) default null;
Nicolas.
The current primary key would have a supporting index which is probably a unique index on NAME/VERSION.
Once the columns have been added, you can create a unique index on those four columns. Then replace the primary key constraint, drop the old index (if it doesn't do so automatically when you drop the PK constraint) and use the newly created index.
It won't cut the total time, bu it may allow you to break the whole operation out into, say, 5 1-hour steps, rather than a single 5-hour step.
How to change the type of a column in a SQLite table?
I've got:
CREATE TABLE table(
id INTEGER,
salt TEXT NOT NULL UNIQUE,
step INT,
insert_date TIMESTAMP
);
I'd like to change salt's type to just TEXT and id's type to INTEGER PRIMARY KEY.
Below is an excerpt from the SQLite manual discussing the ALTER TABLE command (see URL: SQLite Alter Table):
SQLite supports a limited subset of
ALTER TABLE. The ALTER TABLE command
in SQLite allows the user to rename a
table or to add a new column to an
existing table. It is not possible to
rename a colum, remove a column, or
add or remove constraints from a
table.
As the manual states, it is not possible to modify a column's type or constraints, such as converting NULL to NOT NULL. However, there is a work around by
copying the old table to a temporary table,
creating a new table defined as desired, and
copying the data from the temporary table to the new table.
To give credit where credit is due, I learned this from the discussion on Issue #1 of hakanw's django-email-usernames project on bitbucket.org.
CREATE TABLE test_table(
id INTEGER,
salt TEXT NOT NULL UNIQUE,
step INT,
insert_date TIMESTAMP
);
ALTER TABLE test_table RENAME TO test_table_temp;
CREATE TABLE test_table(
id INTEGER PRIMARY KEY,
salt TEXT,
step INT,
insert_date TIMESTAMP
);
INSERT INTO test_table SELECT * FROM test_table_temp;
DROP TABLE test_table_temp;
Notes
I used the table name test_table since SQLite will generate an error if you try to name a table as table.
The INSERT INTO command will fail if your data does not conform to the new table constraints. For instance, if the original test_table contains two id fields with the same integer, you will receive an "SQL error: PRIMARY KEY must be unique" when you execute the "INSERT INTO test_table SELECT * FROM test_table_temp;" command.
For all testing, I used SQLite version 3.4.0 as included as part of Python 2.6.2 running on my 13" Unibody MacBook with Mac OS X 10.5.7.
Since RDBMS is not specified, these are DB2 queries:
Make ID as primary key:
ALTER TABLE table
ADD CONSTRAINT pk_id
PRIMARY KEY (id)
Make salt as not UNIQUE:
ALTER TABLE table
DROP UNIQUE <salt-unique-constraint-name>
Make salt nullable:
ALTER TABLE table
ALTER COLUMN salt DROP NOT NULL
You will need to do a reorg after drop not null. This is to be done from the command prompt.
reorg table <tableName>
In this case you can make salt to nullable and remove unique constraint. Also If id column does not contain any null or duplicate values you can safely make it primary key using sql server management studio. below is the screen shot. hope it makes it clearer:
alt text http://img265.imageshack.us/img265/7418/91573473.png
or use following sql:
alter table <TableName> modify salt text null
alter table <TableName> drop constraint <Unique Constraint Name>
alter table <TableName> modify id int not null
alter table <TableName> add constraint pk<Table>d primary key (id)