I have created the audit table similar to the below code which logs the changes made on the source table. My question is can a audit table contain newly inserted record or it should contain only the updated records/history since the new record is there in source table ?
I am Looking for pros/cons on each approach and best practice.
create table tblOrders
(
OrderID integer Identity(1,1) primary key,
OrderApprovalDateTime datetime,
OrderStatus varchar(20)
)
create table tblOrdersAudit
(
OrderAuditID integer Identity(1,1) primary key,
OrderID integer,
OrderApprovalDateTime datetime,
OrderStatus varchar(20),
UpdatedBy nvarchar(128),
UpdatedOn datetime
)
go
create trigger tblTriggerAuditRecord on tblOrders
after update, insert
as
begin
insert into tblOrdersAudit
(OrderID, OrderApprovalDateTime, OrderStatus, UpdatedBy, UpdatedOn )
select i.OrderID, i.OrderApprovalDateTime, i.OrderStatus, SUSER_SNAME(), getdate()
from tblOrders t
inner join inserted i on t.OrderID=i.OrderID
end
go
It is totally based on your case,
But I would like to have the Audit table to have all records, the new inserted and the updated, so that I can view, check history, do time line calculations,... using just the Audit table as a separate entity without going back to the original table.
Also It might be helpful if I want to roll back to a certain record (it could be the first inserted one)
Related
I'm making a C#/SQL/LINQ web form site to handle a single season in Formula 1. The tricky part appears to be designing tables for single races, each describing around 20 drivers, teams they drive with (2 drivers per team, not necessarily the same drivers all season) and position in the race.
So far I have the tables
Driver (driverid(PK), firstname, lastname, teamid(FK)
Team (teamid(PK), teamname, engine)
Circuit (circuitid, circuitname, country)
For storing race results I have a Race table
dbo.Race
raceId(PK)
date
circuitId(FK)
and a table for each race with 20 records which will be linked to corresponding entry in Race (analogous to an List as a class field in object-oriented design) eg.
dbo.Australia2018
driverid(FK)
teamid(FK)
finalposition
finaltime
The alternative to having a new table for each race was to have 20 other fields in the Race table but either way there is a lot of data to be stored. Obviously I need to search through each race to total points for Drivers and Constructors (Team) results.
For this amount of data there will be no 'correct' way of designing, but is there a neater way I'm missing here?
Something like this should do what you wanted.
You could create a table for each driver, this would hold all of the information about that driver, it would also have a foreign key for the team they belong to. This would allow you to query all drivers & teams seperately to races.
CREATE TABLE Driver
(
Driver_ID INT IDENTITY(1,1) PRIMARY KEY,
Forename varchar(100),
Surname varchar(100),
Team_ID INT
)
You could use a linking table to link the driver to the team and when their realationship started and ended
CREATE TABLE Driver_Team
(
Driver_Team_ID INT IDENEITY(1,1) PRIMARY KEY,
Team_ID INT,
Driver_ID INT,
Start_date datetime,
End_date datetime
)
There would be another table for the teams, all team information could live here.
CREATE TABLE Teams
(
Team_ID INT IDENTITY(1,1) PRIMARY KEY,
Team_Name varchar(100)
)
ALTER TABLE Driver ADD CONSTRAINT FK_TeamID FOREIGN KEY (Team_ID) REFERENCES Teams (Team_ID)
A table for the circuits or tracks, here you could put all information about the track
CREATE TABLE Circuit
(
Circuit_ID INT IDENTITY(1,1) PRIMARY KEY,
CircuitName varchar(200)
)
Now the race table you would have the driver id, team id and circuit id these are foreign keys from other tables, then you could have all the other race information such as the race date, final position and final time
CREATE TABLE Race
(
Race_ID INT IDENTITY(1,1) PRIMARY KEY,
Race_Date DATETIME,
Driver_ID INT,
Team_ID INT,
Circuit_ID INT,
FinalPosition TINYINT,
Final_Time DATETIME
)
ALTER TABLE Race ADD CONSTRAINT FK_Race_DriveID FOREIGN KEY (Race_ID) REFERENCES Driver(Race_ID);
ALTER TABLE Race ADD CONSTRAINT FK_Race_Team FOREIGN KEY (Team_ID) REFERENCES Teams(Team_ID);
ALTER TABLE Race ADD CONSTRAINT FK_Race_CircuitID FOREIGN KEY (Circuit_ID) REFERENCES Circuit(Circuit_ID);
Once you have all of your data in the tables you could select the data from the database using something like this.
SELECT
D.Forename,
D.Surname,
T.TeamName,
C.CircuitName,
R.FinalPosition,
R.Final_Time
FROM Race R
INNER JOIN Driver D ON
D.Driver_ID = R.Driver_ID
INNER JOIN Teams T ON
T.Team_ID = R.Team_ID
INNER JOIN Circuits C ON
C.Circuit_ID = R.Circuit_ID
WHERE C.CircuitName = 'Silverstone' AND D.Forename = 'Lewis'
I am storing identity value of one table to another table in the foreign key but when trying to create a relationship, I get an error 332.
ALTER proc [dbo].[spRegisterUser]
#Doj date,
#UserName nvarchar(100),
#Password nvarchar(10),
#Reference nvarchar(50),
#Aadhar nvarchar(50),
#Email nvarchar(50)
AS
BEGIN
Declare #count int
Declare #ReturnCode int
Select #count = COUNT(UserName)
from tblUsers where UserName = #UserName
if #count > 0
Begin
Set #ReturnCode = -1
End
Else
Begin
Set #ReturnCode = 1
insert into tblUsers (DoJ,UserName,Password,Reference,Aadhar,Email)
Output inserted.User_ID into tblUserProfiles(UserID)
values (#DoJ,#UserName,#Password,#Reference,#Aadhar,#Email)
End
Select #ReturnCode as ReturnValue
end
Error is:
The target table 'tblUserProfiles' of the OUTPUT INTO clause cannot be on either side of a (primary key, foreign key) relationship. Found reference constraint 'FK_tblUserProfiles_tblUsers'.
How to overcome this problem? I need PK FK relationship and I also want FK value automatically saved in the column.
Please find a solution for me. Thanks
Since this stored procedure is really only ever inserting one single row of data, you could use this code:
declare #NewUserID INT
insert into tblUsers (DoJ, UserName, Password, Reference, Aadhar, Email)
values (#DoJ, #UserName, #Password, #Reference, #Aadhar, #Email);
-- get the newly created ID for the new user
SELECT #NewUserID = SCOPE_IDENTITY();
-- insert into the other table
INSERT INTO dbo.tblUserProfiles (UserID)
VALUES (#NewUserID);
This assumes that the User_ID column in the tblUsers table is in fact an Identity column.
Another option would be to use a trigger for insert on the users table, that will insert records into the user profiles table whenever they are inserted into the users table. The advantage of this approach is that even if users are inserted directly to your table (I mean, not using your stored procedure), they will still have a record created in the user profiles table:
CREATE TRIGGER tblUsers_INSERT ON tblUsers
FOR INSERT
AS
BEGIN
INSERT INTO tblUserProfiles(UserId)
SELECT User_ID
FROM Inserted
END
I want to automatically insert create date time in a column for every new row and update time when that row is updated in updated time column. I know it can be done using sql constraint.
And I have done for create date:
ALTER TABLE Persons
ADD CONSTRAINT CO_Persons_AutoCreateDate DEFAULT GetDate() for CreatedDate
But how do you do that for updating record in updated date?
You need to create a trigger something like this:
CREATE TRIGGER tr_somename
ON Persons
FOR UPDATE
BEGIN
SET NOCOUNT ON;
UPDATE T
SET T.createddate = GETDATE()
FROM persons T INNER JOIN INSERTED I
ON t.pk_column = I.pk_column
END
In INSERT statement use all columns except CO_Persons_AutoCreateDate.
For example if you have table Persons like this:
Create Table Persons
(
A int,
B int,
CO_Persons_AutoCreateDate datetime
)
use INSERT statement:
insert into Persons (A,B) values (1,1)
Forgive me as I'm new to databases. I have a recipe form that the user can enter several ingredients and the recipe name into. With this form I have the following tables: Recipe{recipeID, recipeName} RecipeIngredient{recipeID,ingredientID,measurement} Ingredient{ingredientID, ingredientName}
RecipeIngredients acts as an intermediate table for the one to many relationship (one recipe to many ingredients). I assigned recipeID as a foreign key inside that table to the primary key recipeID in the recipe table. I thought a foreign key would update based on the primary key updating, but if I insert into the Recipe table the RecipeIngredients table does nothing.
The recipe and the ingredients are assigned ID's automatically.I'm trying to link the ID of one recipe to the auto assigned ID's of each ingredient. For example if the user enters in 8 ingredients, a unique ID is assigned to each of those ingredients. I need the RecipeIngredients table to duplicate those ID's and associate them with the auto-assigned Recipe ID.
I've tried several solutions for updating a column based on changes in other tables. I've tried modifying this MySQL update statement and also modifying this SQL server but I can't seem to get either of them to work.
Suggestions?
In general, you will need to get the new recipeID from the first insert, then use that when you insert into the ingredients table.
Do you have access to the newly inserted recipeID from the insert into the recipe table? How are you doing this insert?
Here is an example Stored Procedure which goes into the database to do the insert / update and return the id:
CREATE PROCEDURE [dbo].[spAlertCategoryInsUpd]
#AlertCategoryID int,
#AlertID int,
#CategoryID int,
#ScreenSortOrder int
AS
SET NOCOUNT ON
IF EXISTS(SELECT [AlertCategoryID] FROM [dbo].[AlertCategories] WHERE [AlertCategoryID] = #AlertCategoryID)
BEGIN
UPDATE [dbo].[AlertCategories] SET
[AlertID] = #AlertID,
[CategoryID] = #CategoryID,
[ScreenSortOrder] = #ScreenSortOrder
WHERE
[AlertCategoryID] = #AlertCategoryID
SELECT #AlertCategoryID as AlertCategoryID;
END
ELSE
BEGIN
INSERT INTO [dbo].[AlertCategories] (
[AlertID],
[CategoryID],
[ScreenSortOrder]
)
OUTPUT INSERTED.AlertCategoryID AS AlertCategoryID
VALUES (
#AlertID,
#CategoryID,
#ScreenSortOrder
)
;
END
I'm doing some web scraping to build up a personal SQL database. As I'm looping through the web requests, I'm adding records. The only thing is, duplicates sometimes appear in the web requests and I want to make sure to only add a record if it doesn't already exist in my database. I gather this can be done by performing an SQL query before every insert to make sure that record hasn't already been added, but is this the best way to do it? Would it make more sense to build up a Generic.List first, and then do all my database inserts at the end?
You can create a stored procedure that will attempt to update a record and then insert if the update query did not update any rows. This will minimize the number of queries that need to be run and prevent checking for the row's existence. A little bit of Googling found this. The second option looks like it might be what you are looking for.
/*
Same SP is used to INSERT as well as UPDATE a table.
Here we are avoid unnecessary checking of whether the record exists or not.
Instead try to Update directly. If there is no record then ##RowCount would be 0.
Based on that Insert it as a new record.
*/
CREATE PROCEDURE uspUPSert_Ver2
(
#empID INT,
#fname VARCHAR(25),
#lname VARCHAR(25),
#emailid VARCHAR(50)
)
AS
BEGIN
SET NOCOUNT ON
BEGIN TRAN
UPDATE tblUpsert WITH (SERIALIZABLE)
SET emailid = #emailid ,
firstname = #fname ,
lastname = #lname
WHERE EmpID = #empID
IF ##ROWCOUNT = 0
BEGIN
INSERT INTO tblUpsert VALUES (#empID, #fname, #lname, #emailid)
END
COMMIT TRAN
END
GO
seems like you would need either a primary key or a unique constraint on the columns that identify the rows as duplicate. Then if there is an error in the insert that violates the unique constraint the row won't insert. Catch the exception, log it to a different table for future validation and move to the next row.
http://www.w3schools.com/sql/sql_unique.asp