SQL Server temporary tables with a key in different sessions - sql-server

In a stored procedure, I use a temporary table with a primary key.
CREATE TABLE #tmpTable
(
[RowId] [bigint] IDENTITY(1,1) NOT NULL,
[Id] [numeric](10, 0) NOT NULL
)
ALTER TABLE #tmpTable
ADD CONSTRAINT PK_NamePK PRIMARY KEY CLUSTERED (RowId);
The procedure works, but if I run the same procedure in another session I get an error
'PK_NamePK already exists'
How to use keys or indexes on temporary tables so that they are visible only in their scope?

CREATE TABLE #tmpTable
(
[RowId] [bigint] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[Id] [numeric](10, 0) NOT NULL
)
There is no need to add alter table, you can define by table creation. Hope this work, I have never tried to add primary key on temptable before.

Related

Make a "normal" table as temporal table

I have a table created like this:
CREATE TABLE address_user
(
[username] VARCHAR(13) NOT NULL,
[address] CHAR(58) NOT NULL,
[id] BIGINT NOT NULL,
CONSTRAINT [PK_ address_user]
PRIMARY KEY CLUSTERED ([id] ASC)
);
Now I want to be able to keep the history modification of this table, so I want to make it as temporal table. I know the script to create a temporal table, the final result should be:
CREATE TABLE address_user
(
[username] VARCHAR(13) NOT NULL,
[address] CHAR(58) NOT NULL,
[id] BIGINT NOT NULL,
[sys_start_time] DATETIME2(7)
GENERATED ALWAYS AS ROW START HIDDEN NOT NULL,
[sys_end_time] DATETIME2 (7)
GENERATED ALWAYS AS ROW END HIDDEN NOT NULL,
PERIOD FOR SYSTEM_TIME ([sys_start_time], [sys_end_time]),
CONSTRAINT [PK_ address_user]
PRIMARY KEY CLUSTERED ([id] ASC)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE=[dbo].[address_user_history], DATA_CONSISTENCY_CHECK=ON));
The easy way to do that is just delete the previous table, and recreate the table with the good schema.
However, I have a lot of information in my table, save the data and delete the table, recreate it and re-insert the data make me uncomfortable.
So if you have a solution to transform the first table in temporal table without the need to delete everything and recreate it, it should be a great help!
Create the new table address_user_new, insert the data, then use sp_rename to rename address_user to address_user_old and address_user_new to address_user. This can all be done in a transaction to ensure ensure that the transition is atomic and apparently-instantaneous. eg
if object_id('address_user') is not null
ALTER TABLE address_user SET ( SYSTEM_VERSIONING = OFF)
go
if object_id('address_user_new') is not null
ALTER TABLE address_user_new SET ( SYSTEM_VERSIONING = OFF)
go
drop table if exists address_user
drop table if exists address_user_history
drop table if exists address_user_new
drop table if exists address_user_old
go
CREATE TABLE address_user
(
[username] VARCHAR(13) NOT NULL,
[address] CHAR(58) NOT NULL,
[id] BIGINT NOT NULL,
CONSTRAINT [PK_address_user]
PRIMARY KEY CLUSTERED ([id] ASC)
);
go
CREATE TABLE address_user_new
(
[username] VARCHAR(13) NOT NULL,
[address] CHAR(58) NOT NULL,
[id] BIGINT NOT NULL,
[sys_start_time] DATETIME2(7)
GENERATED ALWAYS AS ROW START HIDDEN NOT NULL,
[sys_end_time] DATETIME2 (7)
GENERATED ALWAYS AS ROW END HIDDEN NOT NULL,
PERIOD FOR SYSTEM_TIME ([sys_start_time], [sys_end_time]),
CONSTRAINT [PK_address_user_new]
PRIMARY KEY CLUSTERED ([id] ASC)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE=[dbo].[address_user_history], DATA_CONSISTENCY_CHECK=ON));
go
set xact_abort on
begin transaction
insert into address_user_new(username,address,id)
select username,address,id
from address_user with (tablockx)
exec sp_rename 'address_user', 'address_user_old', 'OBJECT'
exec sp_rename 'PK_address_user', 'PK_address_user_old', 'OBJECT'
exec sp_rename 'address_user_new', 'address_user', 'OBJECT'
exec sp_rename 'PK_address_user_new', 'PK_address_user', 'OBJECT'
commit transaction

How to create dynamic trigger with stored procedure in SQL Server

