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.
Related
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?
This is a question more about design than about solving a problem.
I created three tables as such
CREATE TABLE [CapInvUser](
[UserId] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](150) NOT NULL,
[AreaId] [int] NULL,
[Account] [varchar](150) NULL,
[mail] [varchar](150) NULL,
[UserLevelId] [int] NOT NULL
)
CREATE TABLE [CapInvUserLevel](
[UserLevelId] [int] IDENTITY(1,1) NOT NULL,
[Level] [varchar](50) NOT NULL
)
CREATE TABLE [CapInvUserRegistry](
[UserRegistryId] [int] IDENTITY(1,1) NOT NULL,
[UserLevelId] int NOT NULL,
[DateRegistry] DATE NOT NULL,
[RegistryStatus] VARCHAR(50) NOT NULL,
)
With a view that shows all the data on the first table with "AreaId" being parsed as the varchar identifier of that table, the UserLevel being parsed as the varchar value of that table, and a join of the registry status of the last one.
Right now when I want to register a new user, I insert into all three tables using separate queries, but I feel like I should have a way to insert into all of them at the same time.
I thought about using a stored procedure to insert, but I still don't know if that would be apropiate.
My question is
"Is there a more apropiate way of doing this?"
"Is there a way to create a view that will let me insert over it? (without passing the int value manually)"
--This are just representations of the tables, not the real ones.
-- I'm still learning how to work with SQL Server properly.
Thank you for your answers and/or guidance.
The most common way of doing this, in my experience, is to write a stored procedure that does all three inserts in the necessary order to create the FK relationships.
This would be my unequivocal recommendation.
I am looking for some advise. I have a SQL Server table called AuditLog and this table records any action/changes that happens to our DB from our web application.
I am trying to build some reports and anytime I try to pull data from this table it makes my query run from seconds to 10mins+. Just doing a
select * from dbo.auditlog
takes about 2hours+.
The table has 77 million rows and is growing. Anyhow, only thoughts at this moment is to do an index but that would slow down inserts. Not sure how much that would affect performance but have held back on it. Other thoughts were to partition the table or do an index view but we are running SQL Server 2014 Standard Edition and those options are not supported.
Here is the table create statement:
CREATE TABLE [dbo].[AuditLog]
(
[AuditLogId] [uniqueidentifier] NOT NULL,
[UserId] [uniqueidentifier] NULL,
[EventDateUtc] [datetime] NOT NULL,
[EventType] [char](1) NOT NULL,
[TableName] [nvarchar](100) NOT NULL,
[RecordId] [nvarchar](100) NOT NULL,
[ColumnName] [nvarchar](100) NOT NULL,
[OriginalValue] [nvarchar](max) NULL,
[NewValue] [nvarchar](max) NULL,
[Rams1RecordID] [uniqueidentifier] NULL,
[Rams1AuditHistoryID] [uniqueidentifier] NULL,
[Rams1UserID] [uniqueidentifier] NULL,
[CreatedBy] [uniqueidentifier] NULL,
[CreatedDate] [datetime] NULL DEFAULT (getdate()),
[OriginalValueNiceName] [nvarchar](100) NULL,
[NewValueNiceName] [nvarchar](100) NULL,
CONSTRAINT [PK_AuditLog]
PRIMARY KEY CLUSTERED ([TableName] ASC, [RecordId] ASC, [AuditLogId] ASC)
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[AuditLog] WITH NOCHECK
ADD CONSTRAINT [FK_AuditLog_User]
FOREIGN KEY([UserId]) REFERENCES [dbo].[User] ([UserID])
GO
ALTER TABLE [dbo].[AuditLog] CHECK CONSTRAINT [FK_AuditLog_User]
GO
ALTER TABLE [dbo].[AuditLog] WITH NOCHECK
ADD CONSTRAINT [FK_AuditLog_UserCreatedBy]
FOREIGN KEY([CreatedBy]) REFERENCES [dbo].[User] ([UserID])
GO
ALTER TABLE [dbo].[AuditLog] CHECK CONSTRAINT [FK_AuditLog_UserCreatedBy]
GO
With something that big there are a couple of things you might try.
The first thing you need to do is define how you accessing the table MOST of the time and index accordingly.
I would hope you are not do a select * from AuditLog without any filtering for a reporting solution - it shouldn't even be an option.
Finally, instead of indexed views or partitioning, you might consider a partitioned view.
A partitioned view is basically breaking your table up, physically into smaller meaningful tables - based on date or type or object or however you are MOST often accessing it. Each table is then indexed separately giving you much better stats and if you in 2012 or higher you can take advantage of ColumnStore, assuming you use something like a DATE to group the data.
Create a view that spans all of the tables and then report based on the view. Since you already grouped your data by how you MOST often will access it, your filter will act similarly to partition exclusion and get you to your data faster.
Of course this will result in a little more maintenance and some code change, but be well worth the effort if you are storing that much data and more in a single table.
I have a ASP MVC web application that is required to load a user extract each day from a file. The users in the database should be updated accordingly: deleted if not in source, updated if in source and target, and created if only in source. While doing this, certain rights should also automatically be given to the users. If there is any error, nothing should happen at all.
First I tried to do this with Entity Framework, but the SaveChanges call takes around two minutes to return, which is a lot for the relatively small amount of users (~140 000).
My idea now is to write a stored procedure that would do the updating. I would pass the list of new users as a parameter. The type of my temporary table:
CREATE TYPE [dbo].[TempUserType] AS TABLE
(
[Uid] NVARCHAR(80) NOT NULL PRIMARY KEY,
[GivenName] NVARCHAR(80) NOT NULL,
[FamilyName] NVARCHAR(80) NOT NULL,
[Email] NVARCHAR(256) NOT NULL,
[GiveRight1] BIT NOT NULL,
[GiveRight2] BIT NOT NULL,
[GiveRight3] BIT NOT NULL
)
The users:
CREATE TABLE [dbo].[User] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Uid] NVARCHAR (80) NOT NULL,
[GivenName] NVARCHAR (80) NOT NULL,
[FamilyName] NVARCHAR (80) NOT NULL,
[Email] NVARCHAR (256) NOT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC),
UNIQUE NONCLUSTERED ([Uid] ASC)
);
The user roles:
CREATE TABLE [dbo].[UserRole] (
[UserId] INT NOT NULL,
[RoleId] INT NOT NULL,
CONSTRAINT [PK_UserRole] PRIMARY KEY CLUSTERED ([UserId] ASC, [RoleId] ASC),
CONSTRAINT [FK_UserRole_User] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User] ([Id]),
CONSTRAINT [FK_UserRole_Role] FOREIGN KEY ([RoleId]) REFERENCES [dbo].[Role] ([Id])
);
The procedure I am stuck writing:
CREATE PROCEDURE [dbo].[UpdateUsers]
#extractedUsers TempUserType READONLY
AS
BEGIN TRANSACTION
MERGE
[dbo].[User] AS trg
USING
#extractedUsers AS src
ON
(trg.[Uid] = src.[Uid])
WHEN MATCHED THEN
UPDATE SET
trg.GivenName = src.GivenName,
trg.FamilyName = src.FamilyName,
trg.Email = src.Email
WHEN NOT MATCHED BY TARGET THEN
INSERT
([Uid], GivenName, FamilyName, Email)
VALUES
(src.[Uid], src.GivenName, src.FamilyName, src.Email)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
COMMIT TRANSACTION
My question: is the use of a procedure with merge appropriate in this case to achieve the performance improvement over EF? How can I attribute roles according to the 3 boolean values that are in the source table?
Roles can be hadcoded, meaning I know that the Right1 corresponds to the RoleId 1, Right 2 to RoleId 2 and Right 3 to RoleId3.
After reading the question I want to leave an idea for the solution.
For me it makes more sense to have an IF / ELSE for calling the update or the insert, not using the merge since you need the UserId that you are updating/inserting to add it's role permissions.
You can check if UId exists and if so update the user details, if does not exists then create and keep the new Identity value.
In both cases, when having the user ID add the corresponding permissions according to the boolean values with IF statements.
Pseudo-code:
If UserId exists in UsersTable
Update
Store UserId
Else
Insert
Store created UserId (using the ##IDENTITY)
If bool1 add permission 1
If bool3 add permission 2
If bool3 add permission 3
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;