How to manage an ImportHistory in a Database? - sql-server

I have a table ImportHistory in which I store history of importation. (Each time the user upload a file I store a row).
CREATE TABLE [dbo].[ImportHistory]
(
[Id] INT IDENTITY (1, 1) NOT NULL,
[Date] TIMESTAMP NOT NULL,
CONSTRAINT [PK_ImportHistory] PRIMARY KEY ([Id])
)
And I have also
CREATE TABLE [dbo].[Sales] (
[Id] VARCHAR (150) NOT NULL,
...
[ImportHistoryId] INT NOT NULL,
...
CONSTRAINT [FK_Sales_ImportHistory] FOREIGN KEY ([ImportHistoryId]) REFERENCES [dbo].[ImportHistory] ([Id])
);
The question is how to properly take the ID of ImportHistory and store it each time I insert a line in SALES for this import session ?

You insert a row in ImportHistory.
You SELECT SCOPE_IDENTITY() to get the ID of the newly created record.
You insert your Sales records, using the value acquired in Step 2 as the ImportHistoryID.
PS: The timestamp data type is not what you think it is. You probably want to use date or datetime2 instead.

Related

SQL FOREIGN KEY constraint in Insert

I've got a problem to insert some values into table.
Microsoft SQL server management shows that:
The INSERT statement conflicted with the FOREIGN KEY constraint "FK__Players__Menager__55D59338". The conflict occurred in database
"TransferyProjekt", table "dbo.Menagers", column 'idMenager'.
My Create table script.
CREATE TABLE Menagers (
idMenager INT IDENTITY(1,1) NOT NULL,
[name] VARCHAR(30) NOT NULL CHECK (name LIKE '[A-Z]%'),
surname VARCHAR(30) NOT NULL CHECK (surname LIKE '[A-Z]%'),
phoneNumber VARCHAR(18) NOT NULL CHECK (phoneNumber LIKE '+[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'),
PRIMARY KEY (idMenager)
);
CREATE TABLE Players (
idPlayer INT IDENTITY(1,1) NOT NULL,
[name] VARCHAR(30) NOT NULL,
surname VARCHAR(30) NOT NULL,
age DATE NOT NULL check (DATEDIFF(year,age,GETDATE()) > 18),
club INT NOT NULL,
Menager INT NOT NULL,
PRIMARY KEY (idPlayer),
FOREIGN KEY (club) REFERENCES Clubs(idClub),
FOREIGN KEY (Menager) REFERENCES Menagers(idMenager)
);
My insert look like.
INSERT INTO Menagers VALUES
('Adil','Green','+232247832'),
('Wicky','Dock','+301494064'),
('Alead','King','+447499384'),
('Darmian','Dagoly','+445587849'),
('Kamila','Dobra','+958789278'),
('Mateusz','Jankowiak','+849383098'),
('Lendy','Day','+448902920'),
('Martin','Lloyd','+501044468'),
('Adam','Dosh','+045033739'),
('Cristian','Cosy','+307748735'),
('Andrew','Lloyd','+635875452'),
('Matias','Banega','+520091224'),
('Carl','Rossi','+196935415'),
('Michał','Rolnik','+156541588'),
('Denny','Nowsky','+231785387'),
('Micky','Elly','+125774609'),
('George','Taylor','+094371433'),
('Barack','Obama','+916764868'),
('Jin','Chan','+906765545'),
('Lee','Konsu','+608935829'),
('Adam','Kenzo','+417708081'),
('Bryan','Along','+939454178'),
('Robert','Leey','+183354912'),
('Tom','Vardy','+576176145'),
('Kevin','Betword','+721582207');
INSERT INTO Players VALUES
('Lionel','Messi','1986-07-13','23','4'),
('Cristiano','Ronaldo','1986-04-11','23','5'),
('Sergio','Ramos','1986-09-07','23','12'),
('Łukasz','Piszczek','1986-11-20','23','14'),
('Robert','Lewandowski','1986-12-01','2','13'),
('Michał','Pazdan','1986-06-01','3','23'),
('Łukasz','Trałka','1986-05-02','7','20'),
('Łukasz','Teodorczyk','1986-04-14','6','18'),
('Mariusz','Miley','1985-03-06','3','26');
You should define column names if your source table and destination table has different column counts or different order
INSERT INTO Menagers([name],surname, phoneNumber )
VALUES
('Adil','Green','+232247832'),
('Wicky','Dock','+301494064'),
....
INSERT INTO Players([name], surname, age, club, Menager )
VALUES
('Lionel','Messi','1986-07-13','23','4'),
('Cristiano','Ronaldo','1986-04-11','23','5'),
...
Your foreign key and primary key columns are INT type. But, you are having following SQL
INSERT INTO Players VALUES
('Lionel','Messi','1986-07-13','23','4')
where last column belongs to foreign key column and your value is string.
A foreign key is a reference to a unique value in a different table, and SQL will ensure "referential integrity" - which means it won't let you end you with "orphaned" key references. When you insert a value to a foreign key column it must be a null or a existing reference to a row in the other table, and when you delete, you must delete the row containing the foreign key first, then the row it references.
If you don't, you will get an error such as you describe.
So enter the row into the "main" table first, then enter the "dependant" table information second.
In FK column I added unfortunately referece to row who is not exists in table Managers...
('Mariusz','Miley','1985-03-06','3','26');
but I don't have 26'th row in table Managers (Blame me, now) :(

How to set "auto insert" foreign key value by using SQL Server?

I have created two tables and also created a relationship between them.
Table students:
create table students
(
[StudentId] NVARCHAR(50) NOT NULL PRIMARY KEY,
[Name] NVARCHAR(50) NOT NULL
);
Table studentprofile:
create table studentprofile
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY(1, 1),
[StudentId] NVARCHAR(50) NOT NULL,
[Address] NVARCHAR(50) NOT NULL,
);
and relationship:
alter table studentprofile
add constraint students_studentprofile_FK
foreign key (StudentId)
references students(StudentId)
on delete cascade on update cascade
But, when I wrote this line:
insert into students values('110111', 'Marik')
the value of StudentId (in table studentprofile) wasn't updated automatically. Why?
Can you tell me how to set the value of StudentId (in table studentprofile) can be inserted automatically whenever I insert into table students?
There is no such thing as insert cascade.
You can implement such a thing by using a trigger for insert on your students table, inserting default values (or nulls) into the studentprofile table:
CREATE TRIGGER students_insert ON students AFTER INSERT
AS
INSERT INTO studentprofile(StudentId, Address)
SELECT StudentId, 'NO ADDRESS'
FROM inserted
Note that your Address column is defined as not null and has no default value, this is why I've used the hard coded 'NO ADDRESS' for it.
However, I agree with the comments on your question: you would be better off inserting the data to the student profile using a different insert statement (perhaps inside a transaction with the insert to students).

