How implement the function of `case` in DDL? - sql

I have a table order. Its DDL is listed below
create table "order"
(
id serial primary key,
quantity integer not null,
estimated_delivery_date date not null,
lodgement_date date check ( lodgement_date > '2022-03-02' ),
product_model varchar(128) not null,
sales_id integer not null,
contract_number varchar(10) not null
);
I want to make the lodgement_date attribute to be null if it is later than 2022-03-02 when inserting a new row. How can I achieve this function in DDL.

To do that, you can't do it in the creation of the table. It is gonna be a constraint.
Example:
CONSTRAINT check_lodgement_date
CHECK (lodgement_date > '2022-03-02')

Related

PostgreSQL- Function to update 3 shared columns from table B on table A

The main goal is to create a function that updates 3 columns on another table (the update of the 2 columns from the first table trigger the update on the second one).
CREATE TRIGGER trigger_modif_amount
AFTER INSERT OR DELETE OR UPDATE OF net_amount, iva_amount
ON erp.tb_lines
FOR EACH ROW
EXECUTE PROCEDURE modif_amount();
The name of the 3 columns: net_amount , iva_amount , total_amount
CREATE OR REPLACE FUNCTION modif_amount()
RETURNS TRIGGER AS $$
BEGIN
UPDATE erp.tb_invoice
SET (net_amount,iva_amount,tot_amount) = (select COALESCE(sum(net_amount),0),COALESCE(sum(iva_amount),0),COALESCE(sum(net_amount+iva_amount),0) from tb_lines where invoice_id = coalesce(NEW.invoice_id, OLD.invoice_id))
WHERE invoice_id = coalesce(NEW.invoice_id, OLD.invoice_id);
END;
$$ LANGUAGE plpsql;
The tables:
CREATE TABLE erp.tb_invoice (
co_code CHARACTER(3) NOT NULL,
invoice_id INT NOT NULL,
invoice_no CHARACTER VARYING(15) NOT NULL,
cust_no CHARACTER(5) NOT NULL,
site_id INT NOT NULL,
payed CHARACTER(1) NOT NULL DEFAULT 'N',
net_amount REAL NOT NULL,
iva_amount REAL NOT NULL,
tot_amount REAL NOT NULL,
last_updated_by CHARACTER VARYING(20) DEFAULT 'SYSTEM',
last_update_date DATE NOT NULL,
CONSTRAINT pk_invoice PRIMARY KEY (invoice_id),
CONSTRAINT fk_invoice_company FOREIGN KEY (co_code) REFERENCES erp.tb_company (co_code),
CONSTRAINT fk_invoice_customer FOREIGN KEY (cust_no) REFERENCES erp.tb_customer (cust_no),
CONSTRAINT fk_invoice_site FOREIGN KEY (site_id) REFERENCES erp.tb_site (site_id)
);
CREATE TABLE erp.tb_lines (
invoice_id INT NOT NULL,
line_id INT NOT NULL,
line_num INT NOT NULL,
item CHARACTER(5),
description CHARACTER VARYING(120) NOT NULL,
net_amount REAL NOT NULL,
iva_amount REAL NOT NULL,
last_updated_by CHARACTER VARYING(20) DEFAULT 'SYSTEM',
last_update_date DATE NOT NULL,
CONSTRAINT pk_lines PRIMARY KEY (line_id),
CONSTRAINT fk_lines_invoice FOREIGN KEY (invoice_id) REFERENCES erp.tb_invoice (invoice_id)
);
This trigger definition to only execute the function (modif_amount) if column (net_amount) and (iva_amount) is specified as a target in the UPDATE command:
CREATE TRIGGER trigger_modif_amount
AFTER UPDATE OF net_amount,iva_amount ON tb_lines
FOR EACH ROW
EXECUTE PROCEDURE modif_amount();
This form only executes the function (modif_amount) if column (net_amount), (iva_amount) has in fact changed value:
CREATE TRIGGER trigger_modif_amount
AFTER UPDATE
ON tb_lines
FOR EACH ROW
WHEN ((OLD.net_amount IS DISTINCT FROM NEW.net_amount) AND
(OLD.iva_amount IS DISTINCT FROM NEW.iva_amount) )
EXECUTE PROCEDURE modif_amount();
You can create trigger which trigger after update of specific fields
https://www.postgresql.org/docs/14/sql-createtrigger.html
CREATE TRIGGER test
AFTER INSERT OR DELETE OR UPDATE OF net_amount, iva_amount
ON tb_lines
FOR EACH ROW
EXECUTE PROCEDURE modif_amount();
Updating overal sum in another table inside trigger is not a good idea (it moves business logic into triggers and is not save).
Version 1
update tb_invoice set
(net_amount,iva_amount,tot_amount) = (select COALESCE(sum(net_amount),0),COALESCE(sum(iva_amount),0),COALESCE(sum(net_amount+iva_amount),0) from tb_lines where invoice_id = coalesce(NEW.invoice_id, OLD.invoice_id))
where invoice_id = coalesce(NEW.invoice_id, OLD.invoice_id);
Version 2
update tb_invoice set
(net_amount,iva_amount,tot_amount) = (select COALESCE(sum(net_amount),0),COALESCE(sum(iva_amount),0),COALESCE(sum(net_amount+iva_amount),0) from tb_lines where tb_lines.invoice_id = tb_invoice.invoice_id)
where invoice_id = coalesce(NEW.invoice_id, OLD.invoice_id);
COALESCE in sum is needed to ensure, that even if invoice has no positions sums will be calculated as 0.
COALESCE in where is needed because during insert operation there is no OLD.invoice_id, and during delete operation there is no NEW.invoice_id.
My assumption is, that invoice_id cannot be changed. If not, that moving a position from one invoice to another should update ole and new one.

