Increasing a numeric column, how do not trigger unique constraints? - mysql

for example:
CREATE TABLE test_serial_no_entity (
id BIGINT,
serial_no BIGINT NOT NULL UNIQUE,
PRIMARY KEY (id)
);
INSERT INTO test_serial_no_entity (id, serial_no) VALUES (1,1);
INSERT INTO test_serial_no_entity (id, serial_no) VALUES (2,2);
INSERT INTO test_serial_no_entity (id, serial_no) VALUES (3,3);
INSERT INTO test_serial_no_entity (id, serial_no) VALUES (4,4);
serial_no is a unique column, when i execute the sql: update test_serial_no_entity set serial_no=serial_no+1 where id>=1 ,
I got the error Error Code: 1062. Duplicate entry '2' for key 'serial_no' 0.034 sec in mysql, Is there any other way to solve this problem except to cancel the unique constraint?

Yes, update the higher values first.
update test_serial_no_entity
set serial_no=serial_no+1
where id>=1
ORDER BY serial_no DESC
An example of this can also be found in the manual.

Try loop to update one record at a time. Start from the maximum number.
CREATE TABLE test_serial_no_entity (
id BIGINT,
serial_no BIGINT NOT NULL UNIQUE,
PRIMARY KEY (id)
);
INSERT INTO test_serial_no_entity (id, serial_no) VALUES (1,1);
INSERT INTO test_serial_no_entity (id, serial_no) VALUES (2,2);
INSERT INTO test_serial_no_entity (id, serial_no) VALUES (3,3);
INSERT INTO test_serial_no_entity (id, serial_no) VALUES (4,4);
Declare #Min int, #Iterator int
Select #Min = min(serial_no) from test_serial_no_entity
Select #Iterator = max(serial_no) from test_serial_no_entity
While(#Iterator >= #Min)
BEGIN
Update test_serial_no_entity
Set serial_no = serial_no + 1
Where serial_no = #Iterator
#Iterator = #Iterator - 1
END

Related

how can I form a stored procedure in mysql, which can first check multiple values on multiple tables and then insert into db if true

The actual problem statement looks like :
• Product(prod_id, prod_name, qty_on_hand)
• Order(cust_id, prod_id, order_date, qty_ordered)
• Customer(cust_id, cust_name, phone, address)
"Write a stored procedure to take the cust_id, prod_id and qty_ordered as
input. Procedure should check if the order for a particular customer can be
fulfilled and if yes then insert the new order and update the product
quantity on hand. Display appropriate message if the order cannot be
fulfilled.
Output parameter must have updated value of the qty_on_hand"
I am new to plsql so ignore silly mistakes. I tried to code something like this :
delimiter $$
-- creating procedure
CREATE PROCEDURE order_request( cust_id int, prod_id int, qty_ordered int)
BEGIN
IF( customer.cust_id != cust_id AND product.prod_id != prod_id AND qty_ordered > product.qty_on_hand) THEN
SELECT 'invalid details' ;
ELSE INSERT INTO `orders` (`cust_id`, `prod_id`, `order_date`, `qty_ordered`) VALUES (cust_id, prod_id, current_date(), qty_ordered) ;
END IF ;
END $$
CALL order_request(3,3,2)$$
which showing me error : unknown table customer in field list
I have solved the question. Here is the solution:
CREATE DATABASE shopping;
USE shopping;
CREATE TABLE product( prod_id INT PRIMARY KEY, prod_name varchar(20), qty_on_hand INT CHECK(qty_on_hand >= 0));
CREATE TABLE customer( cust_id INT PRIMARY KEY, cust_name varchar(20), phone INT, address varchar(20) );
-- product table insertion
INSERT INTO `product` (`prod_id`, `prod_name`, `qty_on_hand`) VALUES ('1', 'mug', '2');
INSERT INTO `product` (`prod_id`, `prod_name`, `qty_on_hand`) VALUES ('2', 'bowl', '15');
INSERT INTO `product` (`prod_id`, `prod_name`, `qty_on_hand`) VALUES ('3', 'plate', '7');
INSERT INTO `product` (`prod_id`, `prod_name`, `qty_on_hand`) VALUES ('4', 'fork', '40');
INSERT INTO `product` (`prod_id`, `prod_name`, `qty_on_hand`) VALUES ('5', 'spoon', '30');
-- customer table insertion
INSERT INTO `customer` (`cust_id`, `cust_name`, `phone`, `address`) VALUES ('1', 'duke', '1212121212', 'pune');
INSERT INTO `customer` (`cust_id`, `cust_name`, `phone`, `address`) VALUES ('2', 'finn', '190120138', 'waterland');
INSERT INTO `customer` (`cust_id`, `cust_name`, `phone`, `address`) VALUES ('3', 'buck', '98989898', 'delhi');
INSERT INTO `customer` (`cust_id`, `cust_name`, `phone`, `address`) VALUES ('4', 'larry', '738197232', 'jaipur');
INSERT INTO `customer` (`cust_id`, `cust_name`, `phone`, `address`) VALUES ('5', 'edna', '184194791', 'mumbai');
CREATE TABLE orders( cust_id INT, prod_id INT, order_date DATE, qty_ordered INT CHECK(qty_ordered > 0) , FOREIGN KEY (cust_id) REFERENCES customer(cust_id), FOREIGN KEY (prod_id) REFERENCES product(prod_id));
-- orders table insertion
INSERT INTO `orders` (`cust_id`, `prod_id`, `order_date`, `qty_ordered`) VALUES ('1', '2', '2022-09-15', '2');
delimiter $$
-- creating procedure
CREATE PROCEDURE order_request( cust_id_param INT, prod_id_param INT, qty_ordered_param INT)
BEGIN
IF EXISTS (SELECT cust_id,prod_id,qty_on_hand FROM customer,product WHERE cust_id = cust_id_param AND prod_id = prod_id_param AND qty_on_hand >= qty_ordered_param)
THEN INSERT INTO `orders` (`cust_id`, `prod_id`, `order_date`, `qty_ordered`) VALUES (cust_id_param, prod_id_param, current_date(), qty_ordered_param);
UPDATE `product` SET product.qty_on_hand = qty_on_hand - qty_ordered_param WHERE prod_id = prod_id_param ;
ELSE SELECT 'invalid details' ;
END IF ;
END $$
CALL order_request(1,1,2)$$ -- valid
CALL order_request(3,2,14)$$ -- valid
CALL order_request(5,4,4)$$ -- valid
CALL order_request(10,10,2)$$ -- invalid
select * from orders$$
select * from product$$
-- creating the funtion
CREATE FUNCTION order_details (cust_id_param INT, prod_id_param INT ) RETURNS INT
BEGIN
DECLARE ans int;
SELECT SUM(qty_ordered) INTO ans FROM orders WHERE cust_id = cust_id_param AND prod_id = prod_id_param;
RETURN ans;
END$$
-- calling the funtion
SELECT order_details(5,4)$$

How can I write this complex query SQL?

If I know how to filter by all signs of the zodiac, then by the sign of the zodiac 'Capricorn' (from December 22 to January 20) I do not know how to select.
Here is the structure of the tables, do I need to select all users with the sign of the zodiac 'Capricorn'?
The structure of the tables can be changed (or even add new tables if required):
CREATE TABLE IF NOT EXISTS `horoscope` (
`id` INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(255) NOT NULL UNIQUE,
`date_start` VARCHAR(5),
`date_end` VARCHAR(5)
);
CREATE INDEX `horoscope_idx_1` ON `horoscope`(`date_start`, `date_end`);
CREATE TABLE IF NOT EXISTS `user` (
`id` INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(255) NOT NULL,
`birthday` DATE NOT NULL
);
Insert test data
# Insert horoscope in table
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Aries', '03-21', '04-20');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Taurus', '04-21', '05-20');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Gemini', '05-22', '06-21');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Cancer', '06-22', '07-22');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Leo', '07-23', '08-23');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Virgin', '08-24', '09-22');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Libra', '08-23', '10-22');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Scorpio', '10-23', '11-21');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Sagittarius', '11-22', '12-21');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Capricorn', '12-22', '01-20');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Aquarius', '01-21', '02-19');
INSERT INTO `horoscope` (`name`, `date_start`, `date_end`) VALUES ('Pisces', '02-20', '03-20');
# Insert random user in table
DROP PROCEDURE IF EXISTS `add_user`;
CREATE PROCEDURE `add_user`(IN `count_user` INT)
LANGUAGE SQL
DETERMINISTIC
SQL SECURITY DEFINER
COMMENT 'A procedure for inserting random user'
BEGIN
DECLARE i INT DEFAULT (
SELECT `id`
FROM `user`
ORDER BY `id` DESC
LIMIT 1
);
IF i IS NULL
THEN SET i = 1;
END IF;
SET `count_user` = `count_user` + i;
WHILE i <= `count_user` DO
SET #`name` = CONCAT('user_', i);
SET #`user_birth` = '1980-01-01' + INTERVAL (RAND() * 365 * 20) DAY;
INSERT INTO `user` (`name`, `birthday`) VALUES (#`name`, #`user_birth`);
SET i = i + 1;
END WHILE;
END;
CALL `add_user`(1000);
DROP PROCEDURE IF EXISTS `add_user`;
I decided =)
SELECT *
FROM user as u
WHERE (
DATE_FORMAT(u.birthday, '%m%d') >= (
SELECT
CONCAT(LEFT(`h`.`date_start`, 2), RIGHT(`h`.`date_start`, 2))
FROM horoscope h
WHERE h.name = 'Capricorn'
) AND DATE_FORMAT(u.birthday, '%m%d') <= 1231
) OR (
DATE_FORMAT(u.birthday, '%m%d') >= 101 AND DATE_FORMAT(u.birthday, '%m%d') <= (
SELECT
CONCAT(LEFT(`h`.`date_end`, 2), RIGHT(`h`.`date_end`, 2))
FROM horoscope h
WHERE h.name = 'Capricorn'
)
);
If the boundaries of each zodiac sign are fixed dates, then it would make sense to add birth-sign as an attribute to each user instead of filtering by dates each and every time you need that information.
However I would suggest the following if you do need to filter:
select *
from user u
inner join horoscope h
where (h.date_start > h.date_end
and u.birthday between str_to_date(concat(year(u.birthday)-1, h.date_start),'%Y%m-%d')
and str_to_date(concat(year(u.birthday), h.date_end),'%Y%m-%d')
)
or (h.date_start < h.date_end
and u.birthday between str_to_date(concat(year(u.birthday), h.date_start),'%Y%m-%d')
and str_to_date(concat(year(u.birthday), h.date_end),'%Y%m-%d')
)
Note however that the indexing of the 2 varchar(5) columns in horoscope probably isn't going to be helpful to your queries.
see: https://rextester.com/OAOTEH65480

