Check constraint for current date and expire date on credit card - sql

Currently learning MariaDB, struggling to add a check constraint for a payments table. I want to check that the inputted expiration date for the credit/debit card is after the current date.
Create table payments (
customerID int(11) Not Null,
debit_credit_Num varchar(20) Not Null,
expireDate date Not Null,
CVS int(3) Not Null,
billaddress varchar(100) Not Null,
billcity varchar(100) Not Null,
billprovince varchar(10) Not Null,
billpostalcode varchar(10) Not Null,
billcountry varchar(100) Not Null,
Constraint fk_has_customerpayment Foreign Key (customerID) References customers(customerID),
Constraint chk_expdate check (date('now') < expireDate);
)
2 errors were found during analysis.
A symbol name was expected! A reserved keyword can not be used as a column name without backquotes. (near "check" at position 463).
Unrecognized statement type. (near "date" at position 470)
MariaDB said:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 14
Input query sample
Insert into payments (customerID, debit_credit_Num, expireDate, cvs, billAddress, billcity, billprovince, billpostalcode, billcountry) values
(1, '1234 5678 9123 4567', '2025-07-01', 213, '123 Church St', 'Burnaby', 'BC', 'V5A 1S6', 'Canada'),
(2, '0968 1723 2859 1902', '2025-04-01', 874, '321 W Popeyes Dr', 'Vancouver', 'BC', 'V6B 2J2', 'Canada')
(2, '0968 1723 2859 1111', '1999-04-01', 874, '321 W Popeyes Dr', 'Vancouver', 'BC', 'V6B 2J2', 'Canada'); <--- Should fail constraint
Edit 1
Thank you Umut TEKİN, I tried making a trigger like so but I don't know where I went wrong
CREATE TRIGGER chk_expdate
BEFORE INSERT
ON payments
FOR EACH ROW
BEGIN
IF (new.expiredate < CURRENT_DATE) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Card has expired'; [<------ Line 8]
END IF;
END;
Error Message: MySQL said:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 8
It works on
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=efb986c7edb6b4a3755639e2a380cae4
but not on PHPMyAdmin.
Edit 2
Managed to make trigger work by adding a delimiter on phpmyadmin following Paul T's answer to link
delimiter//
CREATE TRIGGER chk_expdate
BEFORE INSERT ON payments
FOR EACH ROW BEGIN
IF (new.expiredate < CURRENT_DATE) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Card has expired';
END IF;
END;

You have 2 problem here. First one syntax (missing parenthesis or misplaced semicolon). It should be like this:
Create table payments (
customerID int(11) Not Null,
debit_credit_Num varchar(20) Not Null,
expireDate date Not Null,
CVS int(3) Not Null,
billaddress varchar(100) Not Null,
billcity varchar(100) Not Null,
billprovince varchar(10) Not Null,
billpostalcode varchar(10) Not Null,
billcountry varchar(100) Not Null,
Constraint fk_has_customerpayment Foreign Key (customerID) References customers(customerID),
Constraint chk_expdate check (check condition));
Second one is date(now()) or curdate() are nondeterministic functions. So this usage is not allowed.
Literals, deterministic built-in functions, and operators are
permitted. A function is deterministic if, given the same data in
tables, multiple invocations produce the same result, independently of
the connected user. Examples of functions that are nondeterministic
and fail this definition: CONNECTION_ID(), CURRENT_USER(), NOW().
Reference
Yet, triggers allow you to do that. It' s better also to check here.

Related

Constraint not working as desired for my INSERT?