Load user extract with stored procedure

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

add a constraint on a datetime column

i want to to add a constraint onto a ID column and a date time column, so that an id can only be entered once in a day
alter table Table1
...
add constraint pk_id Primary Key (datetime,ID)
If an id has been inserted for the following datetime 2015-03-17 12:48:00, it would not get inserted again on the same datetime, but if the time changes to 2015-03-17 12:45:00 the id gets entered again.
Is there a way to add the constraint to just the date part of the datetime column?
I don't think you can but you have different alternatives:
Change your column to just have the date part populated
Create a computed column where you remove the time part and create the unique index used this column instead.
EDIT: as per #a-ツ comment there are other options:
Split the column in two, one to store the date and other to store the time part, so you can create de index over the date one
You have to give composite primary key or check constraint..
Check this example. For composite key, on design mode, just select both column and right click and select "primary-key".
CREATE TABLE [dbo].[Table_1](
[id] [int] NOT NULL,
[datecolumn] [datetime] NOT NULL,
[name] [varchar](50) NULL,
CONSTRAINT [PK_Table_1] PRIMARY KEY CLUSTERED
(
[id] ASC,
[datecolumn] ASC
)
) ON [PRIMARY]
GO
insert into Table_1 values (1, '2014-03-17 00:00:00.000', 'othercolumnvalue')
insert into Table_1 values (1, '2014-03-17 12:00:00.000', 'othercolumnvalue')
insert into Table_1 values (1, '2014-03-17 02:10:59.000', 'othercolumnvalue')
--this will give error as you already entered the same value.
insert into Table_1 values (1, '2014-03-17 00:00:00.000', 'othercolumnvalue')
how do I make a composite key with SQL Server Management Studio?

How to organize table for storing History in DB?

How can I organize additional table/tables for storing Order History?
Right now my DB structure is very simple, see code below:
CREATE TABLE category_table (
id SERIAL PRIMARY KEY NOT NULL,
name CHARACTER(250) NOT NULL
);
CREATE TABLE order_table (
id SERIAL PRIMARY KEY NOT NULL,
total_price DECIMAL(12, 2),
date TIMESTAMP WITH TIME ZONE DEFAULT now(),
product_amount INT
);
CREATE TABLE product_table (
id SERIAL PRIMARY KEY NOT NULL,
name CHARACTER VARYING(250) NOT NULL,
price DECIMAL(12, 2),
category_id INT,
CONSTRAINT category_fk FOREIGN KEY (category_id) REFERENCES category_table (id)
);
CREATE TABLE product_order_table (
product_id INT,
order_id INT,
CONSTRAINT product_fk FOREIGN KEY (product_id) REFERENCES product_table (id),
CONSTRAINT order_fk FOREIGN KEY (order_id) REFERENCES order_table (id)
);
I need to organize table/tables for Order History regarding to these two restrictions:
1. We can delete records form table `order_table`
2. We can change records in `order_table`
I need advice in a DB design.
It is safe to keep tracking the history with another table "order_table_history".
Create trigger function for this table "order_table" and on any operation like insert/update/delete the trigger insert one record in the history table "order_table_history".
Also you can add more columns in the history table, like "user_id/user_name" or "operation_status=delete/update".
CREATE TABLE order_table_history (
id SERIAL PRIMARY KEY NOT NULL,
order_id INT,
total_price DECIMAL(12, 2),
date TIMESTAMP WITH TIME ZONE DEFAULT now(),
product_amount INT
);

Resources