Let's say I have a table
CREATE TABLE foo (name varchar, new_name varchar);
But I want to rename name -> old_name and new_name -> name. How to do this inside a single transaction? I am told there should be an explicit lock on the transaction... which kind of lock?
Thanks!
Just do it. Start a transaction, do what you want, end the transaction.
begin;
alter table foo rename name to old_name;
alter table foo rename new_name TO name;
commit;
Related
I am running into an issue with creating temp tables in Sybase db. We have a sql where we create a temp table, insert/update it and do a select * from it at the end of get some results. We are invoking this sql from the service layer using spring jdbc tmplate. The first run works fine, but the next subsequesnt runs fails with error
cannot create temporary table <name>. Prefix name is already in use by another temorary table
This is how I am checking if table exists:
if object_id('#temp_table') is not null
drop table #temp_table
create table #temp_table(
...
)
Anything I am missing here?
Might not be a great response, but I also have that problem and I have 2 ways around it.
1. Do the IF OBJECT_ID Drop Table as a separate execute prior to the query
2. Do the Drop Table without the IF OBJECT_ID() right after your query.
You are really close but temp tables require using the db name before too.
IF OBJECT_ID('tempdb..#Results') IS NOT NULL
DROP TABLE #Results
GO
It would be the same if you were checking if a user table in another database existed.
IF OBJECT_ID('myDatabase..myTable') IS NOT NULL
DROP TABLE myDatabase..myTable
GO
NOTE: A bit more info on BigDaddyO's first suggestion ...
The code snippet you've provided, when submitted as a SQL batch, is parsed as a single unit of work prior to the execution. Net result is that if #temp_table already exists when the batch is submitted, then the compilation of the create table command will generate the error. This behavior can be seen in the following example:
create table #mytab (a int, b varchar(30), c datetime)
go
-- your code snippet; during compilation the 'create table' generates the error
-- because ... at the time of compilation #mytab already exists:
if object_id('#mytab') is not NULL
drop table #mytab
create table #mytab (a int, b varchar(30), c datetime)
go
Msg 12822, Level 16, State 1:
Server 'ASE200', Line 3:
Cannot create temporary table '#mytab'. Prefix name '#mytab' is already in use by another temporary table '#mytab'.
-- same issue occurs if we pull the 'create table' into its own batch:
create table #mytab (a int, b varchar(30), c datetime)
go
Msg 12822, Level 16, State 1:
Server 'ASE200', Line 1:
Cannot create temporary table '#mytab'. Prefix name '#mytab' is already in use by another temporary table '#mytab'.
As BigDaddyO has suggested, one way to get around this is to break your code snippet into two separate batches, eg:
-- test/drop the table in one batch:
if object_id('#mytab') is not NULL
drop table #mytab
go
-- create the table in a new batch; during compilation we don't get an error
-- because #mytab does not exist at this point:
create table #mytab (a int, b varchar(30), c datetime)
go
I have two Dbs on the same server named 'DB_prod' and 'DB_test', and they are simply the same.
I need to assume that someone can modify table on 'DB_prod'. The script need to find all columns differences (types,collation,nullable,max length) + find new columns, and alter it to table on the 'DB_test'.
There are no relationships between tables.
First step is to find diffrences and I know how to accomplish this.
The secound step would be to move all chages to 'DB_test'.
The only idea I have for now is to use dynamic sql, so write diffrent table 'alters' and execute them in cursor.
Any other idea?
All work need to be done by procedure(s).
Thanks
A database-scoped trigger is probably what you're looking for. You can use it to record the alter table statements to a table TriggerLog and then run your stored procedure to execute the statements on your test table.
--Table to hold your event data.
CREATE TABLE TriggerLog
(
Event_Data NVARCHAR(MAX),
Username NVARCHAR(250),
Event_Date DATETIME
)
CREATE TRIGGER trg_alter_table ON DATABASE --database level trigger
FOR ALTER_TABLE
AS
INSERT TriggerLog
SELECT EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)'),
COALESCE(SUSER_SNAME(),USER_NAME()),
GETDATE();
GO
ALTER TABLE ProdTable
ADD column1 VARCHAR(100);
SELECT *
FROM triggerlog
Results:
Event_data Username Event_Date
------------------------------------------------------------------------------------------
ALTER TABLE ProdTable ADD column1 VARCHAR(100); Domain\User 2015-03-16 09:29:47.387
Is it possible to rename a temporary table?
create table #t (id integer);
execute tempdb.sys.sp_rename '#t', '#s';
An invalid parameter or option was specified for procedure 'sys.sp_rename'
The proposed solution by #Michel, inserting into another temp table and dropping the original, works but I guess how expensive it is.
Tempdb doesn't have the sp_rename procedure. What you could do is to create a new temptable with the contents of your old one
Something like this
select * into #NewName from #OldName
drop table #OldName
How to remove a column from an existing table?
I have a table MEN with Fname and Lname
I need to remove the Lname
How to do it?
ALTER TABLE MEN DROP COLUMN Lname
Generic:
ALTER TABLE table_name DROP COLUMN column_name;
In your case:
ALTER TABLE MEN DROP COLUMN Lname;
Your example is simple and doesn’t require any additional table changes but generally speaking this is not so trivial.
If this column is referenced by other tables then you need to figure out what to do with other tables/columns. One option is to remove foreign keys and keep referenced data in other tables.
Another option is to find all referencing columns and remove them as well if they are not needed any longer.
In such cases the real challenge is finding all foreign keys. You can do this by querying system tables or using third party tools such as ApexSQL Search (free) or Red Gate Dependency tracker (premium but more features). There a whole thread on foreign keys here
This is the correct answer:
ALTER TABLE MEN DROP COLUMN Lname
But... if a CONSTRAINT exists on the COLUMN, then you must DROP the CONSTRAINT first, then you will be able to DROP the COLUMN. In order to drop a CONSTRAINT, run:
ALTER TABLE MEN DROP CONSTRAINT {constraint_name_on_column_Lname}
In SQL Server 2016 you can use new DIE statements.
ALTER TABLE Table_name DROP COLUMN IF EXISTS Column_name
The above query is re-runnable it drops the column only if it exists in the table else it will not throw error.
Instead of using big IF wrappers to check the existence of column before dropping it you can just run the above DDL statement
The question is, can you only delete a column from an unexisting table ;-)
BEGIN TRANSACTION
IF exists (SELECT * FROM sys.columns c
INNER JOIN sys.objects t ON (c.[object_id] = t.[object_id])
WHERE t.[object_id] = OBJECT_ID(N'[dbo].[MyTable]')
AND c.[name] = 'ColumnName')
BEGIN TRY
ALTER TABLE [dbo].[MyTable] DROP COLUMN ColumnName
END TRY
BEGIN CATCH
print 'FAILED!'
END CATCH
ELSE
BEGIN
SELECT ERROR_NUMBER() AS ErrorNumber;
print 'NO TABLE OR COLUMN FOUND !'
END
COMMIT
The simple answer to this is to use this:
ALTER TABLE MEN DROP COLUMN Lname;
More than one column can be specified like this:
ALTER TABLE MEN DROP COLUMN Lname, secondcol, thirdcol;
From SQL Server 2016 it is also possible to only drop the column only if it exists. This stops you getting an error when the column doesn't exist which is something you probably don't care about.
ALTER TABLE MEN DROP COLUMN IF EXISTS Lname;
There are some prerequisites to dropping columns. The columns dropped can't be:
Used by an Index
Used by CHECK, FOREIGN KEY, UNIQUE, or PRIMARY KEY constraints
Associated with a DEFAULT
Bound to a rule
If any of the above are true you need to drop those associations first.
Also, it should be noted, that dropping a column does not reclaim the space from the hard disk until the table's clustered index is rebuilt. As such it is often a good idea to follow the above with a table rebuild command like this:
ALTER TABLE MEN REBUILD;
Finally as some have said this can be slow and will probably lock the table for the duration. It is possible to create a new table with the desired structure and then rename like this:
SELECT
Fname
-- Note LName the column not wanted is not selected
INTO
new_MEN
FROM
MEN;
EXEC sp_rename 'MEN', 'old_MEN';
EXEC sp_rename 'new_MEN', 'MEN';
DROP TABLE old_MEN;
But be warned there is a window for data loss of inserted rows here between the first select and the last rename command.
To add columns in existing table:
ALTER TABLE table_name
ADD
column_name DATATYPE NULL
To delete columns in existing table:
ALTER TABLE table_name
DROP COLUMN column_name
This can also be done through the SSMS GUI. The nice thing about this method is it warns you if there are any relationships on that column and can also automatically delete those as well.
Put table in Design view (right click on table) like so:
Right click on column in table's Design view and click "Delete
Column"
As I stated before, if there are any relationships that would also need to be deleted, it will ask you at this point if you would like to delete those as well. You will likely need to do so to delete the column.
If you are using C# and the Identity column is int, create a new instance of int without providing any value to it.It worked for me.
[identity_column] = new int()
Syntax:
ALTER TABLE TABLE_NAME DROP COLUMN COLUMN_NAME;
For Example:
alter table Employee drop column address;
I'm looking for a way to script postgreSQL schema changes in an idempotent manner.
In MSSQL I could do something like this:
if(not exists(select * from information_schema.columns where table_name = 'x' and column_name = 'y'))
begin
alter table x add y int
end
go
PostgreSQL doesn't seem to allow ad-hoc pl/pgsql in the same way MSSQL does with T-SQL so I can't use control structures in a SQL script and run it with psql -f x.sql.
I know PostgreSQL will throw an error if the object already exists but I don't want to have to ignore errors.
I could use some schema versioning technique like dbdeploy but I really like the simplicity of running a set of files through psql without incurring any unwanted side effects.
Is this possible?
Thanks,
Mark
Disclaimer: I know, this is a very old question and already has an accepted answer.
But I'd like to register here a totally idempotent script, without external links.
A simple script demonstrating PostgreSQL 9.5+ idempotent built-in capabilities. You can run this script as many times as you wish.
Here we go:
--Table
CREATE TABLE IF NOT EXISTS person (
id integer NOT NULL,
person_name character varying(40) NOT NULL,
updated_date date,
CONSTRAINT person_pkey PRIMARY KEY (id)
);
--Index
CREATE INDEX IF NOT EXISTS idx_person_name ON person (person_name);
--Sequence
CREATE SEQUENCE IF NOT EXISTS seq_person_inc;
--Function
CREATE OR REPLACE FUNCTION simple_sum(a_integer int, b_integer int) RETURNS INT
AS $$ SELECT a_integer+b_integer $$
LANGUAGE SQL;
--View
CREATE OR REPLACE VIEW vw_select_1 AS
SELECT 1;
--Role
DO $$
BEGIN
CREATE ROLE rick_deckard;
EXCEPTION
WHEN duplicate_object THEN
RAISE NOTICE 'Role already exists. Ignoring...';
END$$;
--Simple insert
INSERT INTO person (id, person_name) VALUES (1, 'HAL-9000');
--Upsert (insert + update)
INSERT INTO person (id, person_name) VALUES (1, 'Betrayer') ON CONFLICT ON CONSTRAINT person_pkey DO UPDATE SET person_name = EXCLUDED.person_name;
--Upsert (ignoring duplicate error)
INSERT INTO person (id, person_name) VALUES (1, 'HAL-9000') ON CONFLICT ON CONSTRAINT person_pkey DO NOTHING;
--Upsert (ignoring any error)
INSERT INTO person (id, person_name) VALUES (1, 'HAL-9000') ON CONFLICT DO NOTHING;
--Field
DO $$
BEGIN
ALTER TABLE person ADD COLUMN id_another_person INTEGER;
EXCEPTION
WHEN duplicate_column THEN
RAISE NOTICE 'Field already exists. Ignoring...';
END$$;
--Constraint
DO $$
BEGIN
ALTER TABLE person ADD CONSTRAINT person_id_another_person_fkey FOREIGN KEY (id_another_person) REFERENCES person (id);
EXCEPTION
WHEN duplicate_object THEN
RAISE NOTICE 'Constraint already exists. Ignoring...';
END$$;
--Trigger
CREATE OR REPLACE FUNCTION person_trigger_function() RETURNS trigger AS $BODY$
BEGIN
--Something complex here =)
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;
DO $$
BEGIN
CREATE TRIGGER person_trigger BEFORE INSERT OR UPDATE ON person FOR EACH ROW EXECUTE PROCEDURE person_trigger_function();
EXCEPTION
WHEN duplicate_object THEN
RAISE NOTICE 'Trigger already exists. Ignoring...';
END$$;
--Drop
DROP TRIGGER IF EXISTS person_trigger ON person;
DROP INDEX IF EXISTS idx_person_name;
ALTER TABLE person DROP COLUMN IF EXISTS person_name;
ALTER TABLE person DROP CONSTRAINT IF EXISTS person_id_another_person_fkey;
DROP ROLE IF EXISTS rick_deckard;
DROP VIEW IF EXISTS vw_select_1;
DROP FUNCTION IF EXISTS simple_sum(integer, integer);
DROP FUNCTION IF EXISTS person_trigger_function();
DROP TABLE IF EXISTS person;
DROP SEQUENCE IF EXISTS seq_person_inc;
you might find this blogpost helpful: http://www.depesz.com/index.php/2008/06/18/conditional-ddl/
You should be able to use plpgsql:
create language plpgsql;
create function f() ... as $$
<plpgsql code>
$$language plpgsql;
select f();