I am creating a Table named "Cliente" with some constraints on it as it follows:
CREATE TABLE public."Cliente" (
"K_CODCLIENTE" numeric(5) NOT NULL,
"N_NOMBRE1" varchar(15) NOT NULL,
"N_NOMBRE2" varchar(15) NOT NULL,
"N_APELLIDO1" varchar(15) NOT NULL,
"N_APELLIDO2" varchar(15),
"N_DIRECCION" varchar(50) NOT NULL,
"Q_TELEFONO" numeric(10) NOT NULL,
"K_CODREF" numeric(5),
"I_TIPOID" varchar(2) NOT NULL,
"Q_IDENTIFICACION" varchar(10) NOT NULL,
CONSTRAINT "PK_Cliente" PRIMARY KEY ("K_CODCLIENTE"),
CONSTRAINT "UQ_ID_TIPOID_CLIENTE" UNIQUE ("I_TIPOID","Q_IDENTIFICACION"),
CONSTRAINT "CK_CODCLIENTE" CHECK ("K_CODCLIENTE" >= 100),
CONSTRAINT "CK_Q_IDENTIFICACION" CHECK ("Q_IDENTIFICACION" IN ('CC', 'PA', 'CE', 'NI', 'OT'))
);
When I try to insert some values on it:
INSERT INTO "Cliente"
VALUES ('101','Juan','Felipe','Ortiz','Rojas','AK 15 no. 28-05','3101125507',null,'CC','51111111');
I get the following error (in PostgreSQL 14, on Fedora):
[23514] ERROR: new row for relation "Cliente" violates check constraint "CK_Q_IDENTIFICACION"
Detail: Failing row contains (101, Juan, Felipe, Ortiz, Rojas, AK 15 no. 28-05, 3101125507, null, CC, 51111111).
I am trying to restrict the "Q_IDENTIFICACION" column so it can only be filled with 'CC', 'PA', 'CE, 'NI' or 'OT'.
Maybe I'm doing something wrong when declaring the constraint "CK_Q_IDENTIFICACION"?
Seems like you messed up the mapping of values and are trying to insert '51111111' to "Q_IDENTIFICACION".
Consider this more revealing variant with a formatted list of target columns:
INSERT INTO "Cliente"
("K_CODCLIENTE", "N_NOMBRE1", "N_NOMBRE2", "N_APELLIDO1", "N_APELLIDO2", "N_DIRECCION" , "Q_TELEFONO", "K_CODREF", "I_TIPOID", "Q_IDENTIFICACION")
VALUES ('101' , 'Juan' ,'Felipe' , 'Ortiz' , 'Rojas' , 'AK 15 no. 28-05', '3101125507', NULL , 'CC' , '51111111'); -- !
Maybe you want to switch the last two column names in the table definition - and (not) adapt the VALUES list in the INSERT accordingly? (varchar(2) vs. varchar(10) seems switched as well.)
For persisted code, it's generally advisable to spell out target columns in an INSERT command in any case.
Asides:
Reconsider all these pesky double-quoted upper case identifiers. See:
Are PostgreSQL column names case-sensitive?
Consider plain type text instead of varchar(n) with strikingly tight character limits. See:
Any downsides of using data type "text" for storing strings?

How to create a PL/SQL row trigger that validates a column from another table

