Trigger with a RAISERROR and ELSE case issue - sql-server

I am trying to make a bit of code that takes in 2 separate columns, a month and a year. From there I want it to see if those numbers entered have already passed or not. If they have passed, cause an error to pass and stop the transaction. Otherwise, I want it to continue on and insert new information into the table. I know I am close on getting this to work, but I cant seem to get the RAISERROR to fire. I am sure it has to do with the fact I am pretty new at this and I am missing some small detail.
Currently I am taking the two months in as variables and the making a third variable to use to turn the other two into a proper datetime format. Then I use the datediff function to try and see if it has passed that way. To no avail though. I keep getting the insert function going, even if the card date is old.
USE AdventureWorks2012
GO
CREATE TRIGGER BadCreditCardDate
ON Sales.CreditCard
INSTEAD OF INSERT
AS
Begin
DECLARE #ExpMonth tinyint,
#ExpYear smallint,
#ExpMonthYear datetime
SELECT #ExpMonth=ExpMonth,
#ExpYear=ExpYear,
#ExpMonthYear = #ExpYear + '-' + #ExpMonth + '-00'
FROM INSERTED
IF
DATEDIFF(MONTH,#ExpMonthYear,GETDATE()) < 0
BEGIN
RAISERROR ('The Credit Card you have entered has expired.' ,10,1)
ROLLBACK TRANSACTION
END
ELSE
Begin
INSERT INTO CreditCard (CardType, CardNumber, ExpMonth, ExpYear, ModifiedDate)
Select CardType, CardNumber, ExpMonth, ExpYear, ModifiedDate FROM inserted
END
End

I think there is a simpler way to check for expiration:
CREATE TRIGGER BadCreditCardDate
ON Sales.CreditCard
INSTEAD OF INSERT
AS
BEGIN
IF EXISTS (
SELECT 1
FROM inserted
WHERE (YEAR(GETDATE()) > ExpYear) OR (YEAR(GETDATE()) = ExpYear AND MONTH(GETDATE()) > ExpMonth)
)
BEGIN
RAISERROR ('The Credit Card you have entered has expired.' ,10,1)
ROLLBACK TRANSACTION
END
ELSE
BEGIN
INSERT INTO CreditCard (CardType, CardNumber, ExpMonth, ExpYear, ModifiedDate)
SELECT CardType, CardNumber, ExpMonth, ExpYear, ModifiedDate
FROM inserted
END
END
In this way you effectively check every record to be inserted in CreditCard.

Related

SQL Server stored procedure with case

I am trying to create a stored procedure in SQL Server 2019 where you should insert an employee number and an amount of salary increase by the keyboard.
You should add the amount to the salary if the employee number does not have any commission.
If he has some commission then you should show an error message. You should also show an error message if the employee number does not exist in the table
I am trying to solve this exercise with a case structure but I am not able to do it
Can someone help me?
Thanks in advance
CREATE PROCEDURE subir_sueldo
#emp int,
#com int
AS
BEGIN
SELECT EMP_NO
FROM EMPLE
CASE
WHEN COMISION IS NULL
THEN
UPDATE EMPLE
SET SALARIO = SALARIO + #com
WHERE EMP_NO = #emp
WHEN COMISION IS NOT NULL
THEN
PRINT 'the comission is not null '
WHEN #emp NOT IN (SELECT #emp FROM EMPLE WHERE DEPT_NO = #emp)
THEN
PRINT 'user does not exist'
ELSE
BREAK
END
END
CASE in T-SQL/SQL Server is an expression that returns one of several possible, atomic, single values - it is NOT a flow control statement ..... for that, you need to use IF ... ELSE ... statements - something like this:
CREATE PROCEDURE subir_sueldo
#emp INT,
#com INT
AS
BEGIN
-- you didn't show or tell what datatype "Commission"
-- (should be with TWO "m" and "s" in English) is - just guessing here!
DECLARE #Commission DECIMAL(20,4);
SELECT #Commission = COMMISSION
FROM EMPLE
WHERE EMP_NO = #emp;
IF (#Commission IS NULL)
UPDATE EMPLE
SET SALARIO = SALARIO + #com
WHERE EMP_NO = #emp
ELSE
PRINT 'The commission is not null '
-- you would probably want to check this *FIRST* and stop the
-- procedure if your #emp doesn't match an existing user.....
IF #emp NOT IN (SELECT #emp FROM EMPLE WHERE DEPT_NO = #emp)
PRINT 'user does not exist'
ELSE
BREAK
END
As an alternative idea, you could do something like this, that tries to UPDATE the table, and then if it reports no rows were updated, let's the user know; though this will not give different errors for if the user does not exist or if they have a commission (though sometimes ambiguity is good).
CREATE PROCEDURE dbo.subir_sueldo #emp int, #com int AS
BEGIN
SET NOCOUNT ON;
UPDATE dbo.EMPLE
SET SALARIO = SALARIO +#Com
WHERE EMP_NO = #emp
AND COMISION IS NULL;
IF ##ROWCOUNT = 0
--I use THROW as it seems like you actually want an error
--Use an error number appropriate for your environment.
THROW 65489, N'User does not exist, or Commission is not NULL.',10;
END;

SQL Server: the ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION

I have a trigger that works (it fires when it has to) but I still get an error.
I understand the error but I don't know how to resolve it.
I tried to put some BEGIN TRANSACTION with all the code who go with it but I think my grammar is wrong because I always get a timeout!
So my question is, where exactly do I have to put my BEGIN TRANSACTION statements in my code?
Also, do I need 3 BEGIN TRANSACTION statements since I have 3 ROLLBACK?
Thank you in advance!
My code:
ALTER TRIGGER [dbo].[Tr_CheckOverlap]
ON [dbo].[Tranche]
FOR INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #IdVol INT, #IdTranche INT,
#AgeMinInserted DATE, #AgeMaxInserted DATE
SELECT #AgeMinInserted = t.TRA_Age_Min
FROM Tranche t
JOIN inserted AS i ON t.TRA_Id = i.TRA_Id
SELECT #AgeMaxInserted = t.TRA_Age_Max
FROM Tranche t
JOIN inserted AS i ON t.TRA_Id = i.TRA_Id
DECLARE CR_TrancheVol CURSOR FOR
SELECT t.TRA_Vol_Id,t.TRA_Id
FROM Tranche t
JOIN inserted AS i ON t.TRA_Vol_Id = i.TRA_Vol_Id;
OPEN CR_TrancheVol
FETCH CR_TrancheVol INTO #IdVol, #IdTranche
WHILE( ##FETCH_STATUS = 0)
BEGIN
DECLARE #AgeMin DATE, #AgeMax DATE
SELECT #AgeMin = t.TRA_Age_Min
FROM Tranche t
WHERE t.TRA_Id = #IdTranche
SELECT #AgeMax = t.TRA_Age_Max
FROM Tranche t
WHERE t.TRA_Id = #IdTranche
IF #AgeMinInserted > #AgeMin AND #AgeMinInserted < #AgeMax
BEGIN
PRINT 'Trans1'
RAISERROR('Overlap: Date de naissance minimum déjà couverte', 1, 420)
ROLLBACK TRANSACTION
END
IF #AgeMaxInserted > #AgeMin AND #AgeMaxInserted < #AgeMax
BEGIN
PRINT 'Trans2'
RAISERROR('Overlap: Date de naissance maximum déjà couverte', 1, 421)
ROLLBACK TRANSACTION
END
IF #AgeMinInserted < #AgeMin AND #AgeMaxInserted > #AgeMax
BEGIN
PRINT 'Trans3'
RAISERROR('Overlap: Tranche déjà couverte complètement', 1, 422)
ROLLBACK TRANSACTION
END
FETCH CR_TrancheVol INTO #IdVol, #IdTranche
END
CLOSE CR_TrancheVol
DEALLOCATE CR_TrancheVol
END
EDIT:
Okay, so I tried your answer without cursor (I understand that my way was clearly not the best!) but for now it doesn't work.
My goal: I have a DB to book a flight. In this DB, i have a table "Tranche" who contains some dates and some prices (depending when the flight is).
I need to prevent and avoid any overlap of birthdate, for example:
1y-17y: 80€
18y-64y: 120€
So my trigger has to fire when I try to insert 17y-63y: xx € (because I already have a price for those ages).
Sorry if my English is not perfect btw!
Here's my table "Tranche":
https://i.stack.imgur.com/KuQH8.png
TRA_Vol_ID is a foreign key of another table "Vol" who contain the flights
Here's the code I have atm:
ALTER TRIGGER [dbo].[Tr_CheckOverlap]
ON [dbo].[Tranche]
FOR INSERT
AS
BEGIN
/*
Some SQL goes here to get the value of Minimum age.
I assuming that it doesn't vary by entry, however,
I don't really have enough information to go on to tell
*/
SET NOCOUNT ON;
DECLARE #MinAge DATE, #MaxAge DATE
SELECT #MinAge = t.TRA_Age_Min
FROM Tranche t
JOIN Vol AS v ON v.VOL_Id = t.TRA_Vol_Id
JOIN inserted AS i ON t.TRA_Id = i.TRA_Id
WHERE t.TRA_Id = i.TRA_Id
SELECT #MaxAge = t.TRA_Age_Max
FROM Tranche t
JOIN inserted AS i ON t.TRA_Id = i.TRA_Id
JOIN Vol AS v ON v.VOL_Id = t.TRA_Vol_Id
WHERE t.TRA_Id = i.TRA_Id
IF (SELECT COUNT(CASE WHEN i.TRA_Age_Min > #MinAge AND i.TRA_Age_Min < #MaxAge THEN 1 END) FROM inserted i) > 0
BEGIN
RAISERROR('Overlap: Birthday min reached',1,430);
ROLLBACK
END
ELSE IF (SELECT COUNT(CASE WHEN i.TRA_Age_Max > #MinAge AND i.TRA_Age_Max < #MaxAge THEN 1 END) FROM inserted i) > 0
BEGIN
RAISERROR('Overlap: Birthday max reached',1,430);
ROLLBACK
END
END
I don't really know what the OP's goals are here. However, I wanted to post a small example how to do a dataset approach, and how to check all the rows in one go.
At the moment, the trigger the OP has will only "work" if the user is inserting 1 row. Any more, and things aren't going to work properly. Then we also have the problem of the CURSOR. I note that the declaration of the cursors aren't referencing inserted at all, so I don't actually know what their goals are. It seems more like the OP is auditing the data already in the table when a INSERT occurs, not the data that is being inserted. This seems very odd.
Anyway, this isn't a solution for the OP, however, I don't have enough room in a comment to put all this. Maybe it'll push the OP in the right direction.
ALTER TRIGGER [dbo].[Tr_CheckOverlap]
ON [dbo].[Tranche]
FOR INSERT
AS
BEGIN
/*
Some SQL goes here to get the value of Minimum age.
I assuming that it doesn't vary by entry, however,
I don't really have enough information to go on to tell
*/
IF (SELECT COUNT(CASE WHEN i.Age < #MinAge THEN 1 END) FROM inserted i) > 0 BEGIN
RAISERROR('Age too low',1,430);
ROLLBACK
END
ELSE
IF (SELECT COUNT(CASE WHEN i.Age > #MaxAge THEN 1 END) FROM inserted i) > 0 BEGIN
RAISERROR('Age too high',1,430);
ROLLBACK
END
END
The question at hand seems to very much be an xy question; the problem isn't the CURSOR or the ROLLBACK, the problems with this trigger are much more fundamental. I'd suggest revising your question and actually explaining your goal of what you want to do with your Trigger. Provide DDL to CREATE your table and INSERT statements for any sample data. You might want to also provide some INSERT statements that will have different results for your trigger (make sure to include ones that have more than one row to be inserted at a time).
I realise this is more commenting, however, again, there is definitely not enough room in a comment for me to write all this. :)

i want to limit the data inserting into database table on give date and time only 12

create procedure SP_insert_test #name varchar(20), #emailid varchar(20), #trainer_name varchar(50), #training_date varchar(50), #training_time varchar(50), #gymname varchar(50) , #success int out as
begin
if(
select
count(id)
from
Add_Booking_Fitness_Training
where
training_time = #training_time) > 11 print N'Number of Booking Is Complete for this time and date plz book other time';
else
insert into
Add_Booking_Fitness_Training(memeber_name, member_emailid, trainer_name, training_date, training_time, gymname)
values
(
#name,
#emailid,
#trainer_name,
#training_date,
#training_time,
#gymname
)
SELECT
SCOPE_IDENTITY()
set
#success = 1;
end
begin
set
#success = 0;
end
i have an table in which i want to insert data on give time only 12 member can insert at that time after that they get message list is full plz change the time for inserting i have create procedure its working when its reach number of 12 than its show me message but when i change the time its also show me the same message and not insert any data into database
like 26/04/2018,'6:00' i want to insert this value only 12 time after 12 this show me a message about the limit of number is reach plz change (time)
Create table Add_Booking_Fitness_Training ( id int identity primary key,
memeber_name varchar(20),
member_emailid varchar(20),
trainer_name varchar(50),
training_date varchar(50),
training_time varchar(50),
gymname varchar(50))
i just want to inserting a value into this table only 12 time for a give time like (6:00) if the number of inserting value reach to 12 than its show me the message number of values insert is reach to 12 please change the time.
i want input the value into table only 12 time for a give time 6:00Am when the value is insert into table 12 time than message come up for change time than insert value for change time
Honestly, I am completely guessing here, I still don't really know what you're asking.
I think the OP's statement of "i want input the value into table only 12 time for a give time 6:00Am when the value is insert into table 12 time than message come up for change time than insert value for change time." means that they only want a time to appear in the table up to 12 times. If it appears more than that, the INSERT fails.
This can be achieved with a check constraint and a scalar function. So, as a very simple example:
USE Sandbox;
GO
--Create a very simple table
CREATE TABLE SampleTable (TrainingTime datetime2(0));
GO
--Create the scalar function
CREATE FUNCTION TrainingAtTime (#TrainingTime datetime2(0))
RETURNS INT
AS BEGIN
DECLARE #Trainees int;
SELECT #Trainees = COUNT(*)
FROM SampleTable
WHERE TrainingTime = #TrainingTime;
RETURN #Trainees;
END
GO
--Add the check constraint
ALTER TABLE SampleTable ADD CONSTRAINT MaxTrainees CHECK (dbo.TrainingAtTime(TrainingTime) <= 12) ;
GO
--Insert first trainee
INSERT INTO SampleTable
VALUES ('2018-04-26T06:00:00');
--It works
SELECT TrainingTime, COUNT(*) AS Trainees
FROM SampleTable
GROUP BY TrainingTime;
GO
--insert 11 more
INSERT INTO SampleTable
VALUES ('2018-04-26T06:00:00'),
('2018-04-26T06:00:00'),
('2018-04-26T06:00:00'),
('2018-04-26T06:00:00'),
('2018-04-26T06:00:00'),
('2018-04-26T06:00:00'),
('2018-04-26T06:00:00'),
('2018-04-26T06:00:00'),
('2018-04-26T06:00:00'),
('2018-04-26T06:00:00'),
('2018-04-26T06:00:00');
--It works
SELECT TrainingTime, COUNT(*) AS Trainees
FROM SampleTable
GROUP BY TrainingTime;
GO
--Try to insert another
INSERT INTO SampleTable
VALUES ('2018-04-26T06:00:00');
--It fails
SELECT TrainingTime, COUNT(*) AS Trainees
FROM SampleTable
GROUP BY TrainingTime;
GO
--Use a different time
INSERT INTO SampleTable
VALUES ('2018-04-26T08:00:00');
--it works
SELECT TrainingTime, COUNT(*) AS Trainees
FROM SampleTable
GROUP BY TrainingTime;
GO
--Clean up
DROP TABLE SampleTable;
DROP FUNCTION TrainingAtTime;
GO
If this isn't what you're after, unfortunately I don't understand your requirements due the the language barrier (and absence of a question).

Stored procedure keeps returning zeros for every table. Where Clause?

CREATE PROCEDURE [SSIS].[usp_LifeCount]
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Clear the table to prevent duplicate data.
TRUNCATE TABLE SSIS.LivingMales
-- Insert statements for procedure here
INSERT INTO SSIS.LivingMales
(Males)
SELECT COUNT(SEX)
FROM SSIS.Marvels
WHERE (ALIVE = 'Living Character' AND SEX = 'Male Character');
-- Clear the table to prevent duplicate data.
TRUNCATE TABLE SSIS.LivingFemales
-- Insert statements for procedure here
INSERT INTO SSIS.LivingFemales
(Females)
SELECT COUNT(SEX)
FROM SSIS.Marvels
WHERE (ALIVE = 'Living Character' AND SEX = 'Female Character');
-- Clear the table to prevent duplicate data.
TRUNCATE TABLE SSIS.DeadMales
-- Insert statements for procedure here
INSERT INTO SSIS.DeadMales
(Males)
SELECT COUNT(SEX)
FROM SSIS.Marvels
WHERE (ALIVE = 'Deceased Character' AND SEX = 'Male Character');
-- Clear the table to prevent duplicate data.
TRUNCATE TABLE SSIS.DeadFemales
-- Insert statements for procedure here
INSERT INTO SSIS.DeadFemales
(Females)
SELECT COUNT(SEX)
FROM SSIS.Marvels
WHERE (ALIVE = 'Deceased Character' AND SEX = 'Female Character');
END
I'm trying to get a total count of how many male/ female characters are alive as well as deceased. I know it's my where clause. When I take them out it returns the total for all and not individual. Alive is a column name in SSIS.Marvels
Run this to see what your data actually looks like first.
SELECT DISTINCT ALIVE, SEX FROM SSIS.Marvels
Then you can fix your where clauses to match your data. We can't really fix them for you as we don't know what your data looks like.

How do you create a logon trigger in SQL Server 2012

I've never used Triggers before, but need to use one to capture a location based on the IPAddress on login. I'm unsure of the structure and have followed guidance that was forwarded to me, but I cannot get it to work. This is what I have at the moment -
CREATE TRIGGER LGNCC_TRIGLOG
ON LGNCC_LOGIN
AFTER INSERT
AS
declare #userid VARCHAR(10)
declare #ipaddress VARCHAR(100)
declare #lastactivity VARCHAR(35)
BEGIN
select
#userid = I.userid,
#ipaddress = I.ipaddress,
#lastactivity = I.lastactivity
from
LGNCC_LOGIN I
IF (#lastactivity = 'login')
BEGIN
INSERT INTO lgnco_agent_location2(user_id, user_ip, user_location, user_date, User_Time)
SELECT
#userid, #ipaddress, 'This is a test' as Location,
LEFT (CAST (GETDATE() AS DATE),10) AS USERDATEIN,
LEFT (CAST (GETDATE() AS TIME), 8) AS USERTIMEIN
END
END
I've tried a number of different ways of compiling this, but nothing seems to work. Any help would be appreciated.
You trigger is executed after some data is inserted in the table LGNCC_TRIGLOG.
The insert is probably done from an application.
In that case the trigger can done as
CREATE TRIGGER LGNCC_TRIGLOG
ON LGNCC_LOGIN
AFTER INSERT
AS
BEGIN
INSERT INTO lgnco_agent_location2([user_id], user_ip, user_location
, user_date, User_Time)
SELECT userid, ipaddress, 'This is a test' as Location
, LEFT (CAST (GETDATE() AS DATE), 10) AS USERDATEIN
, LEFT (CAST (GETDATE() AS TIME), 8) AS USERTIMEIN
FROM Inserted
WHERE lastactivity = 'login'
END
Inserted is a special table, it is a copy of the trigger table that contains only the rows affected by the last INSERT or UPDATE executed.
If the column User_Date and User_Time in the table lgnco_agent_location2 are of type Date and Time remove the LEFT, as is it useless.

Resources