How do I validate these columns? - sql

I'm working on a database and I need to validate some columns under the Payment schema.
Like if a credit card is not used for payments, CreditCardNumber, CardHoldersName, and CreditCardExpDate should be made NULL. If a credit card is used, the CreditCardExpDate value should be greater than the PaymentDate
PaymentDue can allow NULL but should not be greater than PaymentAmount
I've searched online but what I get are complex triggers and procedures which are not really helpful.
create table Payment.Payments(
Payment_ID int identity (200, 21),
Payment_Amount money constraint chk_Payment_Amount check (Payment_Amount >
'0'),
Payment_Date date, -- is to be greater than the end date which is on another table
Credit_Card_Number int,
Card_Holders_Name char (50),
Credit_Card_Expiry_Date date,
Project_ID int Foreign Key references ProjectDetails.Projects(Project_ID),
Payment_Due money -- should not be greater than Payment Amount but
can still accept null*
);
The notes show the current validation problem i'm having.
I created a trigger for the payment_date but i can only get it to fire when the inserted date is greater than the current date, i need it to fire if it is less than the end date(end date is on another table)
CREATE TRIGGER paymentdate
ON Payment.Payments
FOR INSERT
AS
DECLARE #ModifiedDate date
SELECT #ModifiedDate = Payment_Date FROM Inserted
IF (#ModifiedDate > getdate())
BEGIN
PRINT 'The modified date should be the current date. Hence, cannot insert.'
ROLLBACK TRANSACTION
END

I'm reading a lot between the lines here, but I think this is what you're after (Note I have used the dbo schema though):
USE Sandbox;
GO
CREATE TABLE dbo.Payments (
Payment_ID int identity(200, 21),
Payment_Amount money CONSTRAINT chk_Payment_Amount CHECK (Payment_Amount > '0'),
Payment_Date date,
Credit_Card_Number char(19), --note datatype change from int to char. See my comment below (copied from my comment)
Card_Holders_Name varchar (50), --note I've used varchar instead. Names aren't all 50 characters long
Credit_Card_Expiry_Date date,
--Project_ID int FOREIGN KEY REFERENCES ProjectDetails.Projects(Project_ID) --Commented out as I don't have this table
Payment_Due money CONSTRAINT chk_Payment_Due CHECK (Payment_Due > '0' OR Payment_Due IS NULL)
);
GO
--Credit Card format validation
ALTER TABLE dbo.Payments ADD CONSTRAINT ck_Credit_Card CHECK (Credit_Card_Number LIKE '[0-9][0-9][0-9][0-9] [0-9][0-9][0-9][0-9] [0-9][0-9][0-9][0-9] [0-9][0-9][0-9][0-9]' OR Credit_Card_Number IS NULL);
--Add card details must be there, or none.
ALTER TABLE dbo.Payments ADD CONSTRAINT ck_Card_Details CHECK ((Credit_Card_Number IS NULL AND Card_Holders_Name IS NULL AND Credit_Card_Expiry_Date IS NULL)
OR (Credit_Card_Number IS NOT NULL AND Card_Holders_Name IS NOT NULL AND Credit_Card_Expiry_Date IS NOT NULL))
GO
DROP TABLE dbo.Payments;
Comment made on the Card Number's datatype:
The datatype int for a credit card number is a bit of an oxymoron. The maximum value for an int is 2,147,483,647 and a card number is made up of 4 sets of 4 digit numbers (i.e. 9999 9999 9999 9999). Even as a number, that's far higher than the max value of an int. I'd suggest using a char(19) and making a constraint on the format as well.

Related

How do I validate these columns, do i need more complex triggers?

I'm trying to validate the columns in the table ProjectDetails.TimeCards
create table ProjectDetails.TimeCards(
Time_Card_ID int identity (55,15),
Employee_ID int foreign key references HumanResources.Employees(Employee_ID),
Date_Issued date, --DateIssued should be greater than the current date and the project start date (Project start date is from another table).
Days_Worked int constraint chk_Days_Worked check(Days_Worked > '0'),
Project_ID int foreign key references ProjectDetails.Projects(Project_ID),
Billable_hours int constraint chk_Billable_Hours check (Billable_Hours > '0'),
Total_Cost money, -- should be automatically calculated by using the following formula: TotalCost=Billable Hours * BillingRate (billing rate is from another table)
Work_Code_ID int foreign key references ProjectDetails.WorkCodes(Work_Code_ID)
);
I tried building a trigger, but was only able to get the trigger to fire if the Date_Issued was less than the current date
CREATE TRIGGER dateissued
ON ProjectDetails.TimeCards
FOR INSERT
AS
DECLARE #ModifiedDate date
SELECT #ModifiedDate = Date_Issued FROM Inserted
IF (#ModifiedDate < getdate())
BEGIN
PRINT 'The modified date should be the current date. Hence, cannot insert.'
ROLLBACK TRANSACTION -- transaction is to be rolled back
END
i need the trigger to fire if the Date issued is less than the current date and also if date issued is less than the start_date. As for the billing rate calculation i'm lost there.
This is the other table
create table ProjectDetails.Projects(
Project_ID int identity (0100, 01) primary key, -- Primary key
Project_Name char (50) not null,
Start_Date date not null, -- the start date i'm referring to
End_Date date not null,
constraint CheckEndLaterThanStart check (End_Date > Start_Date),
Billing_Estimate money constraint chk_Billing_Estimate check (Billing_Estimate > '1000'),
Client_ID int Foreign Key references CustomerDetails.Clients(Client_ID)
);
I believe this provides the logic you are after. There are a couple of comments in the code for you:
CREATE TRIGGER trg_chk_Date_Issued ON ProjectDetails.TimeCards
FOR INSERT, UPDATE --I assume on need on UPDATE as well, as otherwise this won't validate
AS BEGIN
IF EXISTS(SELECT 1
FROM inserted i
JOIN ProjectDetails.Projects P ON i.Project_ID = P.Project_ID
WHERE i.Date_Issued < CONVERT(date,GETDATE())
OR i.Date_Issued < P.Start_Date) BEGIN
RAISERROR(N'Date Issued cannot be less than the current date or the Project Start Date.', 10,1); --Raised an error, rather than using PRINT
ROLLBACK;
END
END
Note that you may want a different trigger for UPDATE, as if you are updating the row, and Date_Issued has a value lower than the date of the UPDATE, the statement will fail.

How to update a column based on an amount of time in SQL

I want to create a stored procedure to update a column based on an amount of time. For example, to update the interest generated column every 15 days.
Here is my code. Please help.
create table Loan(
Loan_ID int not null primary key,
Loan_custID int not null foreign key references Customers(Cust_ID),
Loan_Amount int not null,
Loan_Interest int not null,
Loan_Date date not null unique,
)
Create table Interestgenerated(
IG_ID int not null primary key,
Loan_ID int not null foreign key references Loan1(Loan_ID),
Loan_Date date null foreign key references Loan1(Loan_Date),
IG_Amount int not null,
IG_Date datetime not null
)
create procedure InsertINtoInterestgenerated1
#PresentDate Datetime
as
set #PresentDate=getdate()
select Loan_ID from Loan
set IG_Date=Loan_Date
IG_Date=dateadd(day,15, IG_Date)
if #PresentDate=IG_Date
begin
update Interestgenerated1 set IG_Date = #PresentDate, IG_Amount=IG_Amount*0.15
end
Considering you want to automate the update of the value in column IG_Amount every 15 days,
you can schedule a job to run every 15 days at midnight like on the 1st and 16th of every month.
the below link might help you:
how to schedule a job for sql query to run daily?

Oracle APEX - AFTER INSERT, UPDATE another table trigger

I'm trying to insert into the poPayment table with some of the details from the purchaseOrder table AFTER INSERT ON purchaseorder, to start with I want the
purchaseorder.purchaseorderid added into the popayment.purchaseorderid
after I get this working I want to expand the trigger
here is the purchase order table;
CREATE TABLE purchaseOrder
(
purchaseOrderid NUMBER (6) NOT NULL,
staffid NUMBER (6),
rawMaterialid2 NUMBER (6) NOT NULL,
supplierContactid2 NUMBER (6),
orderDate DATE NOT NULL,
dueDate DATE,
pricePerUnit NUMBER (7,2),
qty NUMBER,
total NUMBER (7,2),
CONSTRAINT purchaseOrderid PRIMARY KEY(purchaseOrderid)
);
here is the purchase order payment table;
CREATE TABLE poPayment
(
poPaymentid NUMBER (6) NOT NULL,
purchaseOrderid NUMBER (6) NOT NULL,
staffid NUMBER (6) NOT NULL,
paymentDate DATE,
amountPaid NUMBER (7,2),
qtyOrdered NUMBER (6),
qtyDelievered NUMBER (6),
invoiceAmount NUMBER (6),
dateDelivered DATE,
CONSTRAINT pk_poPaymentid PRIMARY KEY(poPaymentid)
);
and here is the trigger I tried
CREATE OR REPLACE TRIGGER createPOpayment_trg
ON purchaseorder
AFTER INSERT
AS BEGIN
INSERT INTO popayment (purchaseorderid)
SELECT
purchaseorder.purchaseorderid
FROM purchaseorder
WHERE purchaseorder.purchaseorderid = popayment.purchaseorderid
END
Thank
Brian
You have incorrect syntax for the create trigger statement; the AFTER INSERT' needs to be before theON purchaseorder` part (the dml_event_clause in the syntax diagrams). You also want it to be a row-level trigger, so it fires for each individual row you insert in the table;
CREATE OR REPLACE TRIGGER createPOpayment_trg
AFTER INSERT
ON purchaseorder
FOR EACH ROW
AS
...
But then your current insert is malformed too. It's going to insert a row into popayment for every row in purchaseorder that already has a matching popayment row - which is going to duplicate all existing rows, not create one for your new purchase order.
You only want to insert a single row matching the inserted purchase order. And you need to include at least all the not null columns:
BEGIN
INSERT INTO popayment (poPaymentid, purchaseorderid, staffid)
VALUES (popayment_seq.nextval, :new.purchaseorderid, :new.staffid);
END;
I'm guessing (and hoping) you have a sequence to populate the poPaymentid primary key. The other two values are coming from the inserted purchaseorder record, using the :new pseudorecord. You do not want to query the table you are inserting into.
If the key is being set by its own trigger then you only need to give the other two not-null columns (plus any more you add later):
BEGIN
INSERT INTO popayment (purchaseorderid, staffid)
VALUES (:new.purchaseorderid, :new.staffid);
END;

SQL DDL - 2 CHECK Constraints on 1 Attribute

Below is DDL for the table I want to create. However, I want the attribute 'Appointment_datetime' to be a future date and during working hours (between 8:00AM and 5:00PM). I can get the future date part with -'CHECK (Appointment_datetime >= GETDATE()) But how do I get between 8AM and 5PM ontop of this constraint?
CREATE TABLE tAppointment
(
Appointment_ID int NOT NULL PRIMARY KEY,
Appointment_datetime datetime NOT NULL, -- CHECK CONSTRAINTS NEEDED
Appointment_week int NOT NULL,
Appointment_room varchar(5) NOT NULL,
Vet_ID int NOT NULL REFERENCES tVet(Vet_ID),
Owner_ID int NOT NULL REFERENCES tOwner(Owner_ID),
Pet_ID int NOT NULL REFERENCES tPet(Pet_ID)
)
You can just add it in. Here is a method using the hour:
CHECK (Appointment_datetime >= GETDATE() AND
DATEPART(HOUR, GETDATE()) NOT BETWEEN 8 AND 16
)
Note: If you want to take weekends and holidays into account, that is more difficult and probably requires a user-defined function.

Beginner with triggers

Im a beginner in database and i got this difficult auction database project.
Im using SQL Server Management Studio also.
create table user(
name char(10) not null,
lastname char(10) not null
)
create table item(
buyer varchar(10) null,
seller varchar(10) not null,
startprice numeric(5) not null,
description char(22) not null,
start_date datetime not null,
end_date datetime not null,
seller char(10) not null,
item_nummer numeric(9) not null,
constraint fk_user foreign key (buyer) references user (name)
)
Basically what the rule im trying to make here is:
Column buyer has NULL unless the time (start_date and end_date) is over and startprice didnt go up or increased. Then column buyer will get the name from table user who bidded on the item.
The rule is a bid too difficult for me to make, i was thinking to make a trigger, but im not sure..
Your model is incorrect. First you need a table to store the bids. Then when the auction is over, you update the highest one as the winning bid. Proably the best way is to have a job that runs once a minute and finds the winners of any newly closed auctions.
A trigger will not work on the two tables you have because triggers only fire on insert/update or delete. It would not fire because the time is past. Further triggers are an advanced technique and a db beginner should avoid them as you can do horrendous damage with a badly written trigger.
You could have a trigger that works on insert to the bids table, that updates the bid to be the winner and takes that status away from the previous winner. Then you simply stop accepting new bids at the time the auction is over. Your application could show the bidder who is marked as the winner as the elader if the auction is till open and teh winner if it is closed.
There are some initial problems with your schema that need addressed before tackling your question. Here are changes I would make to significantly ease the implementation of the answer:
-- Added brackets around User b/c "user" is a reserved keyword
-- Added INT Identity PK to [User]
CREATE TABLE [user]
(
UserId INT NOT NULL
IDENTITY
PRIMARY KEY
, name CHAR(10) NOT NULL
, lastname CHAR(10) NOT NULL
)
/* changed item_nummer (I'm not sure what a nummer is...) to ItemId int not null identity primary key
Removed duplicate Seller columns and buyer column
Replaced buyer/seller columns with FK references to [User].UserId
Add currentBid to capture current bid
Added CurrentHighBidderId
Added WinningBidderId as computed column
*/
CREATE TABLE item
(
ItemId INT NOT NULL
IDENTITY
PRIMARY KEY
, SellerId INT NOT NULL
FOREIGN KEY REFERENCES [User] ( UserId )
, CurrentHighBidderId INT NULL
FOREIGN KEY REFERENCES [User] ( UserId )
, CurrentBid MONEY NOT NULL
, StartPrice NUMERIC(5) NOT NULL
, Description CHAR(22) NOT NULL
, StartDate DATETIME NOT NULL
, EndDate DATETIME NOT NULL
)
go
ALTER TABLE dbo.item ADD
WinningBidderId AS CASE WHEN EndDate < CURRENT_TIMESTAMP
AND currentBid > StartPrice THEN CurrentHighBidderId ELSE NULL END
GO
With the additional columns a computed column can return the correct information. If you must return the winner's name instead of id, then you could keep the schema above the same, add an additional column to store the user's name, populate it with a trigger and keep the computed column to conditionally show/not show the winner..