I have two tables:
CREATE TABLE PRODUCT
(
PRODUCT_NAME VARCHAR(40) NOT NULL,
SUPPLIER_NAME VARCHAR(40) NOT NULL,
CATEGORY_NAME VARCHAR(30) NOT NULL,
QUANTITY_PER_UNIT VARCHAR(20) NULL,
UNIT_PRICE NUMBER(10,2) DEFAULT 0,
UNITS_IN_STOCK NUMBER(9) DEFAULT 0,
UNITS_ON_ORDER NUMBER(9) DEFAULT 0,
REORDER_LEVEL NUMBER(9) DEFAULT 0,
DISCONTINUED CHAR(1) DEFAULT 'N',
CONSTRAINT PK_PRODUCT PRIMARY KEY (PRODUCT_NAME),
CONSTRAINT FK_CATEGORY_NAME FOREIGN KEY (CATEGORY_NAME) REFERENCES CATEGORY(CATEGORY_NAME),
CONSTRAINT FK_SUPPLIER_NAME FOREIGN KEY (SUPPLIER_NAME) REFERENCES SUPPLIER(COMPANY_NAME),
CONSTRAINT CK_PRODUCT_UNIT_PRICE CHECK (UNIT_PRICE >= 0),
CONSTRAINT CK_PRODUCT_UNITS_IN_STOCK CHECK (UNITS_IN_STOCK >= 0),
CONSTRAINT CK_PRODUCT_UNITS_ON_ORDER CHECK (UNITS_ON_ORDER >= 0),
CONSTRAINT CK_PRODUCT_REORDER_LEVEL CHECK (REORDER_LEVEL >= 0),
CONSTRAINT CK_PRODUCT_DISCONTINUED CHECK (DISCONTINUED in ('Y','N'))
);
CREATE TABLE SUPPLIER
(
COMPANY_NAME VARCHAR(40) NOT NULL,
CONTACT_NAME VARCHAR(30) NOT NULL,
CONTACT_TITLE VARCHAR(30) NOT NULL,
ADDRESS VARCHAR(60) NOT NULL,
CITY VARCHAR(15) NOT NULL,
REGION VARCHAR(15) NULL,
POSTAL_CODE VARCHAR(10) NOT NULL,
COUNTRY VARCHAR(15) NOT NULL,
PHONE VARCHAR(24) NOT NULL,
FAX VARCHAR(24) NULL,
HOME_PAGE VARCHAR(500) NULL,
TRUSTED_SUPPLIER VARCHAR(3) NULL,
CONSTRAINT PK_SUPPLIER PRIMARY KEY (COMPANY_NAME)
);
I need to create a ROW TRIGGER that automatically verifies if information about a new product to be inserted into the database is supplied by a trusted supplier. If a supplier is not trusted, then the insertion must fail and an error message must be displayed.
Here is my row trigger so far:
CREATE OR REPLACE TRIGGER VERIFY_SUPPLIER_TRUST
BEFORE INSERT ON PRODUCT
FOR EACH ROW
DECLARE TRUST VARCHAR(3);
BEGIN
SELECT SUPPLIER.TRUSTED_SUPPLIER
INTO TRUST
FROM SUPPLIER
INNER JOIN PRODUCT ON PRODUCT.SUPPLIER_NAME = SUPPLIER.COMPANY_NAME
WHERE SUPPLIER.TRUSTED_SUPPLIER = 'YES';
IF TRUST = 'NO' THEN
RAISE_APPLICATION_ERROR(20001, 'SUPPLIER NOT TRUSTED');
END IF;
END;
/
However when I try to test the trigger with valid and non-valid insert statements:
//this should insert without errors
INSERT INTO PRODUCT
(PRODUCT_NAME, SUPPLIER_NAME, CATEGORY_NAME, QUANTITY_PER_UNIT, UNIT_PRICE,
UNITS_IN_STOCK, UNITS_ON_ORDER, REORDER_LEVEL, DISCONTINUED)
VALUES
('Backlestan','Exotic Liquids', 'Beverages', '10 boxes x 30 bags',
11, 20, 0, 27, 'N');
// this should display the trigger's error
INSERT INTO PRODUCT
(PRODUCT_NAME, SUPPLIER_NAME, CATEGORY_NAME, QUANTITY_PER_UNIT, UNIT_PRICE,
UNITS_IN_STOCK, UNITS_ON_ORDER, REORDER_LEVEL, DISCONTINUED)
VALUES
('Backlestan','Another Company', 'Beverages', '10 boxes x 30 bags',
11, 20, 0, 27, 'N');
I receive these errors:
Error report -
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "RK721.VERIFY_SUPPLIER_TRUST", line 4
ORA-04088: error during execution of trigger 'BH576.VERIFY_SUPPLIER_TRUST'
Error report -
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "RK721.VERIFY_SUPPLIER_TRUST", line 4
ORA-04088: error during execution of trigger 'BH576.VERIFY_SUPPLIER_TRUST'
Does anybody know how to fix this error? Any help would be greatly appreciated!
There are several issues with your trigger. Let's begin with the 'relationship' between a select statement and remaining code. In this particular case the select.. and the if...end_if (for the moment assume your select actually works, it does not but just assume). Now concentrate on the WHERE clause.
SELECT SUPPLIER.TRUSTED_SUPPLIER
INTO TRUST
...
WHERE SUPPLIER.TRUSTED_SUPPLIER = 'YES';
IF TRUST = 'NO' THEN ...
Since your select returns ONLY YES the if statement will never be True. Therefore the application exception can never be raised. Now, what are the issues with the select.
Well first you are accessing the table that the trigger is fired upon. While in some cases you can get away with it but usually it results in an ORA-04091: table <table_name> is mutating, trigger/function may not see it. It is bust to always avoid referencing the triggering table altogether. You reference the table data with the :NEW and/or :OLD pseudo records. Secondly, your query is not doing what you think it is. It says
Select the trusted_supplier column for every row in the Supplier
table that has at least 1 row in the Product table and the
trusted_supplier column is 'YES'.
However the INTO clause requires the statement to return exactly 1 row. More that 1 row results in the exception, and 0 rows results in a no data found exception.
Finally there is an issue with the raise_application_error statement. If it were executed it would raise an number argument...is out of range exception. The first parameter must be between -20999 to -20000 (Negative number).
So what does the result look like:
create or replace trigger verify_supplier_trust
before insert or update on product
for each row
declare
trust varchar2(3);
begin
select supplier.trusted_supplier
into trust
from supplier
where supplier.company_name = :new.supplier_name
and supplier.trusted_supplier = 'YES';
exception
when no_data_found then
raise_application_error(-20001, 'supplier not trusted');
end;
/
NOTES:
DO not use data type VARCHAR. It is allowed but Oracle recommends against it. Means they are reserving the right to change what it does at any time. Use the recommended VARCHAR2 instead.
I change the trigger to fire on either Insert or Update. If fired on Insert only someone CAN change the supplier_name to reference a non-trusted supplier and all would be fine.
You must filter by the inserted row's id!
And not by SUPPLIER.TRUSTED_SUPPLIER = 'YES'
BEGIN
SELECT SUPPLIER.TRUSTED_SUPPLIER
INTO TRUST
FROM SUPPLIER
INNER JOIN PRODUCT ON PRODUCT.SUPPLIER_NAME = SUPPLIER.COMPANY_NAME
WHERE PRODUCT.PRODUCT_NAME = :NEW.PRODUCT_NAME;
Try this:
create or replace TRIGGER VERIFY_SUPPLIER_TRUST
BEFORE INSERT ON PRODUCT
REFERENCING NEW AS NEW_PRODUCT
FOR EACH ROW
DECLARE TRUST_COUNT NUMBER;
BEGIN
SELECT COUNT(*)
INTO TRUST_COUNT
FROM SUPPLIER
WHERE SUPPLIER.TRUSTED_SUPPLIER = 'YES'
and SUPPLIER.COMPANY_NAME = :NEW_PRODUCT.SUPPLIER_NAME;
IF TRUST_COUNT = 0 THEN
RAISE_APPLICATION_ERROR(20001, 'SUPPLIER NOT TRUSTED');
END IF;
END;
/
For this set of data:
INSERT INTO SUPPLIER(COMPANY_NAME,CONTACT_NAME,CONTACT_TITLE,ADDRESS,CITY,REGION,POSTAL_CODE,COUNTRY,PHONE,FAX,HOME_PAGE,TRUSTED_SUPPLIER)
VALUES('C1','C1','CT1','A1','R1','PC1','C1','P1','F1','H1','H1','YES');
INSERT INTO SUPPLIER(COMPANY_NAME,CONTACT_NAME,CONTACT_TITLE,ADDRESS,CITY,REGION,POSTAL_CODE,COUNTRY,PHONE,FAX,HOME_PAGE,TRUSTED_SUPPLIER)
VALUES('C2','C1','CT1','A1','R1','PC1','C1','P1','F1','H1','H1','NO');
COMMIT;
This insert works:
INSERT INTO PRODUCT(PRODUCT_NAME, SUPPLIER_NAME, CATEGORY_NAME, QUANTITY_PER_UNIT, UNIT_PRICE, UNITS_IN_STOCK, UNITS_ON_ORDER, REORDER_LEVEL, DISCONTINUED)
VALUES('Backlestan111','C1', 'Beverages', '10 boxes x 30 bags', 11, 20, 0, 27, 'N'); /* it works*/
But this one, doesn't:
INSERT INTO PRODUCT(PRODUCT_NAME, SUPPLIER_NAME, CATEGORY_NAME, QUANTITY_PER_UNIT, UNIT_PRICE, UNITS_IN_STOCK, UNITS_ON_ORDER, REORDER_LEVEL, DISCONTINUED)
VALUES('Backlestan222','C2', 'Beverages', '10 boxes x 30 bags', 11, 20, 0, 27, 'N'); /* it doesn't work*/