I am working on an audit trail using SQL Server triggers to identify inserts, updates and deletes on tables. Below are my tables and trigger:
CREATE TABLE [dbo].[AuditTrail]
(
[AuditId] [INT] IDENTITY(1,1) NOT NULL,
[DateTime] [DATETIME] NOT NULL,
[TableName] [NVARCHAR](255) NOT NULL,
[AuditEntry] [XML] NULL,
CONSTRAINT [PK_AuditTrail] PRIMARY KEY CLUSTERED
)
CREATE TABLE [dbo].[Employee]
(
[ID] [UNIQUEIDENTIFIER] NOT NULL DEFAULT (newid()),
[NameEmployee] [NVARCHAR](255) NOT NULL,
CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED
)
CREATE TABLE [dbo].[Transaction]
(
[ID] [UNIQUEIDENTIFIER] NOT NULL DEFAULT (newid()),
[NameTransaction] [NVARCHAR](255) NOT NULL,
CONSTRAINT [PK_Transaction] PRIMARY KEY CLUSTERED
)
CREATE TRIGGER AuditEmployee
ON [dbo].[Employee]
AFTER INSERT, DELETE, UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF (SELECT COUNT(*) FROM deleted) > 0
BEGIN
DECLARE #AuditMessage XML
SET #AuditMessage = (SELECT * FROM deleted FOR XML AUTO)
INSERT INTO AuditTrail (DateTime, TableName, AuditEntry)
VALUES (GETDATE(), 'Simple', #AuditMessage)
END
END
GO
I have created a trigger for the employee table, but that is a static trigger. How to dynamically trigger with stored procedure depends on the number of tables we have, except the AuditTrail table?

Simple SQL Server Delete fails

I am seeing intermittent failures upon a simple delete.
Essentially I have a temporary note that has many entries. Each entry has a classification which is a lookup value. Once this note is completed, it gets sent to a note repository, and the temporary version needs to be deleted.
I can't replicate reliably, but on occasion, when calling the stored procedure that does the delete of the temp note, only SOME of the entries get deleted. Coincidentally (?) the entry left behind has always been of one specific classification type.
After many many many attempts I was able to reproduce the issue while running SQL Server Profiler. Despite trying to catch Attention, ErrorLog, EventLog, Exception, and Execution Warnings, the resulting profile shows nothing out of the ordinary.
None of the involved tables are large. In fact they're minuscule. ~100-1000 at any given time in Entry, ~100 in Draft, 9 in Classification, 3 in Category.
I don't believe it should matter, but just in case, this stored procedure is being called from Entity Framework.
Any ideas? Any ideas on what to try for troubleshooting? I'm completely at a loss. Thanks in advance for any help.
Here is the stored procedure for deletion:
CREATE PROCEDURE [NoteDraft].[ClearNoteDraft]
#DraftId BIGINT
AS
BEGIN
SET NOCOUNT ON;
DELETE FROM NoteDraft.[Entry]
WHERE DraftId = #DraftId
DELETE FROM NoteDraft.Draft
WHERE Id = #DraftId
END
Here are the table definitions (with some columns left out for brevity as noted.)
CREATE TABLE [NoteDraft].[Category]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL,
[SortOrder] [int] NULL,
CONSTRAINT [PK_Category]
PRIMARY KEY CLUSTERED ([Id] ASC)
) ON [PRIMARY]
CREATE TABLE [NoteDraft].[Classification]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[CategoryId] [int] NOT NULL,
[Name] [varchar](50) NOT NULL,
[SortOrder] [int] NULL,
CONSTRAINT [PK_Classification]
PRIMARY KEY CLUSTERED ([Id] ASC)
)
CREATE TABLE [NoteDraft].[Draft]
(
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[DateModified] [datetime] NOT NULL CONSTRAINT [DF_TestNoteDraft_DateModified] DEFAULT (getdate()),
[AccountNumber] [varchar](30) NULL,
--...10 other biz columns...
CONSTRAINT [PK_Notes]
PRIMARY KEY CLUSTERED ([Id] ASC)
) ON [PRIMARY]
CREATE TABLE [NoteDraft].[Entry]
(
[DraftId] [bigint] NOT NULL,
[ClassificationId] [int] NOT NULL,
[Body] [varchar](2100) NULL,
CONSTRAINT [PK_Entry]
PRIMARY KEY CLUSTERED ([DraftId] ASC, [ClassificationId] ASC)
) ON [PRIMARY]
ALTER TABLE [NoteDraft].[Classification] WITH CHECK
ADD CONSTRAINT [FK_Classification_Category]
FOREIGN KEY([CategoryId]) REFERENCES [NoteDraft].[Category] ([Id])
GO
ALTER TABLE [NoteDraft].[Classification] CHECK CONSTRAINT [FK_Classification_Category]
GO
ALTER TABLE [NoteDraft].[Entry] WITH CHECK
ADD CONSTRAINT [FK_Entry_Classification]
FOREIGN KEY([ClassificationId]) REFERENCES [NoteDraft].[Classification] ([Id])
GO
ALTER TABLE [NoteDraft].[Entry] CHECK CONSTRAINT [FK_Entry_Classification]
GO
ALTER TABLE [NoteDraft].[Entry] WITH CHECK
ADD CONSTRAINT [FK_Entry_Draft]
FOREIGN KEY([DraftId]) REFERENCES [NoteDraft].[Draft] ([Id])
GO
ALTER TABLE [NoteDraft].[Entry] CHECK CONSTRAINT [FK_Entry_Draft]
GO
As with everything simple like this, the answer wasn't where I was looking.
Turns out, there's an event listener on the page that's re-inserting the records post deletion.
Still having trouble figuring out why the listener is running, but at least I know what's going on.

