Set permissions within create table script - sql-server

I have a simple create table script, below:
CREATE TABLE [dbo].[CAS_WORKED](
[recordid] [int] IDENTITY(1,1) NOT NULL,
[Region] [varchar](20) COLLATE Latin1_General_CI_AS NULL,
[OpsLevel1] [varchar](20) COLLATE Latin1_General_CI_AS NULL,
[OpsLevel2] [varchar](20) COLLATE Latin1_General_CI_AS NULL,
[CostCentre] [varchar](4) COLLATE Latin1_General_CI_AS NULL
CONSTRAINT [PK_CAS_WORKED] PRIMARY KEY CLUSTERED
(
[recordid] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
Is there a way to setup Delete, Insert, Select and Update permissions for a specific database role within the create table script?

It's entirely possible to put permissions in the same script, even in the same batch, but not possible on the same statement. The CREATE TABLE should be issued normally, and then the GRANT/DENY to setup permissions. For example, it can be something like that:
CREATE TABLE dbo.test (Id INT NOT NULL PRIMARY KEY) ;
GRANT SELECT ON dbo.test TO SomeUser ;
GO

You can create a new database role and then assign rights via the following:
For example, I have a role called "Custom_Admin"
GRANT SELECT, UPDATE, INSERT, DELETE ON CAS_WORKED TO CustomAdmin
or (more standard, you should have fulluser)
GRANT SELECT, UPDATE, INSERT, DELETE ON CAS_WORKED TO FULLUSER
Hope this helps.

GRANT SELECT, INSERT, UPDATE, DELETE ON CAS_WORKED
TO USERGROUP1, USERGROUP2;

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

Is there any way to track changes from views in MS Sql Server?

I'm looking for how to track changes from a view in MS Sql-Server 2012. And, the role of the log-in user is Public. So, it's hard to do it.
For example, Assuming that there is the schema.
CREATE TABLE [dbo].[USER_CREDENTIAL](
[USERID] [nvarchar](48) NOT NULL,
[VALID_FROM] DATETIME NULL,
[EXPIRED_AT] DATETIME NULL,
[CREDENTIAL_ID] int NOT NULL,
CONSTRAINT [UNIQUE_USERID] PRIMARY KEY CLUSTERED( [USERID] ASC)
) ;
CREATE VIEW [VIEW_OF_USER_CREDENTIAL] as
SELECT * FROM dbo.[USER_CREDENTIAL];
It can be only permitted to access the view. The view will be changed when some data is inserted/updated/deleted from the USER_CREDENTIAL table. I will do query to the view.
I saw the document. I tried that, but the target to track should be the data table and the login user is lack of the role. I got the error message.
Object 'foo' is of a data type that is not supported by the CHANGETABLE function. The object must be a user-defined table.
I tried the following. I added the temporary table and the trigger which make changed-data be inserted to the temporary table when the view is changed. But, it was also failed because it was permission denied.
CREATE TABLE dbo.[CHANGES_FROM_A_VIEW] (
[VERSION] [int] IDENTITY(1,1) NOT NULL,
[USERID] [nvarchar](48) NOT NULL,
CONSTRAINT [UNIQUE_VERSION] PRIMARY KEY CLUSTERED ( [VERSION] ASC)
)
CREATE TRIGGER [SOMETHING_CHANGED] ON dbo.[VIEW_OF_USER_CREDENTIAL] ...
ALTER DATABASE database_name
SET CHANGE_TRACKING = ON (CHANGE_RETENTION = 2 DAYS,AUTO_CLEANUP = ON)
ALTER TABLE [CHANGES_FROM_A_VIEW]
ENABLE CHANGE_TRACKING WITH (TRACK_COLUMNS_UPDATED = ON)
SELECT * FROM CHANGETABLE(CHANGES dbo.CHANGES_FROM_A_VIEW, 0) AS C
Anyone knows any way to solve this?

SQL Server temporary tables with a key in different sessions

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.

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 to add the column by default in sql server 2005

I have 2 tables called login and Roles.
In the login table, I have these fields:
CREATE TABLE [dbo].[login]
([Id] [int] IDENTITY(1,1) NOT NULL,
[Uname] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[Pwd] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
CONSTRAINT [PK_login_1] PRIMARY KEY CLUSTERED([Uname] ASC)
In the roles table I have these fields:
CREATE TABLE [dbo].[Roles]
([Uname] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[Valid] [int] NOT NULL
)
Now what I need is if I fill the uname as some xyz I would like to fill the same uname in the role table automatically in the corresponding field that i makes as foreign key...
You could do this using a Trigger. You may or may not want to execute this code on an Insert and / or Update Further details on triggers can be found here
CREATE TRIGGER trgInsertUserIntoRoles ON Login
FOR Insert
AS
INSERT INTO Roles (UName, Valid)
SELECT Uname, 1
FROM Inserted
Although I think it would be better if you just added the code to insert the username into the Roles table within the Stored Procedure to create the user.
Also, you are aware that you are creating all this on the master database?
A solution is to put a trigger on inserts to the original table.
This microsoft article on triggers will tell you how they work.

Resources