MySql : Select statement inside Check statement - mysql

I have to create a table as following
Borrower(customerNo,LoanNo)
customers can take loans if they havent take more than 3 loans.
I created table as follows
create table borrower(
customerno int(5),
LoanNo int(5),
primary key(customerno,loanno),
check( customerno not in
(select customerno from borrower group by customerno having count(loanno)>=4))
);
But it givs me an error saying
[root#localhost:3306] ERROR 1146: Table 'test.borrower' doesn't exist
Can someone tell me how to fix this error??

The reason it's giving the error is because the CHECK constraint refers to the table being created, but it doesn't exist at the time that the statement is parsed.
But I have some bad news for you... mysql ignores CHECK constraints. It is allowed as syntax only for compatibility with create statements from other databases.
See the mysql documentation for CREATE TABLE:
The CHECK clause is parsed but ignored by all storage engines.
You'll have to use a trigger, but note that you can't throw an exception from one. The best you can hope for is when you detect a problem, do something like execute SELECT * FROM TOO_MANY_LOANS and hope that the caller figures out what the error "No such table TOO_MANY_LOANS" really means.

As this belongs to the business rules and not to data structure you should use a Stored Procedure like this
DELIMITER ;;
CREATE PROCEDURE `AddCustomerLoan`(IN Acustomerno int(5), IN ALoanNo int(5), OUT ResultCode INT)
BEGIN
SELECT COUNT(*)
INTO #LoanCount
FROM borrower
WHERE customerno = Acustomerno;
IF #LoanCount < 4 THEN
INSERT INTO borrower ( customerno, LoanNo )
VALUES ( Acustomerno, ALoanNo );
SET ResultCode = 0;
ELSE
-- Too many Entries
SET ResultCode = 1;
END IF;
END;;
DELIMITER ;
The ResultCode will inform your application if it was successful or not, and why not successful.
Another advantage is that you can modify the maximum entries or get the maximum entries per customer, without changing your application code.

Related

Selecting all values from a table in mysql using a stored procedure

I have a table called Contacts with a field called person_id that I have connected to a java application.
If no value is specified for person_id in the application, I want to select everything from the contacts table using a stored procedure.
The operation I want to perform is this:
Select * from Contacts where (person_id like "%")
For this I have written a stored procedure shown below:
Delimiter $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `selectTest2`(In p_id int(11))
BEGIN
if p_id = null then
set p_id = "%";
end if;
select * from Contacts where (person_id like p_id);
END $$
Delimiter ;
However when I run this procedure in my sql using the following
call selectTest2(null)
The table that is returned is blank. How do I make it show all the values in the table?
The parameter p_id gets its value from a text box in the application. If the user has entered an id, I want the procedure to show only that particular record else I want it to show all records.
What have I done wrong and how do I correct it? I am aware that p_id is an int however I tried the same thing with other fields of type varchar and the table failed to return any value.
Try using case statement in where clause like below
WHERE CASE WHEN p_id IS NOT NULL THEN person_id = p_id ELSE TRUE END
Hope this should solve your problem

MYSQL Trigger based on query

I have table called company. Structure as follows:
company
-----------------------------
company_id integer
company_name varchar
fk_company_type varchar
created_date date
fk_company_type is foreign key with the following values:
HQ
SITE
CUSTOMER
SUPPLIER
My issue I only want one record in company table to be HQ (HeadQuarters). Therefore I need a trigger that will count how many HQ in the company table. If it the count returns 1 and the new record being inserted has value of fk_company_type = HQ then the insert is aborted.
Any help on the best way to do this will be much appreciated. Also I already have a trigger which generates a UUID for the company_id and date. Hopefully this does not effect what I am trying to achieve.
phpadmin trigger (time: BEFORE, event: INSERT)
BEGIN
SET NEW.company_id=UUID_SHORT();
SET NEW.created_date=current_timestamp();
END
I've tried the basics layout and got as far as this but it produces a syntax error, here is how far I got.
BEGIN
IF fk_company_type = "HQ" THEN
DECLARE valid_number int;
SELECT COUNT(*) into valid_number FROM company WHERE fk_company_type = "HQ";
IF valid_number > 0 THEN
-- some error message
END IF;
END IF;
SET NEW.company_id=UUID_SHORT();
SET NEW.created_date=current_timestamp();
END
A simple way to abort an insert is to set a value to an illegal one.
for example if the column is set to NOT NULL then set the value to NULL and the insert will fail.
The question/issue of how you tell people it has failed depends on your application.

How to display result and or any message in trigger body?

Hi I want to create trigger if it's condition satisfy then it's body should be executed and I want to display some message or any data that should be displayed if trigger body executed.
I want that if quantity of product went less then 50 then it should display message or some data.
Is it possible to display message ?
Here testdata is table name.
Code :
delimiter //
create trigger trigger2 before update on test.testdata
for each row
begin
if new.qty < 50 then
**display here some message that quantity is less**
end if;
end;
//
delimiter ;
You cannot do it, there is no place to output them in MySQL. As a work around you can add your message to the table, and then read this table.
Short example -
CREATE TABLE table1 (
column1 VARCHAR(255) DEFAULT NULL
);
CREATE TABLE messages (
id INT(11) NOT NULL AUTO_INCREMENT,
message VARCHAR(255) DEFAULT NULL,
time TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
DELIMITER $$
CREATE TRIGGER trigger1
AFTER INSERT
ON table1
FOR EACH ROW
BEGIN
INSERT INTO messages(message) VALUES ('new action');
END
$$
DELIMITER ;
Also, you could use UDF function write your logic.
More information - CREATE FUNCTION Syntax for User-Defined Functions.
For Quick and plain answering: You cannot Display Messages From Triggers. You may Only Throw errors.
You are propably not knowing the reason u use triggers in databases assuming from your question. We all have passed that level so dont worry. U have understood the syntax when we use triggers but not how and what they can do and not.
A trigger will do (for your case BEFORE an UPDATE) something concerning the database and only that.
That means the trigger cannot display any message on your screen. You can only handle database staff and not all of the actions are allowed for that too or some actions arent even recommended!.
That is for the theory part.
To give you a solution to your problem now.
The only thing you can do to know when the trigger has worked (that means when the new.qua<50) or basically check anything with any other trigger is the following. (Just a small fast solution):
You need to create a Table that will handle all logging of the
triggers.
Add in it an ID field, a descr field that will hold the action of
the triggerex. BefUpdate, BefInsert etc. another field for the
propably the condition that triggered the logging and antyhing else
u want displayed later in the application.
Then inside the if condition u are using write and insert
statemement to fill the info in the new (logging) table.
in your app later select that logging table to see the messages.
That is a useful and fast way to log, not only triggers but also functions (stored procs).
Judt for reference i give you s sample code with the CREATE, and the INSERT statement for your trigger.
CREATE TABLE LOGGER (
ID BIGINT PRIMARY KEY AUTO_INCREMENT,
DESCR_ACTIVITY VARCHAR(10),
ACTIVITY VARCHAR(50),
DT TIMESTAMP,
CONDITIONVALUE VARCHAR(50)
)
In the IF of your code now make it as :
if new.qty < 50 then
INSERT INTO LOGGER VALUES ('BEFINS','CHECKING QUA',NULL,'QUANTITY IS LOWER THAN 50')
end if;
And even from the workbench or from your application u can just :
SELECT * FROM LOGGER
to see the loggings.
But if i am confused from the reading and you want just to throw an error u can read the Mysql Documentation concerning throwing errors:
enter link description here
What u can do is in your if condition write something like:
if new.qty < 50 then
SIGNAL SQLSTATE '01000' SET MESSAGE_TEXT = 'Lower than 50', MYSQL_ERRNO = 1000;
endif;
What u should always NOT DO is alter the same table that a trigger is assigned and use only small portion of not so complex code in the trigger.
Hope i helped a bit.
Also, you can display any message using the select command.
IF (NEW.qty < 50) THEN
SELECT "message that quantity is less" AS Output;
END IF
Place above code inside the trigger. It will print the output

Trigger issue with syntax

Hi to all im trying to create a trigger for this table:
create table Episode(
title varchar(25) not null,
number int not null,
length time not null,
aired date not null,
serie_name varchar(25),
PRIMARY KEY(title,number),
FOREIGN KEY (serie_name)REFERENCES Serie(name)
) ENGINE=InnoDB;
this is a table of a db that saves some tv series...so the trigger have to check if i m trying to insert a new episode that had benn aired before the precedent one....But i have some problem any solutions?
i tried this:
create trigger ControlDataEp
before insert on Episode
for each row
begin
if new.aired<(select aired from Episode where title=new.title and number=new.number-1)
then raise.application_error(-21,'error');
end if;
end;
If you don't that much care about returning meaningful error message you can simplify your trigger to one statement
CREATE TRIGGER ControlDataEp
BEFORE INSERT ON Episode
FOR EACH ROW
SET NEW.aired =
(
SELECT IF(IFNULL(MAX(aired), 0) < NEW.aired, NEW.aired, NULL)
FROM Episode
WHERE title = NEW.title
AND number = NEW.number - 1
);
What it does it violates NOT NULL constraint on aired column.
Here is SQLFiddle demo. Uncomment last insert statement
Now if you do need to return a custom error message:
You can use SIGNAL but only if you on MySql 5.5 and higher
Use one the hackish ways (read e.g. TRIGGERs that cause INSERTs to fail? Possible?, Throw an error in a MySQL trigger)
If I were you, I wouldn't use a trigger when there's no need to.
You can use
INSERT IGNORE ...
INSERT ... ON DUPLICATE KEY UPDATE ...
REPLACE ...
Please have a look in the respective manual pages I linked for additional information.
To explain, why your solution doesn't work:
if new.aired<(select aired
Your subquery might return multiple rows. Use SELECT MAX(aired) ... instead.
... and number=new.number-1)
It's a bad idea to rely on code outside the database to make sure, that data in the database is okay.
then raise.application_error(-21,'error');
raise.application_error() is not a MySQL built-in function. You can't call functions from your code in MySQL like this. If you really want to raise an error in MySQL use SIGNALs

MySQL Procedure check if record exists before insert not working

I have looked at the other questions on here about this. It isn't working.
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `environment_admin`(
IN environment_id TEXT,
IN user_id TEXT,
IN username VARCHAR(75),
IN password VARCHAR(512)
)
BEGIN
DECLARE env_id INT;
DECLARE admin_id INT;
SET env_id = CAST(environment_id AS SIGNED INT);
SET admin_id = CAST(user_id AS SIGNED INT);
IF NOT EXISTS(SELECT 1 FROM `environment`.`environment_accounts` WHERE environment_id = env_id AND user_id = admin_id) THEN
BEGIN
INSERT INTO
`environment`.`environment_accounts`
(
`environment_id`,
`user_id`,
`username`,
`password`,
`is_active`,
`is_admin`,
`is_mod`
)
VALUES
(
env_id,
admin_id,
username,
password,
1,
1,
1
);
END;
END IF;
END
So if I run:
CALL `environment`.`environment_admin`('22','1','kacieh','512c9ad228332bbd30d09ce7ffb8896e00a1610e914a5fa180bf15ce702b90423e6a9540579f672315ae3c6cb1b8d06ee2b784b4761e806675aa88c2a915553e');
I get 0 row(s) effected
and sure enough, nothing happened. -_- I have been working on this hours
I tested the conditional query, it works.
I have tested just the insert statement inside a stored proc, it works as well.
Stop doing it like that, it's inefficient and it could be worse if two insertare running concurrently! :)
Use INSERT.... ON DUPLICATE KEY UPDATE ... see here
One trick is to do ON DUPLICATE KEY UPDATE environment_id = env_id (not changing the column, so nothing will be updated, ensuring the INSERT will not work without any error condition, you might check number of modified/inserted rows after that)
I realise you've solved your problem (and +1 for Parallelis's answer, especially for highlighting the concurrency issue), but just in case it helps someone else...
MySQL was probably getting confused between your parameters environment_id and user_id and the environment_accounts columns environment_id and user_id. I suspect the parameters were taking precedence in the WHERE clause, meaning as long as there's at least one row in environment_accounts, the NOT EXISTS clause would always return false, and your insert would never run.
For example, if your environment_id and user_id parameters had values of 1 and 2 respectively, the NOT EXISTS clause would evaluate as
IF NOT EXISTS(SELECT 1 FROM `environment`.`environment_accounts` WHERE 1 = 1 AND 2 = 2) THEN
Might be worth having a naming convention for your parameters (and other variables), such as adding a prefix like p_ for parameter.