My question is kind of easy but i'm still doubting after I created this transaction. If I execute the following code:
BEGIN TRANSACTION
DROP TABLE Table_Name
Can I perform a ROLLBACK TRANSACTION that recovers the dropped table? I'm asking because I don't know what happens in the 'Object Explorer' and I didn't found any question of this topic, so I think that it could be a useful issue.
DROP TABLE can be rolled back and it does not auto-commit.
This is incredibly easy to test.
create table TransactionTest
(
ID int identity primary key clustered,
SomeValue varchar(20)
)
insert TransactionTest
select 'Here is a row'
begin transaction
drop table TransactionTest
rollback transaction
select * from TransactionTest
I just want to add that I tried in Oracle 11g, Mysql 5.7 and MSSQL 2016. It only rolled back (worked) with MSSQL RDBMS. I would expect that most other RDBMS won't support it since it execute schema changes.
ORACLE PL/SQL EX:
savepoint mysave;
DROP TABLE test_table;
ROLLBACK TO mysave;
select * from test_table;
Related
I'm trying to come up with a way to prevent analysts from creating tables without a Primary key. I know how to create a database level trigger, and I know how to query to find whether or not a table has a primary key, but I was hoping that SQL Server has a 'Created' table, much in the same way it has 'inserted'/'updated' tables used in ON INSERT/ON UPDATE triggers.
Hypothetically, if SQL Server did have this 'Created' table, my trigger would look like this:
CREATE TRIGGER PKViolations
ON DATABASE
FOR CREATE_TABLE
AS
IF EXISTS (SELECT 1
FROM Created
WHERE OBJECTPROPERTY(OBJECT_ID,'TableHasPrimaryKey') = 0)
BEGIN
PRINT 'Please include a Primary Key. Transaction has been rolled back.'
ROLLBACK;
END
Instructing analysts on importance of primary keys has helped, but tables are still being created without PKs, any insight is greatly appreciated!
You can use EVENTDATA() to get the ObjectName. Then you can use your query to examine if there is a primary key.
SELECT NewTableName = EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]', 'NVARCHAR(255)')
You can read more about EVENTDATA here. https://learn.microsoft.com/en-us/sql/t-sql/functions/eventdata-transact-sql
Here is a fully functional example:
CREATE TRIGGER PKViolations
ON DATABASE
FOR CREATE_TABLE
AS
declare #NewTableName nvarchar(255)
SELECT #NewTableName = EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]', 'NVARCHAR(255)')
IF OBJECTPROPERTY(OBJECT_ID(#NewTableName),'TableHasPrimaryKey') = 0
BEGIN
PRINT 'Please include a Primary Key. Transaction has been rolled back.'
ROLLBACK;
END
go
I have a table called myTable where continuous insertion is happening. I will rename that table by myTable_Date and create a new table, myTable through a Store Procedure.
I want to know what will happen during re-naming and re-creating the table, will it drop any packet?
SQL Server has sp_rename built in if you just want to change the name of a table.
sp_rename myTable, myTable_Date
Would change the name from myTable to myTable_Date
But it only changes the name reference in sys.Objects so make sure any references are altered and read the documentation about it :)
The Microsoft doc for it is HERE
When you rename the myTable to myTableDate, myTable won't exist anymore so if someone tries to insert something inside myTable it will fail.
When you create new myTable with the same name and columns everything will be fine and the insertion process will continue.
I suggest you to make a little script renaming the table and creating new one. Something like this:
sp_rename myTable, myTable_Date
GO
CREATE TABLE myTable(
-- Table definition
)
When you rename the table you will get warning like this: "Caution: Changing any part of an object name could break scripts and stored procedures." so you better create the new table fast.
Other option is you create a table exact like myTable and insert all data from myTable there and then can delete them from myTable. No renaming, no dropping and insertion process will not be interrupted.
I want to know what will happen during re-naming and re-creating the
table, will it drop any packet?
Inserts attempted after the table is renamed will err until the table is recreated. You can avoid that by executing the tasks in a transaction. Short term blocking will happen if an insert is attempted before the transaction is committed but no rows will be lost. For example:
CREATE PROC dbo.ReanmeMytableWithDate
AS
DECLARE #NewName sysname = 'mytable_' + CONVERT(nchar(8), SYSDATETIME(), 112);
SET XACT_ABORT ON;
BEGIN TRY;
BEGIN TRAN;
EXEC sp_rename N'dbo.mytable', #NewName;
CREATE TABLE dbo.mytable(
col1 int
);
COMMIT;
END TRY
BEGIN CATCH
THROW;
END CATCH;
GO
I don't know your use case for renaming tables like this but it seems table partitioning might be a better approach as #Damien_The_Unbeliever suggested. Although table partitioning previously required Enterprise Edition, the feature is available in Standard Edition beginning with SQL Server 2016 SP1 as well as Azure SQL Database.
I'm trying to write a small script to create a database if it doesn't exist, and create a table for that database if the table doesn't exist. What I have is this:
IF (db_id('db') is null) BEGIN
print 'Must create the database!';
CREATE DATABASE db;
END
USE db;
IF (object_id('test_table', 'U') is null) BEGIN
print 'Must create the table!';
CREATE TABLE test_table (
id int
);
END
I'm getting a strange error with this:
Database 'db' does not exist. Make sure that the name is entered correctly.
I'm guessing that it's parsing the script before running it and finding that 'db' doesn't exist, so it can't use it.
There must be a solution to this. Any help is appreciated.
SOLVED!
I realised 5 minutes after posting that the GO keyword solves the problem. Here is the fixed code:
IF (db_id('db') is null) BEGIN
print 'Must create the database!'
CREATE DATABASE db;
END
GO
USE db
IF (object_id('test_table', 'U') is null) BEGIN
print 'Must create the table!';
CREATE TABLE test_table (
id int
);
END
Sorry for wasting everyone's time.
SQL statements are parsed as one batch unless you break them apart. In SQL Server, you can use GO to do this. In both MySQL and SQL Server, you can use BEGIN and END.
If you want to commit the separate blocks to the database in different instances you can use BEGIN TRANS / COMMIT TRANS and START TRANSACTION / COMMIT for SQL Server and MySQL, respectively.
Something along the lines of Check if table exists in SQL Server would probably work (With a slight change)
IF (NOT EXISTS (SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'TheSchema'
AND TABLE_NAME = 'TheTable'))
BEGIN
--Do Stuff
END
I might suggest using the built-in SQL syntax -
CREATE DATABASE name IF NOT EXISTS;
And subsequently
CREATE TABLE name(definition) IF NOT EXISTS;
I want to do this:
create procedure A as
lock table a
-- do some stuff unrelated to a to prepare to update a
-- update a
unlock table a
return table b
Is something like that possible?
Ultimately I want my SQL server reporting services report to call procedure A, and then only show table a after the procedure has finished. (I'm not able to change procedure A to return table a).
Needed this answer myself and from the link provided by David Moye, decided on this and thought it might be of use to others with the same question:
CREATE PROCEDURE ...
AS
BEGIN
BEGIN TRANSACTION
-- lock table "a" till end of transaction
SELECT ...
FROM a
WITH (TABLOCK, HOLDLOCK)
WHERE ...
-- do some other stuff (including inserting/updating table "a")
-- release lock
COMMIT TRANSACTION
END
BEGIN TRANSACTION
select top 1 *
from table1
with (tablock, holdlock)
-- You do lots of things here
COMMIT
This will hold the 'table lock' until the end of your current "transaction".
Use the TABLOCKX lock hint for your transaction. See this article for more information on locking.
I would to create a trigger for Sybase, but it shows an error.
What I want to do is, when a delete operation is done on the [student] table, to check whether there is any record related to student on [account], and if so, raise an exception.
There seems to be a lack of support by Sybase. Their official seem not people to visit.
*CREATE TRIGGER AccountChecker
BEFORE DELETE ON student
REFERENCING OLD AS old_student
FOR EACH ROW
BEGIN
DECLARE #acc CHAR(4);
DECLARE #acc_not_null EXCEPTION FOR SQLSTATE '99999';
SELECT #acc=account.account_number FROM account
WHERE account.student_id = old_student.student_id;
IF #acc IS NOT NULL
BEGIN
SIGNAL acc_not_null
END
END*
Sybase supports foreign keys and primary keys, both via procedures such as sp_primarykey and sp_foreignkey and via declarative SQL constraints. What you are seeking to do is exactly what a foreign key from [account] referencing [student] should do.
The Sybase SQL User Guide (Adaptive Server 15, if it matters) illustrates a 'delete restricted' trigger (with somewhat different indentation):
create trigger deltitle
on titles
for delete
as
if (select count(*)
from deleted, salesdetail
where salesdetail.title_id =
deleted.title_id) > 0
begin
rollback transaction
print "You cannot delete a title with sales."
end
I'm not convinced that rollback is a good idea; an exception is probably better.
The notation you are trying to use hews more closely to the SQL standard than the documented Sybase-supported notation.
Doesn't Sybase support foreign keys?