postgres syntax error at or near "ON"

I created this table:
CREATE TABLE IF NOT EXISTS config_activity_log
(
id serial primary key,
activity_name varchar(100) NOT NULL,
last_config_version varchar(50) NOT NULL,
activity_status varchar(100) NOT NULL DEFAULT 'Awaiting for cofman',
cofman_last_update bigint NOT NULL DEFAULT -1,
is_error boolean DEFAULT FALSE,
activity_timestamp timestamp DEFAULT current_timestamp
);
I try to run this postgres script:
INSERT INTO config_activity_log
(activity_name, last_config_version, activity_status)
VALUES
('test awating deployment','5837-2016-08-24_09-12-22', 'Awaiting for deployment')
ON CONFLICT (activity_name)
DO UPDATE SET
activity_status = EXCLUDED.activity_status
why do i get this syntax error?
psql:upsert_test_log.sql:7: ERROR: syntax error at or near "ON"
LINE 5: ON CONFLICT (activity_name)
Supported Version
Per #klin's comment above, ON CONFLICT is only supported from PostgreSQL 9.5 onwards.
If you're on an earlier version, there's some great info in this answer: https://stackoverflow.com/a/17267423/361842
Unique Constraint
Add a unique index on activity_name. At present there's no constraints on that column, so there's no possibility for a conflict on that column.
CREATE UNIQUE INDEX UK_config_activity_log__activity_name
ON config_activity_log (activity_name);
If, however, you don't want that column to be unique, what conflict are you envisaging / what's the issue you're hoping to resolve with the on conflict action?
See conflict_target in https://www.postgresql.org/docs/9.5/static/sql-insert.html#SQL-ON-CONFLICT
An alternative syntax is to modify your create statement to include the unique condition there; e.g.
CREATE TABLE IF NOT EXISTS config_activity_log
(
id serial primary key,
activity_name varchar(100) NOT NULL UNIQUE,
last_config_version varchar(50) NOT NULL,
activity_status varchar(100) NOT NULL DEFAULT 'Awaiting for cofman',
cofman_last_update bigint NOT NULL DEFAULT -1,
is_error boolean DEFAULT FALSE,
activity_timestamp timestamp DEFAULT current_timestamp
);
According to the error code, your version does not support ON CONFLICT.
On PostreSQL 9.6 the error message is -
[Code: 0, SQL State: 42P10] ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification

