What statement to decide whether the insert statement goes through - sql-server

For example, I have 2 tables
Create table Authorized
(D_ID char(5), MNUM char(5), primary key(D_ID,MNUM),
foreign key(D_ID) REFERENCES Distributor(D_ID),
foreign key(MNUM) REFERENCES Model(MNUM));
Create table Orders
(ORDNO char(8), D_ID char(5), MNUM char(5),
Qty int, Date date, primary key (ORDNO,D_ID,MNUM),
foreign key(MNUM) REFERENCES Model(MNUM),
foreign key(D_ID) REFERENCES Distributor(D_ID));
INSERT INTO Authorized VALUES ('D0003', 'M0001');
INSERT INTO Authorized VALUES ('D0003', 'M0003');
How to I make sure that insert statement to the order table is restricted to D_ID that is authorized? Like if the statement is
INSERT INTO Orders VALUES
('20161232', 'D0003','M0002',2, '2016-12-22');
How do you prevent this insert statement from going through? AS M0002 is not authorized

You can create a Scalar function and use it in your table as:
CREATE FUNCTION IsAuthorized
(
#Value CHAR(5) --I think you mean "MNUM" column here
)
RETURNS BIT
AS
BEGIN
DECLARE #Result BIT = 0;
IF EXISTS (SELECT 1 FROM Authorized WHERE D_ID = #Value)
SET #Result = 1;
RETURN(#Result);
END;
GO
Here is how to use it in the table:
Create table Orders(
ORDNO char(8),
D_ID char(5) CONSTRAINT CHK_IsAuthorized CHECK(IsAuthorized(D_ID) = 1),
MNUM char(5),
...
...

Related

Problem with adding constraint that wont let me insert members with certain columns [duplicate]

I have this table
CREATE TABLE members
(
member_id INT PRIMARY KEY NOT NULL,
first_name VARCHAR(20),
last_name VARCHAR(20),
web_page VARCHAR(200),
e_mail VARCHAR(200),
cv VARCHAR(800),
dep_id INT,
teacher_id INT
);
and I want to create a trigger that if someone wants to insert a member which has a dep_id of 1 or 2 or 3.
And the teacher_id is different than NULL (as the teacher_id column is filled with either NULL or an id of another member)
I came up with this
CREATE TRIGGER employee_insup1
ON members
FOR INSERT, UPDATE
AS
DECLARE #dep_id INT, #teacher_id INT
SELECT #dep_id = i.dep_id, #teacher_id = i.teacher_id
FROM inserted i
IF ((#dep_id = 1) AND (#teacher_id != NULL))
BEGIN
RAISERROR('Teacher_id expects NULL',16,1)
ROLLBACK TRANSACTION
END
but after all if I try to insert a member with dep_id 1 and teacher_id 7(for example) it will be registered
You don't need a trigger for this. A check constraint is sufficient:
alter table members add constraint chk_members_dep_teacher
check (dep_id not in (1, 2, 3) or teacher_id is not null);
Specifically, this ensures that when dep_id is in one of those departments, then the teacher_id is not null. You might find the logic easier to follow as:
alter table members add constraint chk_members_dep_teacher
check (not (dep_id nt in (1, 2, 3) and teacher_id is null) );

Problem when trying to convert CHECK with subqueries to a function in SQL

I've been sitting with this problem for hours and I'm on the verge of going crazy. I want each Student to only be able to study a maximum of 45 courseCredits. At this point it prohibits me from adding more than a total of 45 CourseCredits. How am I supposed to rearrange the Function CheckCredits?
CREATE TABLE Student
(
studentID VARCHAR(5),
studentName VARCHAR(20),
studentAddress VARCHAR(20),
CONSTRAINT student_pk PRIMARY KEY(studentID)
)
CREATE TABLE Course
(
courseID VARCHAR(5),
courseCredits INT,
courseName VARCHAR(20),
CONSTRAINT course_pk PRIMARY KEY(courseID)
)
CREATE TABLE Studies
(
studentID VARCHAR(5),
courseID VARCHAR(5),
CONSTRAINT studies_pk PRIMARY KEY(studentID,courseID),
CONSTRAINT studies_fk_student FOREIGN KEY(studentID) REFERENCES Student(studentID) ON DELETE CASCADE,
CONSTRAINT studies_fk_course FOREIGN KEY(courseID) REFERENCES Course(courseID) ON DELETE CASCADE
)
CREATE TABLE HasStudied
(
studentID VARCHAR(5),
courseID VARCHAR(5),
grade VARCHAR(1),
CONSTRAINT has_studied_pk PRIMARY KEY(studentID,courseID),
CONSTRAINT has_studied_fk_student FOREIGN KEY(studentID) REFERENCES Student(studentID) ON DELETE CASCADE,
CONSTRAINT has_studied_fk_course FOREIGN KEY(courseID) REFERENCES Course(courseID) ON DELETE CASCADE
)
GO
CREATE FUNCTION CheckCredits()
RETURNS INT
AS
BEGIN
DECLARE #returnvalue INT
SELECT #returnvalue = (SELECT SUM(courseCredits) FROM Course c where c.courseID IN(
SELECT s.courseID FROM Studies s JOIN Student st ON s.studentID = st.studentID OR c.courseID = s.courseID))
RETURN #returnvalue
END;
GO
ALTER TABLE Studies
ADD CONSTRAINT chkCredits CHECK (dbo.CheckCredits() <= 45);
INSERT INTO Student VALUES('S1', 'Joe', 'Street')
INSERT INTO Student VALUES('S2', 'Joe', 'Street')
INSERT INTO Student VALUES('S3', 'Joe', 'Street')
INSERT INTO Student VALUES('S4', 'Joe', 'Street')
INSERT INTO Course VALUES('C1', 45, 'Biology')
INSERT INTO Course VALUES('C2', 15, 'History')
INSERT INTO Course VALUES('C3', 35, 'English')
INSERT INTO Course VALUES('C4', 20, 'Music')
INSERT INTO Studies VALUES('S1', 'C1')
INSERT INTO Studies VALUES('S2', 'C2')
INSERT INTO Studies VALUES('S3', 'C3')
Change your function to return the max credits per student. Like this:
CREATE FUNCTION CheckCredits()
RETURNS INT
AS
BEGIN
DECLARE #returnvalue INT
SELECT TOP 1 #returnvalue = SUM(courseCredits)
FROM Studies s
JOIN Course c ON s.courseID = c.courseID
GROUP BY s.studentID
ORDER BY SUM(courseCredits) desc
RETURN #returnvalue
END;
GO

Creting FOREIGN KEY constraint on multiple columns with one of them being constant value

When I have table with PRIMARY KEY from 2 columns:
CREATE TABLE SizeTypes
(
TypeID tinyint NOT NULL,
SizeID tinyint NOT NULL,
Name varchar(100) NOT NULL,
CONSTRAINT PK_SizeType
PRIMARY KEY (TypeID, SizeID)
)
How can I create second table with a foreign key that have 1st constant value and 2nd from column like below:
CREATE TABLE Something
(
ID INT IDENTITY(1,1) PRIMARY KEY,
SizeTypeID_1 TINYINT,
SizeTypeID_2 TINYINT,
SizeTypeID_3 TINYINT,
CONSTRAINT FK_Something_SizeTypes_1
FOREIGN KEY (1, SizeTypeID_1)
REFERENCES SizeTypes(TypeID, SizeID),
CONSTRAINT FK_Something_SizeTypes_2
FOREIGN KEY (2, SizeTypeID_2)
REFERENCES SizeTypes(TypeID, SizeID),
CONSTRAINT FK_Something_SizeTypes_3
FOREIGN KEY (3, SizeTypeID_3)
REFERENCES SizeTypes(TypeID, SizeID)
)
This can be done using FOREIGN KEY, if yes then how?
If no then what other ways to do this I have? Triggers on INSERT and UPDATE for table something and on DELETE for table SizeTypes? Any other choices I have?
It looks like the following code will let you create suitable check constraints with the check implemented by a separate function:
-- Create the first table.
create table SizeTypes(
TypeId TinyInt not NULL,
SizeId TinyInt not NULL,
Name VarChar(100) not NULL,
constraint PK_SizeType primary key ( TypeId, SizeId ) );
go
-- Create a function to implement the logic for the check constraint.
create function CheckSizeTypeId(
#TypeId TinyInt, #SizeId TinyInt )
returns Int
as begin
-- Replace the following statement with the logic for your check.
if #SizeId >= 0 and #SizeId <= ( select SizeId from SizeTypes where TypeID = #TypeID )
return 1;
return 0;
end;
go
-- Create the second table with the check constraints.
create table Something(
Id Int identity(1,1) primary key,
SizeTypeId_1 TinyInt,
SizeTypeId_2 TinyInt,
SizeTypeId_3 TinyInt,
constraint Check_SizeTypeId_1 check ( dbo.CheckSizeTypeId( 1, SizeTypeId_1 ) = 1 ),
constraint Check_SizeTypeId_2 check ( dbo.CheckSizeTypeId( 2, SizeTypeId_2 ) = 1 ),
constraint Check_SizeTypeId_3 check ( dbo.CheckSizeTypeId( 3, SizeTypeId_3 ) = 1 ) );
go
-- Houseclean.
drop table SizeTypes;
drop table Something;
drop function CheckSizeTypeId;
Note that the constraints restrict what you can do with values in Something. Changes in SizeTypes will not revalidate data in Something, though that could be implemented in a trigger on SizeTypes.

Why does SCOPE_IDENTITY() return NULL after insert on one table and not on the other?

Why does SCOPE_IDENTITY() return NULL after inserting a row in the ComponentAssociation table (as ##IDENTITY returns the right Id)
while SCOPE_IDENTITY() returns the right Id after inserting a row in the CustomerProjectAssociation table ?
The two association tables are created the same way.
Here is an extract of the table creation script:
-- Creating table 'CustomerProjectAssociation'
CREATE TABLE [dbo].[CustomerProjectAssociation]
(
[Id] int IDENTITY(1,1) NOT NULL,
[CustomerId] int NOT NULL,
[ProjectId] int NOT NULL,
[CreationDate] datetime NOT NULL CONSTRAINT DF_CustomerProjectAssociation_CreationDate DEFAULT (SYSUTCDATETIME()),
[LastModificationDate] datetime NOT NULL CONSTRAINT DF_CustomerProjectAssociation_ModificationDate DEFAULT (SYSUTCDATETIME())
);
GO
-- Creating table 'ComponentAssociation'
CREATE TABLE [dbo].[ComponentAssociation]
(
[Id] int IDENTITY(1,1) NOT NULL,
[EcuId] int NOT NULL,
[CreationDate] datetime NOT NULL CONSTRAINT DF_ComponentAssociation_CreationDate DEFAULT (SYSUTCDATETIME()),
[LastModificationDate] datetime NOT NULL CONSTRAINT DF_ComponentAssociation_ModificationDate DEFAULT (SYSUTCDATETIME()),
[ComponentId] int NOT NULL
);
GO
-- Creating primary key on [Id] in table 'CustomerProjectAssociation'
ALTER TABLE [dbo].[CustomerProjectAssociation]
ADD CONSTRAINT [PK_CustomerProjectAssociation]
PRIMARY KEY CLUSTERED ([Id] ASC);
GO
-- Creating primary key on [Id] in table 'ComponentAssociation'
ALTER TABLE [dbo].[ComponentAssociation]
ADD CONSTRAINT [PK_ComponentAssociation]
PRIMARY KEY CLUSTERED ([Id] ASC);
GO
And here are two queries executed on the database from SQL Server Management Studio:
INSERT [dbo].[CustomerProjectAssociation]([CustomerId], [ProjectId])
VALUES (1, 2)
SELECT
[RowCount] = ##RowCount,
[##IDENTITY] = ##IDENTITY,
[SCOPE_IDENTITY] = SCOPE_IDENTITY()
Result:
RowCount ##IDENTITY SCOPE_IDENTITY
1 24 24
INSERT [dbo].[ComponentAssociation]([EcuId], [ComponentId])
VALUES(1, 2)
SELECT
[RowCount] = ##RowCount,
[##IDENTITY] = ##IDENTITY,
[SCOPE_IDENTITY] = SCOPE_IDENTITY()
Result:
RowCount ##IDENTITY SCOPE_IDENTITY
1 613 NULL
OK, the issue is solved.
Found the solution here: error when inserting into table having instead of trigger from entity data framework
I added the following select statement at the end of the instead of insert,update trigger returning all the computed columns:
select [Id], [CreationDate], [LastModificationDate] from {0}.[dbo].[ComponentAssociation] where ##ROWCOUNT > 0 and Id = scope_identity()

How to allowed null Auto_Increment primary key in SQL Server

midx column is the primary key that using auto increment (identity 1,1).
When I try to insert data using this query, that is a problem:
Insert into coordinfo(mdate, X, Y, lat, lon)
values (GETDATE(), 12344, 334, 34.775, 123.554);
I want to increase the midx by automatically without entering the primary key.
Thanks!
Normally a primary key column cannot be null, since it has to be a clustered index on the table.
In order to get the effect you want, you should create a keys table with a non-null identity column.
If your table is defined as follows, with an insert trigger, your insert DML will yield an auto-generated value for midx:
CREATE TABLE keyTable
(
[key] int identity(1,1) primary key not null,
date datetime
)
CREATE TRIGGER myTable_increment_midx ON myTable
after INSERT
AS
BEGIN
DECLARE #key int
INSERT INTO keyTable (date) values (getdate())
SET #key = ##IDENTITY
UPDATE t
set t.midx = #key
FROM mytable t join INSERTED i on i.mdate = t.mdate and ...
END
CREATE TABLE myTable
(
mdate DATETIME,
udate DATETIME,
midx INT PRIMARY KEY NULL, --again, you shouldn't be allowed to do this
X INT,
Y INT,
lat DECIMAL(9, 6),
lon DECIMAL(9, 6)
)
you can use compete column:
ALTER TABLE coordinfo ADD midx AS idx*100

Resources