SQL: Missing Parenthesis

I have tried editing the command and looking at other questions in order to answer this question, but I still get the dreaded
ORA-00907: missing right parenthesis.
Here is my code. Is there any key word that I may need to drop here? Thanks
CREATE TABLE Loan
(
LoanID INT IDENTITY ( 1, 1 ) UNIQUE,
BranchID INT NOT NULL REFERENCES Branch(BranchID) ON DELETE CASCADE,
LoanNumber CHAR(20) NOT NULL UNIQUE,
LoanType VARCHAR(30) NOT NULL,
Amount MONEY NOT NULL,
ModifiedDate DATETIME DEFAULT (getdate()),
PRIMARY KEY ( LoanID )
);
The following ddl is syntactically correct. Of course, you have to check whether that statement really produces what you want ( in particular the IDENTITY keyword in your original statement is not accounted for ):
CREATE TABLE Loan
(
LoanID INTEGER NOT NULL PRIMARY KEY
, BranchID INTEGER NOT NULL CONSTRAINT tl_fk_branchid REFERENCES Branch(BranchID) ON DELETE CASCADE
, LoanNumber CHAR(20) NOT NULL CONSTRAINT tl_u_loannumber UNIQUE
-- right padded to length of 20 with blanks
, LoanType VARCHAR2(30) NOT NULL
, Amount Number(*,4) NOT NULL
-- cf. http://stackoverflow.com/a/29014422, changed per #BobJarvis' comment
, ModifiedDate DATE DEFAULT SYSDATE
);
The syntax deviations are as follows:
IDENTITYkeyword
inline constraint specification
datatype to represent date and time
datatype for string content
stand-in for money datatype
current datetime

SQL library trigger

Im trying to make a library database. I would like to ensure that one book can be borrowed just to one person at a time. I have no expirience with triggers so I thought I might ask you.
create table "book" (
"book_id" INTEGER not null,
"condition" VARCHAR2(50),
"isbn" VARCHAR2(50) not null,
constraint PK_BOOK primary key ("book_id")
);
create table "borrowed" (
"book_id" INTEGER not null,
"borrowed_id" INTEGER not null,
"user_id" INTEGER not null,
"date_borrowing" DATE not null,
"date_returning" DATE not null,
"returned" SMALLINT not null,
constraint PK_BORROWED primary key ("book_id", "borrowed_id")
);
atribute "returned" has just yes or no value (1 or 0)
You don't need a trigger for this. Your borrowed table should be structured like this. Note the use of a virtual column, which requires Oracle 11g+:
create table borrowed (
borrowed_id INTEGER not null primary key, -- this should be set to a unique id for each row, using your preferred method
book_id INTEGER not null,
user_id INTEGER not null,
date_borrowing DATE not null,
date_returning DATE not null,
date_actualreturn DATE,
returned as (case date_actualreturn is null then 0 else 1 end)
);
Then, you want date_actualreturn to have at most one NULL value per book. You can do this with a unique index or constraint:
create table borrowed (
borrowed_id INTEGER not null primary key, -- this should be set to a unique id for each row, using your preferred method
book_id INTEGER not null,
user_id INTEGER not null,
date_borrowing DATE not null,
date_returning DATE not null,
date_actualreturn DATE,
returned as (case date_actualreturn is null then 0 else 1 end),
constraint unq_only_one_book_borrowed unique
(coalesce(date_actualreturn, date '1900-01-01'), book_id)
);
This creates a unique constraint on the column. If a book has not been returned, the date always looks the same -- so the same book cannot be borrowed twice. And, voila! No trigger.