SQL table display error

I am encountering a display issue with my SQL code and was hoping someone could help me figure out whats going on. When I create my CUSTOMER table then INSERT a line of values it works successfully... however, when I type select * from customer; then it displays horrible output where none of the data is lined up in the columns properly. Can you please take a look at my code and tell me what I can do to fix this.
I have multiple tables in this database and none of the other tables have this issue and display properly. My window was configured using these two lines of code:
SET LINESIZE 132
SET PAGESIZE 50
My table creation code:
CREATE TABLE Customer
(
CustomerID NUMBER(5) NOT NULL CONSTRAINT PK_Customer_CustomerID PRIMARY KEY,
BillingID NUMBER(5) NOT NULL,
CustomerFName VARCHAR2(40) NOT NULL,
CustomerLName VARCHAR2(40) NOT NULL,
CustomerPhone VARCHAR2(10) NOT NULL,
CustomerStreet VARCHAR2(30)NOT NULL,
CustomerCity VARCHAR2(30) NOT NULL,
CustomerState CHAR(2) NOT NULL,
CustomerZip VARCHAR2(9) NOT NULL,
CustomerEmail VARCHAR2(75) NOT NULL,
SignUp_Date DATE DEFAULT sysdate NOT NULL,
CustomerStatus CHAR(1) NOT NULL CONSTRAINT CC_Customer_CustomerStatus CHECK (CustomerStatus IN ('A', 'I')),
InactiveDate DATE,
InactiveReason VARCHAR2(200),
CustomerBillingCycle CHAR(1) NOT NULL CONSTRAINT CC_Customer_CustomerBC CHECK (CustomerBillingCycle IN ('A', 'B'))
);
My line of values being inserted into the table:
INSERT INTO Customer VALUES (01234, 99012, 'Michael', 'Huffaker', '6235551414', '65 N 35th Ln', 'Glendale', 'AZ', '85308', 'm.huffaker#quickmail.com', '29-MAY-2010', 'A', NULL, NULL, 'A');
As I stated above, both of these work successfully and the problem appears when I display the data in the table. Check out the screen shot link below to see the messed up output:
http://i.stack.imgur.com/uMu4S.png
It's not messed up at all; the output lines are just "wrapping" the output after 132 characters. It's very normal. I don't use command line often for running selects, but try routing the output to a file. Or perhaps try with a very large LINESIZE setting (like 1000 or so). Your terminal windows may not support a line that wide.

