Can someone give me a real time example with the below temp table and tablevariable example that I found in stackexchange - sql

Difference between temp table and table variable as stated:
Operations on #table_variables are carried out as system transactions, independent of any outer user transaction, whereas the equivalent #temp table operations would be carried out as part of the user transaction itself. For this reason a ROLLBACKcommand will affect a #temp table but leave the #table_variable untouched.
DECLARE #T TABLE(X INT)
CREATE TABLE #T(X INT)
BEGIN TRAN
INSERT #T
OUTPUT INSERTED.X INTO #T
VALUES(1),(2),(3)
/*Both have 3 rows*/
SELECT * FROM #T
SELECT * FROM #T
ROLLBACK
/*Only table variable now has rows*/
SELECT * FROM #T
SELECT * FROM #T
DROP TABLE #T
Can anyone tell me when will this above mentioned application/scenario will be used in real time? Can anyone give a real time example. Thanks
P.S. - Referred from this link: https://dba.stackexchange.com/questions/16385/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server/16386#16386

In a real example, just consider you have a transaction and for somehow your transaction rollbacks but you still want to log and see why the transaction is failed and try to keep the log until you execute the transaction without any rollbacks.
In this example, you can capture all your logs information into a table variable.

What is going on is that the developer is demonstrating the use of a temporary table (which for most intents is the same as a regular table) and a variable that is a table. When a rollback occurs any changes made to the temporary table is undone (the table is in the same state as before transaction started) but the variable is changed - its not affected by the rollback.

Related

Make sure only one record inserted in table with thousands of concurrent users

Recently, I needed to write a stored procedure to insert only one record when the first user come and ignore for others. I think the IF NOT EXISTS INSERT will not work for me. Also, some people saying online that MERGE adds race condition. Any quick way to achieve this? This is my code for now.
IF NOT EXISTS (SELECT ......)
INSERT
You might add another table to use as the lock mechanism.
Let's say your table's name is a, and the name of the table which has the locked value is check_a :
create table a (name varchar(10))
create table check_a (name varchar(10))
Insert only one record to the lock table:
insert into check_a values ('lock')
go
Then create a stored procedure which checks if there is a value in the main table. If there is no record, we might lock the only value in the table check_a and insert our value into the table a.
create proc insert_if_first
as
begin
set nocount on
if not exists (select name from a)
begin
declare #name varchar(10)
begin tran
select #name = name from check_a with (updlock)
if not exists (select name from a)
begin
insert into a values ('some value')
end
commit
end
end
go
First selection from the table a to check there is no record is for using system resources as low as we can. If there is a record in the table a, we can skip opening transaction and skip locking the row.
Second check is to make sure that while we are waiting to obtain the lock, no one inserted a row to the table a.
This way, only the first user which can lock check_a will be able to insert a value to the table a.
I'm guessing that you mean you want users to make a stored procedure that makes sure only one user can run the procedure. Then you need to use isolation levels. There are different Isolation levels, so you need to decide which one you need.
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE
You can read what they do here:
https://msdn.microsoft.com/en-us/library/ms173763.aspx

Why rollback is not working for variable table in SQL Server 2012?

I have created one variable table. In my stored procedure, there are lots of transactions.
Now whenever an error occurs, I want to rollback a specific transactions which has some statements which insert or update or delete records from variable table.
This is just an example of my actual problem :
declare #tab table (val int)
insert into #tab select 2
insert into #tab select 3
insert into #tab select 4
select * from #tab
begin tran
begin try
update #tab set val = 1
select 1/0;
commit
end try
begin catch
rollback
end catch
select * from #tab
Actual output :-
My expected output is :-
So here rollback of a transaction is not working. Why it is not working here ? Am I doing something wrong ?
You are not using a temp table, you are using a variable table. There is a difference.
Temp tables work with transactions, variable tables don't. See http://blog.sqlauthority.com/2009/12/28/sql-server-difference-temp-table-and-table-variable-effect-of-transaction/
If you were to change your variable table #tab to a temporary table of #tab, you would get your desired behavior.
Differences between temp and variable tables: https://dba.stackexchange.com/questions/16385/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server/16386#16386
I have modified my question. Thanks for your knowledge sharing. But question remains the same. Why it is not working for variable table?
The links I posted above go through that with more detail than I could.

Using a single column table for generation sequence in SQL Server 2008 is scalable solution?

Currently we are relying on a formula for generating confirmation numbers, but on heavy loads we observed duplicate confirmation numbers are being generated. We are considering switching to a sequence table as a quick fix, but we're worried about how it will perform. How can we calculate the risk in using the following approach?
CREATE TABLE dbo.TRN_CNFRM_SEQUENCE_UC_LOC_1
(
id INT IDENTITY(seed,increment)
)
declare #confirm table (id int);
BEGIN TRAN
INSERT INTO dbo.TRN_CNFRM_SEQUENCE_UC_LOC_1
output inserted.id into #confirm
DEFAULT VALUES
ROLLBACK TRAN
select ID from #confirm
First, creating a memory table means a table will be created in tempdb requiring schema lock. Adding a row to that table requires an additional exclusive page lock. If you're only acquiring a single "confirmation number" at the time you could get around that by altering the code to:
BEGIN TRAN
INSERT INTO dbo.TRN_CNFRM_SEQUENCE_UC_LOC_1
DEFAULT VALUES
ROLLBACK TRAN
SELECT SCOPE_IDENTITY()
Inserting into the table will also require an exclusive page lock. Having a high degree of concurrent work loads can lead to latch contention on the single page this table will allocate.

