SQLite trigger before insert - database

I am trying to create a trigger where it filters the itemID first and then checks the most highest bidNo of that itemID. bidNo has to be only +1 bigger than the last. bid is bidder.
CREATE TRIGGER new_bid_no
BEFORE INSERT ON BID
BEGIN
SELECT CASE
WHEN (SELECT itemID
FROM bid
WHERE itemID = NEW.itemID
GROUP BY itemID
) AND (SELECT MAX(bidNo) AS bidNo
FROM bid
WHERE NEW.bidNo < bidNo
OR NEW.bidNo = (bidNo+1)
GROUP BY itemID
)THEN
RAISE (ABORT, 'New bid number has to be 1 higher than the last')
END;
END;
the bid table
CREATE TABLE BID(
buyerUsername VARCHAR(30) NOT NULL,
itemID INTEGER NOT NULL,
bidNo INTEGER NOT NULL,
bidAmount INTEGER,
bidDate VARCHAR(10),
bidTime TIME,
PRIMARY KEY(buyerUsername, itemID, bidNo),
FOREIGN KEY (buyerUsername) REFERENCES BUYER(buyerUsername),
FOREIGN KEY (itemID) REFERENCES ITEM(itemID)
)
WITHOUT ROWID;

First, you must define a UNIQUE constraint for itemID, bidNo and this can be done only in the CREATE statement of the table and not added later:
CREATE TABLE BID(
buyerUsername TEXT NOT NULL,
itemID INTEGER NOT NULL,
bidNo INTEGER NOT NULL,
bidAmount INTEGER,
bidDate TEXT,
bidTime TEXT,
PRIMARY KEY(buyerUsername, itemID, bidNo),
FOREIGN KEY(buyerUsername) REFERENCES BUYER(buyerUsername),
FOREIGN KEY(itemID) REFERENCES ITEM(itemID),
UNIQUE(itemID, bidNo)
)
WITHOUT ROWID;
I also changed the data types of the columns that you defined as VARCHAR to TEXT, because there is no VARCHAR data type in SQLite. Even if you defined it as such it will be TEXT. Also there is no data type TIME.
Now your trigger can be written like this:
CREATE TRIGGER new_bid_no
BEFORE INSERT ON BID
WHEN NEW.bidNo <> COALESCE((SELECT MAX(bidNo) FROM bid WHERE itemID = NEW.ItemID AND bidNo < NEW.bidNo), 0) + 1
BEGIN
SELECT RAISE (ABORT, 'New bid number has to be 1 higher than the last');
END

Related

Update a table column depending on a column from the foreign key table

I have a problem where I have a table A which has a foreign key to table B, both tables contain a From and a createdAt column, both of type datetime.
I want to update the From column in table A to be either the A.From or B.CreatedAt depending on which one is bigger.
How should I approach this kind of problem? Can this only be done using cursor?
I want to update the From column in table A to be either the A.From or B.CreatedAt depending on which one is bigger.
There's no need to update the From column in table A if A.From is equal to or larger than the corresponding CreatedAt value in table B.
Assuming your tables look something like:
DECLARE #TableA table
(
ID integer NOT NULL PRIMARY KEY,
[From] datetime NOT NULL,
CreatedAt datetime NOT NULL
);
DECLARE #TableB table
(
ID integer NOT NULL PRIMARY KEY,
A_ID integer NOT NULL, -- foreign key
[From] datetime NOT NULL,
CreatedAt datetime NOT NULL
);
The update you need is of the form:
UPDATE TA
SET TA.[From] = TB.CreatedAt
FROM #TableA AS TA
JOIN #TableB AS TB
ON TB.A_ID = TA.ID
WHERE
TB.CreatedAt > TA.[From];

Insert new record with composite primary key, which consists of two foreign keys from different tables