Writing CASE statement Error ORA-00923

I have a database that I have populated using CREATE and INSERT INTO statements. I am now trying to write a CASE statemenet that will display 'customers' whose payment_due_date has passed todays date. Below is the following code
CREATE STATEMENT 'Ord'(Order)
CREATE TABLE Ord(OrderID varchar2(9) PRIMARY KEY,
CustomerID varchar(9) REFERENCES Customer(CustomerID),
Expected_Delivery_Date date DEFAULT sysdate NOT NULL,
Actual_Delivery_Date date DEFAULT sysdate NOT NULL,
Payment_Due_Date date DEFAULT sysdate NOT NULL,
Order_Date date DEFAULT sysdate NOT NULL, Price Varchar(10),
Order_Placed varchar2(1) CONSTRAINT OrderPlaced
CHECK(Order_Placed IN('Y','N')) NOT NULL, Order_Confirmed varchar2(1)
CONSTRAINT Order_Confirmed CHECK(Order_Confirmed IN('Y','N'))
NOT NULL, Order_Completed varchar2(1) CONSTRAINT Order_Completed
CHECK(Order_Completed IN('Y','N')) NOT NULL)
INSERT STATEMENT
INSERT INTO Ord VALUES(401565981, 501623129,
'10-Dec-10', '11-Dec-10', '07-Dec-10', '03-Dec-10','£14.99', 'Y', 'Y', 'Y')
CASE STATEMENT
SELECT OrderID, CustomerID, Payment_Due_Date CASE WHEN
Payment_Due_Date = '08-Dec-10' THEN 'Send Final Demand Letter'
ELSE 'Do not send letter'
END FROM Ord;
When I try to run the above case statement I recieve the following error
ORA-00923: FROM keyword not found
where expected
00923. 00000 - "FROM keyword not found where expected"
*Cause:
*Action: Error at Line: 26 Column: 50
Is there any possible way around this?
I think you need a comma between Payment_Due_Date and CASE.