How to define table constraint to check non empty datetime?

While creating a table how to add table level constraint so as to check that a column with datatype datetime is not empty?
You would use something like this with NOT NULL:
CREATE TABLE [dbo].[MyTable](
[ID] [int] NOT NULL,
[MyField] [DATETIME] NOT NULL)
The NOT NULL constraint enforces a column to NOT accept NULL values.
The NOT NULL constraint enforces a field to always contain a value. This means that you cannot insert a new record, or update a record without adding a value to this field.
The following SQL enforces the "P_Id" column and the "LastName" column to not accept NULL values:
CREATE TABLE PersonsNotNull
(
P_Id int NOT NULL,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Address varchar(255),
City varchar(255)
)
If the date field has a point beyond which you know there will be no valid dates, you can set that as a lower boundary.
Date_Field date check( Date_Field > '2000-01-01' ),
If it is peoples birthdate, you will have to set it back to a more reasonable value. Now, now matter how the date is entered or what is is converted from, it must be within a reasonable range to be considered valid.

Oracle - How do I create a table that has an autoincrementing unique key for the ID

This is the first time that I've use oracle SQL and I'm having a problem creating tables with a unique key.
I don't understand why this auto-incrementing id is not working:
ID BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
The next question I have is why I am getting an error in each of my statements:
ORA-00922: missing or invalid option
Here is my code:
--
-- Sequence for aout incrment
--
CREATE SEQUENCE IF NOT EXISTS AUTO_INC_SEQ
START WITH 1
INCREMENT BY 1;
--
-- Table Person
--
CREATE TABLE IF NOT EXISTS FITNESS_PERSON
(
ID NUMBER NOT NULL PRIMARY KEY,
FIRST_NAME VARCHAR NOT NULL,
LAST_NAME VARCHAR NOT NULL,
NICK_NAME VARCHAR NOT NULL,
DATE_BIRTH DATE NOT NULL,
PASSWORD VARCHAR NOT NULL,
CONSTRAINT UNIQUE(NICK_NAME)
);
--
-- Table BMR
--
CREATE TABLE IF NOT EXISTS FITNESS_BMR
(
ID NUMBER NOT NULL PRIMARY KEY,
VALUE FLOAT NOT NULL,
VALUE_DATE DATE NOT NULL
);
--
-- M:N for BMR and Person
--
CREATE TABLE IF NOT EXISTS FITNESS_BMR_PERSON
(
BMR_ID NUMBER NOT NULL,
PERSON_ID NUMBER NOT NULL,
FOREIGN KEY(BMR_ID) REFERENCES FITNESS_BMR(ID),
FOREIGN KEY(PERSON_ID) REFERENCES FITNESS_PERSON(ID),
CONSTRAINT BMR_PER PRIMARY KEY(BMR_ID, PERSON_ID)
);
What's the right way to do this (create a table and with an auto-incrementing key that is unique).
You can use a table, a sequence to generate unique ID values and a trigger.
For example:
Table:
CREATE Table FITNESS_BMR
(
ID NUMBER NOT NULL PRIMARY KEY,
VALUE FLOAT NOT NULL,
VALUE_DATE DATE NOT NULL
);
Sequence: create sequence t1_seq start with 1 increment by 1 nomaxvalue;
Trigger:
CREATE OR REPLACE TRIGGER test_trigger
BEFORE INSERT
ON FITNESS_BMR
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT t1_seq.nextval INTO :NEW.ID FROM dual;
END;
/