How can I make one table depend on another in SQL Server?

I have the following tables that I created in SQL Server:
CREATE TABLE [dbo].[Application] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (MAX) NULL,
CONSTRAINT [PK_dbo.Application] PRIMARY KEY CLUSTERED ([Id] ASC)
);
CREATE TABLE [dbo].[Account] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (MAX) NULL,
CONSTRAINT [PK_dbo.Account] PRIMARY KEY CLUSTERED ([Id] ASC)
);
Is there a way I can change these so that there's a link to the
account table inside the application table. A link that makes it
not possible to delete an application entry if there is an
account for that application? Sorry if this is a basic question
but I only know how to use the designer and I am not sure how I
can code this in SQL.
Add a foreign key relationship between the two tables. In your case you would want to add another int type column to the Account table called Application_Id. Then add the foreign relationship between Application_Id and Id on the Application table. I also suggest possibly changing Id on the Application table to Application_Id
CREATE TABLE [dbo].[Application] (
[Application_Id] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (MAX) NULL,
CONSTRAINT [PK_dbo.Application] PRIMARY KEY CLUSTERED ([Application_Id] ASC)
);
CREATE TABLE [dbo].[Account] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Application_Id] INT,
[Name] NVARCHAR (MAX) NULL,
CONSTRAINT [PK_dbo.Account] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT fk_AccountApps FOREIGN KEY (Application_Id)
REFERENCES Application(Application_Id)
);
SQL Fiddle
W3 Schools Foreign Key
Your problem can be solved using foreign key concept.
http://en.wikipedia.org/wiki/Foreign_key

New uniqueidentifier on the go

I want to add a column for a table which would become a PRIMARY KEY and be of type uniqueidentifier. I have this, but I wonder if there is a faster (in fewer code lines) way?
ALTER TABLE [table] ADD [id] [uniqueidentifier]
DEFAULT('00000000-0000-0000-0000-000000000000') NOT NULL
GO
UPDATE [table] SET [id] = NEWID()
GO
ALTER TABLE [table] ADD CONSTRAINT [PK_table_id] PRIMARY KEY CLUSTERED
GO
If you want to keep naming your constraints (and you should), I don't think we can reduce it below 2 statements:
create table T (
Col1 varchar(10) not null
)
go
insert into T (Col1)
values ('abc'),('def')
go
ALTER TABLE T ADD [id] [uniqueidentifier] constraint DF_T_id DEFAULT(NEWID()) NOT NULL
GO
ALTER TABLE T ADD constraint PK_T PRIMARY KEY CLUSTERED (id)
go
drop table T
Note, that I've added a name for the default constraint. Also, this ensures that new rows also have id values assigned. As I said in my comment, it's usually preferable to avoid having columns with values generated by NEWID() clustered - it leads to lots of fragmentation. If you want to avoid that, consider NEWSEQUENTIALID().
If you don't care about constraint names, you can do it as a single query:
ALTER TABLE T ADD [id] [uniqueidentifier] DEFAULT(NEWID()) NOT NULL PRIMARY KEY CLUSTERED

Resources