SQL - Insert into table if doesn't have data

I'm using MYSQL script and I want to insert some values in a table.
INSERT INTO `testType` (`name`) VALUES ('URL');
INSERT INTO `testType` (`name`) VALUES ('xD');
INSERT INTO `testType` (`name`) VALUES ('LOL');
But I only want to insert if the table is empty in the first place.
I'm not a SQL guy but basically
if(testType.length() == 0 {
INSERT INTO `testType` (`name`) VALUES ('URL');
INSERT INTO `testType` (`name`) VALUES ('xD');
INSERT INTO `testType` (`name`) VALUES ('LOL');
}
How can I do this the simplest and smallest way possible? Thank you.
EDIT: my question is different. I want to insert ALL THE DATA if the table is empty. not only one insert at the time
First, I would suggest doing this in one step:
INSERT INTO testType(name)
VALUES ('URL'), ('xD'), ('LOL');
Then, you can express this without IF:
INSERT INTO testType(name)
SELECT t.name
FROM (SELECT 'URL' as name UNION ALL
SELECT 'xD' as name UNION ALL
SELECT 'LOL' as name
) t
WHERE NOT EXISTS (SELECT 1 FROM testType);
Finally, if you want to insert these values if each doesn't exist, then you can let the database do the work. First, define a unique constraint/index on the name (if name is not already the primary key), and then use ON DUPLICATE KEY UPDATE:
CREATE UNIQUE INDEX unq_testtable_name ON testtable(name);
INSERT INTO testType(name)
VALUES ('URL'), ('xD'), ('LOL')
ON DUPLICATE KEY UPDATE name = VALUES(name);
You can use stored procedure
DELIMITER //
CREATE PROCEDURE `proc1` ()
BEGIN
SELECT COUNT(*) INTO variable1 FROM testType;
IF variable1 = 0 THEN
INSERT INTO `testType` (`name`) VALUES ('URL');
INSERT INTO `testType` (`name`) VALUES ('xD');
INSERT INTO `testType` (`name`) VALUES ('LOL');
END WHILE;
END //
Try this:
DECLARE #ExistCount INT;
SET #ExistCount = (SELECT COUNT(1) FROM `testType`);
IF #ExistCount<1
THEN
INSERT INTO `testType` (`name`) VALUES ('URL'),('xD'),('LOL');
END IF;

Unique constraints across a many to many relationship table

Is there any way to add a constraint to ensure that an entry of X in one column can then only allow an entry of Y in another column?
Say I have two tables, stripped down to minimal columns, tbl_1 has a pk. tbl_2 has 2 columns - a pk and a text string.
These tables are joined by a 3rd relationship table because they're many to many and it uses pk from tbl1 and tbl2.
t1_pk t2_pk | t2_str t1fk | t2fk
x 1 AAA x 1
y 2 BBB x 2
z 3 AAA y 3
4 BBB y 4
z 1
z 2
All entries above are allowed, but now I'm trying to figure out how I can constrict the relationship table so that the string attached to t2_pk can only tie in to the t1_pk ONCE. E.g. in the 3rd table:
t1fk | t2fk
x 3
would not be allowed because x-1 exists and both 1 and 3 have the string AAA attached. One way I can think without making 3 more tables and going round in circles, is to move the string to the relationship table and add a constraint so if the t2fk number exists in the table already it'll only allow the number again if accompanied by the same string.
is there a background process for this I can declare like adding a unique constraint, or would it simply need to be imposed by a stored procedure?
Either you add a t2_str column to your third table that contains the relations or you create a new table for this purpose. Here an example how to implement the new table tab_constr.
drop table if exists tab_constr;
drop table if exists tab_rel;
drop table if exists tab_1;
drop table if exists tab_2;
CREATE TABLE tab_1 (
t1_pk varchar(5),
PRIMARY KEY (t1_pk)
);
CREATE TABLE tab_2 (
t2_pk INT,
t2_str varchar(10) NOT NULL,
PRIMARY KEY (t2_pk),
INDEX(t2_pk, t2_str)
);
CREATE TABLE tab_rel (
t1_pk varchar(5),
t2_pk INT,
PRIMARY KEY (t1_pk,t2_pk),
INDEX (t2_pk),
FOREIGN KEY (t1_pk) REFERENCES tab_1(t1_pk),
FOREIGN KEY (t2_pk) REFERENCES tab_2(t2_pk)
);
CREATE TABLE tab_constr (
t1_pk varchar(5),
t2_str varchar(10),
t2_pk int,
PRIMARY KEY pair_already_exists(t1_pk,t2_str),
INDEX(t1_pk, t2_pk),
INDEX(t2_pk, t2_str),
FOREIGN KEY (t1_pk, t2_pk) REFERENCES tab_rel(t1_pk, t2_pk)
ON DELETE CASCADE,
FOREIGN KEY (t2_pk, t2_str) REFERENCES tab_2(t2_pk, t2_str)
ON UPDATE CASCADE
);
CREATE TRIGGER tr_ins_rel AFTER INSERT ON tab_rel
FOR EACH ROW
BEGIN
INSERT INTO tab_constr ( t1_pk, t2_str, t2_pk)
select new.t1_pk, t2_str, new.t2_pk
from tab_2
where t2_pk=new.t2_pk
;
END;
INSERT INTO tab_1 (t1_pk) VALUES ('x');
INSERT INTO tab_1 (t1_pk) VALUES ('y');
INSERT INTO tab_1 (t1_pk) VALUES ('z');
INSERT INTO tab_2 (t2_pk,t2_str) VALUES (1, 'AAA');
INSERT INTO tab_2 (t2_pk,t2_str) VALUES (2, 'BBB');
INSERT INTO tab_2 (t2_pk,t2_str) VALUES (3, 'AAA');
INSERT INTO tab_2 (t2_pk,t2_str) VALUES (4, 'BBB');
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('x', 1);
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('x', 2);
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('y', 3);
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('y', 4);
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('z', 1);
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('z', 2);
commit;
The following statement will raise an error:
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('x', 3);
This also raises an error
UPDATE tab_2 set t2_str='BBB' where t2_pk=1;
But this will work
DELETE FROM tab_rel where t1_pk='x' and t2_pk=1;
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('x', 3);
and this will work
UPDATE tab_2 set t2_str='XXX' where t2_pk=1;
Here you can try it out.
Of course this additional table violates normal form and adds redundancy to your database. But that is no problem because this table tab_constr is an auxiliary structure like an index and it will be automatically maintained by the database. So no insert/update/delete anomalies will occur.

MySQL: What's wrong with this CREATE PROCEDURE statement?

DROP PROCEDURE IF EXISTS CreateTopic;
CREATE PROCEDURE CreateTopic
(
i_forum_id INT,
i_user_id INT,
i_title VARCHAR(255),
i_language VARCHAR(50),
i_content TEXT,
i_stickied TINYINT,
i_announce TINYINT,
i_closed TINYINT
)
BEGIN
INSERT INTO forum_topics (forum_id, user_id, title, language)
VALUES (i_forum_id, i_user_id, i_title, i_language);
SET #tid := LAST_INSERT_ID();
INSERT INTO forum_posts (topic_id, user_id, subject, content) VALUES (#tid, i_user_id, i_title, i_content);
INSERT INTO core_logs (obj_id, user_id, type, action) VALUES (#tid, i_user_id, 'Topics', 'Topic Created');
END;
I'm not sure what's wrong with it. MySQL tells me all sorts of things are incorrect, it just doesn't want to be created. Also, the parameters are identical types and lengths to their respective tables.
It is your first ";" that breaks procedure definition and mysql thinks you are done and treats whatever goes after ";" as another query.
You have to use delimiter for stored procedures.
DELIMITER $$
DROP PROCEDURE IF EXISTS CreateTopic$$
CREATE PROCEDURE CreateTopic
(
i_forum_id INT,
i_user_id INT,
i_title VARCHAR(255),
i_language VARCHAR(50),
i_content TEXT,
i_stickied TINYINT,
i_announce TINYINT,
i_closed TINYINT
)
BEGIN
INSERT INTO forum_topics (forum_id, user_id, title, language)
VALUES (i_forum_id, i_user_id, i_title, i_language);
SET #tid := LAST_INSERT_ID();
INSERT INTO forum_posts (topic_id, user_id, subject, content) VALUES (#tid, i_user_id, i_title, i_content);
INSERT INTO core_logs (obj_id, user_id, type, action) VALUES (#tid, i_user_id, 'Topics', 'Topic Created');
END
$$
DELIMITER ;
There are a few problems. I hope I got them all:
DROP PROCEDURE IF EXISTS CreateTopic;
CREATE PROCEDURE CreateTopic
(
i_forum_id INT,
i_user_id INT,
i_title VARCHAR(255),
i_language VARCHAR(50),
i_content TEXT,
i_stickied TINYINT,
i_announce TINYINT,
i_closed TINYINT
)
BEGIN
DECLARE tid INT;
INSERT INTO forum_topics (`forum_id`, `user_id`, `title`, `language`)
VALUES (i_forum_id, i_user_id, i_title, i_language);
SET tid = LAST_INSERT_ID();
INSERT INTO forum_posts (`topic_id`, `user_id`, `subject`, `content`) VALUES (tid, i_user_id, i_title, i_content);
INSERT INTO core_logs (`obj_id`, `user_id`, `type`, `action`) VALUES (tid, i_user_id, 'Topics', 'Topic Created');
END;