I need to rename the sequences of my tables. There are a lot of tables and they are complex and droping anything would not be prefered. Is there a way to rename them?
I tried:
ALTER SEQUENCE ISEQ$$_149698 RENAME TO NEW_SEQUENCE;
RENAME ISEQ$$_149698 to NEW_SEQUENCE;
The first option throws the following error:
SQL Error [2286] [42000]: ORA-02286: no options specified for ALTER SEQUENCE
The second:
SQL Error [32799] [99999]: ORA-32799: cannot rename a system-generated sequence
You cannot rename a sequence generated for an identity column. (As other users have pointed out, and as the error message implies.) For that reason, I recommend you use a sequence default value instead of an identity column.
For example:
--Create the sequence and a table to use it.
create sequence my_sequence;
create table my_table(a number default my_sequence.nextval, b number);
--Rename the sequence to whatever you want.
rename my_sequence to my_sequence2;
However, there are a few disadvantages of the default approach:
This feature is not available until 12.1. (Although identity columns are also a new feature.)
You have to create the sequences yourself (obviously).
You need to remember to also grant the sequence to any users who will insert rows to the table:
grant insert, select on my_table to test_user;
grant select on my_sequence to test_user;
If you rename a default sequence you must also modify the default value to point to the new sequence.
--Afate a sequence rename, this INSERT fails with: ORA-02289: sequence does not exist
insert into my_table(b) values(1);
--You must first modify the table:
alter table my_table modify a number default my_sequence2.nextval;
--Now this will run:
insert into my_table(b) values(1);
Despite the disadvantages of using the sequence default, I still prefer that approach over identity columns because I want all of my objects to have the exact same name in every environment.
rename old_seq to new_sequence;
Related
Using PostgreSQL 11.5. I need to allow a table to only allow one row and one column in it (not 0 or 2, exactly 1). I feel like ADD CONSTRAINT would be useful but I'm not sure what to do.
I'd like to be able to update this row when needed.
Something to make the following valid:
foo
-----
bar
But not the following:
foo | baz
-----+-----
bar | bin
-----+-----
| gar
You can force a table to have only one row setting a CHECK constraint on your primary key (or any other coulmn that is unique and not nullable) like this:
ALTER TABLE <tablename> ADD CONSTRAINT [<name>] CHECK ([pk/unique field] = [constant value]);
Anyways, since you want to have an updatable field you would need to use a table with 2 columns. If you really need to have only one row (and selecting only foo or creating a view for this purpose is not an option), you could also use triggers on insert and delete (and reject any operations inside them by raising an exception). To avoid having an empty table (not sure if you need to), you will also need this trigger on delete, the constraint will not be strong enough. For triggers see here: https://www.postgresql.org/docs/current/triggers.html
To avoid any further ALTER TABLE commands (such as adding a column) and DROP TABLE, use an event trigger. For more information, have a look into the Documentation: https://www.postgresql.org/docs/current/event-triggers.html
For using PL/pgSQL with triggers, also have a look at https://www.postgresql.org/docs/current/plpgsql-trigger.html
Here's an example that might help you:
CREATE TABLE singleton (x SMALLINT NOT NULL UNIQUE CHECK (x=1), foo VARCHAR(10) NOT NULL);
INSERT INTO singleton (x, foo) VALUES (1,'one row');
Create a VIEW as superuser or some trusted role:
CREATE VIEW onerow AS SELECT 'bar' AS foo; -- defaults to type text
GRANT SELECT ON onerow TO public;
The creator is the owner. Or:
ALTER VIEW onerow OWNER TO postgres; -- or to a trusted role
Everybody can SELECT from it like from any other table.
Nobody can add or remove rows from a VIEW - or even change anything at all with DDL commands.
Only DML commands can change it, and only the owner or superusers are allowed to do so:
CREATE OR REPLACE VIEW onerow AS
SELECT 'bar1' AS foo;
Remember that, ultimately, a motivated superuser can do anything.
On an extremely busy system, the exclusive lock taken by CREATE OR REPLACE VIEW might be a problem. That's the only possible problem with this solution I can think of.
Alternatively, consider this closely related answer to allow at most one row:
How to allow only one row for a table?
You might do that and (as superuser):
ALTER TABLE onerow OWNER TO postgres;
REVOKE ALL ON onerow FROM public;
GRANT SELECT ON onerow TO public;
Superusers can still DELETE or TRUNCATE. You can prevent that, too, with a TRIGGER or RULE ...
Or you could add a general TRIGGER with RETURN NULL or a RULE with DO INSTEAD NOTHING for INSERT and DELETE ...
One single value might alternatively be provided by a function or by a "global variable". See:
Passing user id to PostgreSQL triggers
Is there a way to define a named constant in a PostgreSQL query?
HI I am generating schema script for a database, but when i finish creating it and and look at the script it gives create table statement for a table but not including all column in it also it generates alter table add column statement for the same tables but for missing columns which are left in create table statement.
see the attached screenshot.
Assuming the question is "why does it not create all of the columns in the CREATE TABLE statement" ...
You'll notice that between the CREATE TABLE and the ALTER statements, the value for SET ANSI_PADDING is altered. As the documentation notes, the setting's value is taken into account at the point in time when a column is created.
There's no way to override this setting in-line with the declaration of a column.
Since your table apparently contains a mixture of columns, some of which are defined with the setting ON and others with it defined OFF, there's no way to write a single CREATE TABLE statement that creates all of the columns in one go.
I'm porting a SQL Server based app to Oracle. Our Oracle DBA has given me a schema that was supposed to be identical to the original SQL Server schema (and generated from it), but the auto generated keys are missing. I am trying to alter these table PK's from a normal INT to incrementing. I am doing so with Oracle SQL Developer 4.0.3 and Oracle 12c.
The error I receive is ORA-01442: column to be modified to NOT NULL is already NOT NULL
I get this after editing the table, selecting the column and setting it's Identity dropdown to 'Generated as Identity'. I am not sure why SQl Developer is attempting to make it not null when it's already a PK.
My questions are: Is this the proper way to setup a generated key? How can I get around this? If I go alter all the required columns, can the DBA use the schema to regenerate whatever procedure he used to create it in the first place to allow proper generated keys and is there a better solution for creating a good schema to go forward with?
Thanks.
If the column is already definied as NOT NULL there is no need to re-defined it as NOT NULL. Therefore you get the error ora-01442.
The best way to obtain sequence values, such as identity in SQL Server, is define the column with default sequence, before inserting row:
CREATE SEQUENCE SEQ_NAME
START WITH 1
INCREMENT BY 1
NOCACHE
NOCYCLE;
ALTER TABLE table_name MODIFY column_name INT DEFAULT SEQ_NAME.NEXTVAL;
PD: This DEFAULT works with 12 c. To 11g or less, you must create a trigger
I need to rename bunch of sequences in another schema.
RENAME old_seq to new_seq doesnt work.
Tried:
ALTER SEQUENCE old_seq RENAME TO new_seq;
but it gives me error
ORA-02286: no options specified for ALTER SEQUENCE
I do not wish to mention all the options that i had mentioned earlier while creating the sequence, since they need to be same. Only the name needs to be changed.
If you are not the owner of that sequence, You can use following steps:-
SELECT CURVAL FROM old_seq;
This will give you the value of Current_Sequence.
Now Drop this sequence using
DROP SEQUENCE old_seq;
And Create new Sequence with same name. Using
CREATE SEQUENCE old_seq;
And then alter that with this:-
ALTER SEQUENCE seq_example INCREMET BY <CURVAL FROM OLD VALUE>;
The answer from #ankit is quite in line with what's needed to fix this issue but it presents a few problems and typos which I'm fixing in this answer. I hope it'd be useful.
First, you have to select the current value for the old_seq:
SELECT old_seq.CURRVAL FROM dual;
If you get an ORA-08002 error that's because you need to ask for the NEXTVAL first in order to initialize the sequence. Just do:
SELECT old_seq.NEXTVAL FROM dual;
and then ask for CURRVAL again.
Now that you have the current value, just drop the old sequence by using
DROP SEQUENCE old_seq;
and create the new_seq with the name you want by using
CREATE SEQUENCE new_seq START WITH <CURRVAL FROM old_seq>;
If you use INCREMENT instead of START WITH, you should take into account that the increment would apply to every request for a value from the sequence. You would have to create the sequence and then reset the increment to 1. Using START WITH avoids that issue.
You can rename it straight out:
rename old_sequence to new_sequence;
It would say table renamed but you can ignore it. Your sequence will be renamed.
Try it.
I'm trying to create and increment by one some values to put into an already existing (but empty) column. I'm currently using the identity function, but I wouldn't mind using a custom made function. Right now, SSMS is saying there's incorrect syntax near IDENTITY. Could anybody help me fix this syntax?
ALTER Table anthemID IDENTITY(1,1)
First, you can't make a column identity after the fact: it has to be set that way at creation time.
Second, I'm not quite sure what you mean by "increment the value of an already existing column by one." You can only increment the value of rows within a column--perform a DML (Data Modification Language) query. The script you suggested above is a DDL (Data Definition Language) query that actually modifies the structure of the table, affecting the entire column--all rows.
If you just want to increment all the rows by 1, you'd do this:
UPDATE dbo.YourTable SET anthemID = anthemID + 1;
On the other hand, if you want the anthemID column to acquire the identity property so that new inserts to the table receive unique, autoincrementing values, you can do that with some juggling:
Back up your database and confirm it is a good backup.
Script out your table including all constraints.
Drop all constraints on your table or other tables that involve anthemID.
ALTER TABLE dbo.YourTable DROP CONSTRAINT PK_YourTable -- if part of PK
ALTER TABLE dbo.AnotherTable DROP CONSTRAINT FK_AnotherTable_anthemID -- FKs
Rename your table
EXEC sp_rename 'dbo.YourTable', 'YourTableTemp';
Modify the script you generated above to make anthemID identity (add in identity(1,1) after int);
Run the modified script to create a new table with the same name as the original.
Insert the data from the old table to the new one:
SET IDENTITY_INSERT dbo.YourTable ON;
INSERT dbo.YourTable (anthemID, AnotherColumn, RestOfColumns)
SELECT anthemID, AnotherColumn, RestOfColumns
FROM dbo.YourTableTemp;
SET IDENTITY_INSERT dbo.YourTable OFF;
Re-add all constraints that were dropped.
Drop the original, renamed table after confirming you don't need the data any more.
You may be able to do this from SSMS's GUI table designer, and it will take care of moving the data over for you. However, this has bitten some people in the past and if you don't have a good database backup, well, don't do it because you might encounter some regret in the process.
UPDATE
Now that I know the column is blank, it's even easier.
ALTER TABLE dbo.YourTable DROP COLUMN anthemID;
ALTER TABLE dbo.YourTable ADD anthemID int identity(1,1) NOT NULL;
This does have the drawback of moving the column to the end of the table. If that's a problem, you can follow much the same procedure as I outlined above (to fix things yourself, or alternately use the designer in SQL Server Management Studio).
I recommend in the strongest terms possible that you use an identity column and do not try to create your own means of making new rows get an incremented value.
For emphasis, I'll quote #marc_s's comment above:
The SELECT MAX(ID)+1 approach is highly unsafe in a concurrent environment - in a system under some load, you will get duplicates. Don't do this yourself - don't try to reinvent the wheel - use the proper mechanisms (here: IDENTITY) that your database gives you and let the database handle all the nitty-gritty details!
I wholeheartedly agree with him.