Forbid insert into table on certain conditions

I have a SQL Server 2008 database. There are three terminals connected to it (A, B, C). There is a table SampleTable in the database, which reacts to any terminal activity. Every time there is some activity on any terminal, logged on to this DB, the new row is inserted into SampleTable.
I want to redirect traffic from one (C) of the three terminals to write to table RealTable and not SampleTable, but I have to do this on DB layer since services that write terminal activity to DB are in Black Box.
I already have some triggers working on SampleTable with the redirecting logic, but the problem is that rows are still being inserted into SampleTable.
What is the cleanest solution for this. I am certain that deleting rows in an inserting trigger is bad, bad, bad.
Please help.
Edit:
Our current logic is something like this (this is pseudo code):
ALTER TRIGGER DiffByTerminal
ON SampleTable
AFTER INSERT
AS
DECLARE #ActionCode VARCHAR(3),
#ActionTime DATETIME,
#TerminalId INT
SELECT #ActionCode = ins.ActionCode,
#ActionTime = ins.ActionTime,
#TerminalId = ins.TerminalId
FROM inserted ins
IF(#TerminalId = 'C')
BEGIN
INSERT INTO RealTable
(
...
)
VALUES
(
#ActionCode,
#ActionTime,
#TerminalId
)
END
In order to "intercept" something before a row gets inserted into a table, you need an INSTEAD OF trigger, not an AFTER trigger. So you can drop your existing trigger (which also included flawed logic that assumed all inserts would be single-row) and create this INSTEAD OF trigger instead:
DROP TRIGGER DiffByTerminal;
GO
CREATE TRIGGER dbo.DiffByTerminal
ON dbo.SampleTable
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.RealTable(...) SELECT ActionCode, ActionTime, TerminalID
FROM inserted
WHERE TerminalID = 'C';
INSERT dbo.SampleTable(...) SELECT ActionCode, ActionTime, TerminalID
FROM inserted
WHERE TerminalID <> 'C';
END
GO
This will handle single-row inserts and multi-row inserts consisting of (a) only C (b) only non-C and (c) a mix.
One of the easiest solution for you is INSTEAD OF trigger. Simply stating, it's trigger that "fires" on very action you decide and lets you "override" the default behavior of the action.
You can override the INSERT, DELETE and UPDATE statements for specific table/view (you use it a lot with views that combine data from different tables and you want make the view insert-able) using INSTEAD OF trigger, where you can put your logic. inside the trigger you can then call again to INSERT when it's appropriate, and you don't have to worry about recursion - INSTEAD OF triggers won't apply on statements from inside the trigger code itself.
Enjoy.

At what point should a Table Variable be abandoned for a Temp Table?

Is there a row count that makes table variable's inefficient or what? I understand the differences between the two and I've seen some different figures on when that point is reached, but I'm curious if anyone knows.
When you need other indices on the table other than those that can be created on a temp table variable, or, for larger datasets (which are not likely to be persisted in available memory), when the table width (number of bytes per row) exceeds some threshold (This is because the number or rows of data per I/O page shrinks and the performance decreases... or if the changes you plan on making to the dataset need to be part of a multi-statement transaction which may need to be rolled back. (changes to Table variables are not written to the transaction log, changes to temp tables are...)
this code demonstrates that table variables are not stored in Transaction log:
create table #T (s varchar(128))
declare #T table (s varchar(128))
insert into #T select 'old value #'
insert into #T select 'old value #'
begin transaction
update #T set s='new value #'
update #T set s='new value #'
rollback transaction
select * from #T
select * from #T
Internally, table variables can be instantiated in tempdb as well as the temporary tables.
They differ in scope and persistence only.
Contrary to the popular belief, operations to the temp tables do affect the transaction log, despite the fact they are not subject to the transaction control.
To check it, run this simple query:
DECLARE #mytable TABLE (id INT NOT NULL PRIMARY KEY)
;
WITH q(num) AS
(
SELECT 1
UNION ALL
SELECT num + 1
FROM q
WHERE num <= 42
)
INSERT
INTO #mytable (id)
SELECT num
FROM q
OPTION (MAXRECURSION 0)
DBCC LOG(tempdb, -1)
GO
DBCC LOG(tempdb, -1)
GO
and browse the last entries from both recordsets.
In the first recordset, you will see 42 LOP_INSERT_ROWS entries.
In the second recordset (which is in another batch) you will see 42 LOP_DELETE_ROWS entries.
They are the result of the table variable getting out of scope and its record being deleted.