Please help me figure out how to Insert new record with composite primary key, which consists of two foreign keys from different tables.
I am working in C#, WPF if that matters.
I have three tables: Sales, SaleItem, Item.
CREATE TABLE [dbo].[Sales] (
[saleID] INT IDENTITY (1, 1) NOT NULL,
[saleTime] DATETIME NOT NULL,
[customerID] INT NULL,
[TIN] INT NOT NULL,
CONSTRAINT [PK_Sales] PRIMARY KEY CLUSTERED ([saleID] ASC),
CONSTRAINT [FK_Sales_Customers] FOREIGN KEY ([customerID]) REFERENCES [dbo].[Customers] ([customerID]),
CONSTRAINT [FK_Sales_Company] FOREIGN KEY ([TIN]) REFERENCES [dbo].[Company] ([TIN])
);
CREATE TABLE [dbo].[Item] (
[ItemSKU] INT IDENTITY (1, 1) NOT NULL,
[itemName] NVARCHAR (50) NOT NULL,
[volume] FLOAT (53) NOT NULL,
[measureUnit] NVARCHAR (50) NOT NULL,
[producer] NVARCHAR (50) NOT NULL,
[supplierID] INT NOT NULL,
[retailPrice] NUMERIC (18) NOT NULL,
CONSTRAINT [PK_Item] PRIMARY KEY CLUSTERED ([ItemSKU] ASC),
CONSTRAINT [FK_Item_Suppliers] FOREIGN KEY ([supplierID]) REFERENCES [dbo].[Suppliers] ([supplierID])
);
CREATE TABLE [dbo].[SaleItem] (
[saleID] INT IDENTITY (1, 1) NOT NULL,
[itemSKU] INT NOT NULL,
[quantity] INT NOT NULL,
CONSTRAINT [PK_SaleItem] PRIMARY KEY CLUSTERED ([saleID] ASC, [itemSKU] ASC),
CONSTRAINT [FK_SaleItem_Sales] FOREIGN KEY ([saleID]) REFERENCES [dbo].[Sales] ([saleID]),
CONSTRAINT [FK_SaleItem_Item] FOREIGN KEY ([itemSKU]) REFERENCES [dbo].[Item] ([ItemSKU])
);
I want to insert a new record into SaleItem table (the third one) where saleID is the last ID recorded in Sales table and ItemSKU which is equal to the value I get from another window.
I want these values:
SaleID = SELECT TOP 1 saleID FROM Sales ORDER BY saleID DESC";
ItemSKU = "SELECT itemName FROM Item WHERE ItemSKU = #sku";
I think I must do it in one query but I have no idea how.
Can you please give me a hint? I
First, you need to remove the IDENTITY property from the dbo.SaleItem table. The IDENTITY property is only required on the parent table, dbo.Sales.
You can do a single INSERT statement like this. It uses two subqueries, which are the SELECT statements in parentheses, to get values from the other two tables.
INSERT INTO dbo.SaleItem (saleID, itemSKU, quantity)
VALUES ((SELECT MAX(saleID) FROM dbo.Sales),
(SELECT ItemSKU FROM dbo.Item WHERE itemName = N'Widget'),
50);
You might want to turn it into a stored procedure, like this:
CREATE PROCEDURE dbo.up_InsertSaleItem
(
#itemName nvarchar(50),
#quantity int
)
AS
INSERT INTO dbo.SaleItem (saleID, itemSKU, quantity)
VALUES ((SELECT MAX(saleID) FROM dbo.Sales),
(SELECT ItemSKU FROM dbo.Item WHERE itemName = #itemName),
#quantity);
Then to use the stored procedure:
-- Test the stored procedure
EXEC dbo.up_InsertSaleItem #itemName=N'Widget', #quantity=50;
SELECT *
FROM dbo.SaleItem;
To read more about subqueries, see Microsoft SQL Server 2012 T-SQL Fundamentals by Itzik Ben-Gan, Chapter 4: Subqueries.

How to create a computed column that references another column from another table?

I am using Microsoft SQL Server and I am still learning. I have two tables, a product table and an order details table. The product table contains a price and then the order details table has a reference to the the product, the quantity of the product and the total price. Here are the two tables:
--Create Product Table
CREATE TABLE Products.Product
(
product_id INT NOT NULL PRIMARY KEY IDENTITY,
product_name VARCHAR(40) NOT NULL,
product_desc VARCHAR(5000),
product_price SMALLMONEY NOT NULL CHECK (product_price >= 0)
);
--Create Order Details Table
CREATE TABLE Orders.Order_detail
(
order_detail_id INT NOT NULL PRIMARY KEY IDENTITY,
product_id INT NOT NULL,
product_quantity INT NOT NULL CHECK (product_quantity >= 0),
order_detail_total MONEY NOT NULL,
FOREIGN KEY (product_id) REFERENCES Products.Product
);
How can I make it so that order_detail_total is a computed column that is the product_price * product_quantity?
Thanks to #Andy K, I came up with this solution:
--Create Product Table
CREATE TABLE Products.Product
(
product_id INT NOT NULL PRIMARY KEY IDENTITY,
product_name VARCHAR(40) NOT NULL,
product_desc VARCHAR(5000),
product_price SMALLMONEY NOT NULL CHECK (product_price >= 0)
);
GO
--Create a function to calculate the order details total
CREATE FUNCTION Orders.calcOrderDetailTotal(#quantity INT, #productId INT)
RETURNS MONEY
AS
BEGIN
DECLARE #price SMALLMONEY
SELECT #price = product_price FROM Products.Product AS TP
WHERE TP.product_id = #productId
RETURN #quantity * #price
END
GO
--Create Order Details Table
CREATE TABLE Orders.Order_detail
(
order_detail_id INT NOT NULL PRIMARY KEY IDENTITY,
product_id INT NOT NULL,
product_quantity INT NOT NULL CHECK (product_quantity >= 0),
order_detail_total MONEY NOT NULL,
FOREIGN KEY (product_id) REFERENCES Products.Product
);
This worked for me on a test db that I created.

SQL Server Trigger functioning backwards

I have a little strange issue with my SQL script and I was hoping someone could help me out with it.
I have a Database being created by using
IF EXISTS (SELECT name
FROM sysdatabases
WHERE name = 'travel')
DROP DATABASE travel
GO
CREATE DATABASE travel
GO
USE travel
GO
I then create 3 tables as shown below
CREATE TABLE customer
(
customerID INT,
lastname VARCHAR(70) NOT NULL,
firstname VARCHAR(70) NOT NULL,
phone VARCHAR(10) CONSTRAINT phoneCheck CHECK ((phone LIKE '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]')),
category VARCHAR(7) NOT NULL CONSTRAINT categoryDefault DEFAULT 'A',
CONSTRAINT categoryCheck CHECK (category IN ('A', 'B', 'C')),
CONSTRAINT customerPK
PRIMARY KEY (customerID)
)
CREATE TABLE package /*Still need to do the Zero Padding*/
(
packageCode VARCHAR(6),
destination VARCHAR(70),
CONSTRAINT packageCodeCheck CHECK (packageCode LIKE ('YFK%')),
price MONEY NOT NULL CONSTRAINT priceCheck CHECK ((price BETWEEN 1000 AND 10000)),
passportRequired VARCHAR(7) NOT NULL CONSTRAINT passportRequiredDefault DEFAULT 'Y',
CONSTRAINT passportCheck CHECK (passportRequired IN ('Y', 'N')),
CONSTRAINT packagePK
PRIMARY KEY (packageCode)
)
CREATE TABLE booking /*Still need to do the Customer and Package delete*/
(
customerID VARCHAR(6),
bookingDate VARCHAR(70) NOT NULL DEFAULT GETDATE(),
amountPaid MONEY CONSTRAINT amountPaidDefault DEFAULT 0.00,
CONSTRAINT bookingPK
PRIMARY KEY (customerID)
)
Now heres the issue, I create a trigger as shown below
GO
CREATE TRIGGER customerDelete ON customer AFTER DELETE
AS
DELETE booking
FROM customer
WHERE customer.customerID = booking.customerID
GO
Which to my understanding it will delete all records in booking... that have the matching customerID WHEN a record is deleted from the customer Table. (I am new to triggers)
I INSERT Sample Data as shown below
INSERT INTO customer
(customerID, lastname, firstname, phone, category)
VALUES
(1, 'Picard', 'Corey', 1234567890, 'A'),
(2, 'Bond', 'Devon', 9876543210, 'B'),
(3, 'Douglas', 'Bryan', 6549871230, 'C')
INSERT INTO package
(packageCode, destination, price, passportRequired)
VALUES
('YFK001', 'Toronto', 1000.57, 'N'),
('YFK002', 'Orlando', 3000.98, 'Y')
INSERT INTO booking
(customerID, bookingDate, amountPaid)
VALUES
(1, GETDATE(), 1548),
(2, GETDATE(), 1586),
(3, GETDATE(), 1350),
(4, GETDATE(), 1650)
And Finally I delete the Customer from the TABLE customer with the customerID of 1 by using
DELETE customer
WHERE customerID = 1
However, when I attempt to see the results by using
SELECT * FROM customer
--WHERE customerID = 1 OR customerID = 2 OR customerID = 3
SELECT * FROM package
--WHERE packageCode = 'YFK001' OR packageCode = 'YFK002'
SELECT * FROM booking
--WHERE customerID = 1 OR customerID = 2 OR customerID = 3 OR customerID = 4
It displays bookings with customerID 1 and 4.
Can you let me know what I'm doing wrong?
The trigger is essentially used for the purpose of deleting the bookings with the same customerID of the customer we delete from the customer TABLE
All help is greatly appreciated.
Thanks,
Bryan
Change your delete to this:
DELETE B
FROM booking B
INNER JOIN DELETED D
ON B.customerID = D.customerID;
My Answer is not trigger, [ If you specially want to use Trigger then You can use Lamak's & Pradeep's Answer]
Here best way you can do is use Cacade on foreign Key in your case
Here is your Query I just updated cascade in it
CREATE TABLE customer
(
customerID INT,
lastname VARCHAR(70) NOT NULL,
firstname VARCHAR(70) NOT NULL,
phone VARCHAR(10) CONSTRAINT phoneCheck CHECK ((phone LIKE '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]')),
category VARCHAR(7) NOT NULL CONSTRAINT categoryDefault DEFAULT 'A',
CONSTRAINT categoryCheck CHECK (category IN ('A', 'B', 'C')),
CONSTRAINT customerPK
PRIMARY KEY (customerID)
)
CREATE TABLE package /*Still need to do the Zero Padding*/
(
packageCode VARCHAR(6),
destination VARCHAR(70),
CONSTRAINT packageCodeCheck CHECK (packageCode LIKE ('YFK%')),
price MONEY NOT NULL CONSTRAINT priceCheck CHECK ((price BETWEEN 1000 AND 10000)),
passportRequired VARCHAR(7) NOT NULL CONSTRAINT passportRequiredDefault DEFAULT 'Y',
CONSTRAINT passportCheck CHECK (passportRequired IN ('Y', 'N')),
CONSTRAINT packagePK
PRIMARY KEY (packageCode)
ON DELETE CASCADE
ON UPDATE CASCADE
)
CREATE TABLE booking /*Still need to do the Customer and Package delete*/
(
customerID VARCHAR(6),
bookingDate VARCHAR(70) NOT NULL DEFAULT GETDATE(),
amountPaid MONEY CONSTRAINT amountPaidDefault DEFAULT 0.00,
CONSTRAINT bookingPK
PRIMARY KEY (customerID)
ON DELETE CASCADE
ON UPDATE CASCADE
)
This way when you are deleting or update [keyvalue] any entry of Table holding primary key will update its related foreign childs

creating before INSERT TRIGGER comparing values between two tables

I need help creating a before insert trigger, as i am new to TSQL. below are the two tables.
SALARY table:
CREATE TABLE SALARY
(
StarName varchar(30) NOT NULL,
MovieTitle varchar(30)NOT NULL,
MovieYearMade numeric(4, 0) NOT NULL,
Amount numeric(8, 0) NULL,
PRIMARY KEY (MovieTitle,StarName,MovieYearMade),
)
MOVIESTAR table
CREATE TABLE MOVIESTAR
(
Name varchar(30) NOT NULL,
Address varchar(20),
City varchar(15) DEFAULT ('Palm Springs'),
Gender char(1) NULL CHECK (Gender ='M' OR GENDER ='F'),
BirthYear Numeric(4),
PRIMARY KEY CLUSTERED (Name)
)
I want to create a trigger so when a new movie is added. It prevents adding SALARY.Amount if SALARY.MovieYearMade is before MOVIESTAR.BirthYear.
I am confused as how to define trigger, when I am comparing values in two tables i.e. SALARY and MOVIESTAR.
thanks,
Are you looking for something like this?
CREATE TRIGGER tg_salary ON salary
INSTEAD OF INSERT AS
BEGIN
INSERT INTO salary (StarName, MovieTitle, MovieYearMade, Amount)
SELECT i.StarName, i.MovieTitle, i.MovieYearMade,
CASE WHEN i.MovieYearMade < s.BirthYear THEN NULL ELSE i.Amount END
FROM INSERTED i JOIN moviestar s
ON i.StarName = s.Name
END
Here is SQLFiddle demo

Resources