How can I avoid duplicate values in my result set? - mysql

CREATE TABLE student
(
s_id int(10) NOT NULL AUTO_INCREMENT,
s_roll_no int(30),
s_name varchar(30),
s_gender varchar(4) not null,
class int(2) not null,
PRIMARY KEY (s_id)
);
CREATE TABLE attendance_date
(
date_today varchar(10),
PRIMARY KEY (date_today)
);
CREATE TABLE attendance_today
(
s_id int(10),
s_roll_no int(30),
s_name varchar(30),
s_gender varchar(4),
class int(2),
date_today varchar(10),
attendance_status varchar(2) not null default 'P'
);
delimiter $$
create trigger after_insertion_into_attendance_date
after insert on attendance_date
for each row
begin
insert into attendance_today(s_id, s_roll_no, s_name, s_gender, class, date_today)
select * from student cross join attendance_date order by date_today, s_id;
end$$
delimiter ;
INSERT INTO student
VALUES
(1,1,'Mridul Kumar','M',1),
(2,2,'Harish Paul','M',1),
(3,3,'Imtiaz Hossain','M',1);
INSERT INTO attendance_date
VALUES
('1st Jan'),
('2nd Jan');
now,
select * from attendance_today;
giving duplicates after every insertion, is there any way to avoid such duplicates inside trigger?
I'm not looking for
select distinct * from attendance_today;
after the trigger gets activated.

This will prevent duplicate values from being inserted
insert into attendance_today(s_id, s_roll_no, s_name, s_gender, class, date_today)
select *
from student cross join attendance_date ad
WHERE NOT EXISTS (
SELECT null FROM attendance_today at
WHERE ad.s_id = at.s_id and ad.date_today = at.date_today
)
order by date_today, s_id;

Try this:
begin
insert into attendance_today(s_id, s_roll_no, s_name, s_gender, class, date_today)
select * from student cross join attendance_date group by s_id order by date_today, s_id;
end$$

Related

Why doesn't my MySql-Query work the way I would like it to work?

I have a MySQL-DB which has three tables: drugs, ingredients (both have a m:n relationship) and a linking table/association table. So obviously a drug can have multiple ingredients and ingredients are allowed to be in multiple drugs. I wanna create a website, where my user can select <=3 ingredients he wanna have in his drug and <=3 ingredients he don't wanna have. Therefore I created a stored procedure:
DROP procedure IF EXISTS `getMeds`;
DELIMITER $$
USE `epharmacy`$$
CREATE PROCEDURE `getMeds` (IN all1 VARCHAR(10), IN all2 VARCHAR(10), IN all3 VARCHAR(10),
IN unall1 VARCHAR(10), IN unall2 VARCHAR(10), IN unall3 VARCHAR(10))
BEGIN
SELECT m_id, m_name, i_id, i_name FROM epharmacy.`mi_med-ing` INNER JOIN epharmacy.`m_medication`
INNER JOIN epharmacy.`i_ingredients`
ON mi_m_id = m_id AND mi_i_id = i_id
#Allowed
WHERE (i_id = all1 OR all1 = '')
AND (i_id = all2 OR all2 = '')
AND (i_id = all3 OR all3 = '')
#Unallowed
AND ((i_id!= unall1 OR unall1 = '')
AND (i_id != unall2 OR unall2 = '')
AND (i_id != unall3 OR unall3 = ''))
ORDER BY m_id ASC;
END
$$
DELIMITER ;
call getMeds('I005', 'I006', 'I007', 'I001', 'I002', 'I003');
But this somehow doesn't work. I should get two drugs in return, but I don't get anything. I tried many things, like subsqueries and other JOINS, but it didn't help. Hope you can :)
Edit:
That's how my DB looks like:
m_medication:
CREATE TABLE IF NOT EXISTS `m_medication` (
`m_id` varchar(10) NOT NULL,
`m_name` varchar(500) DEFAULT NULL,
PRIMARY KEY (`m_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `m_medication` (`m_id`, `m_name`) VALUES('M00001', 'drug1');
INSERT INTO `m_medication` (`m_id`, `m_name`) VALUES('M00002', 'drug2');
i_ingredients:
CREATE TABLE IF NOT EXISTS `i_ingredients` (
`i_id` varchar(10) NOT NULL,
`i_name` varchar(500) DEFAULT NULL,
PRIMARY KEY (`i_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `i_ingredients` (`i_id`, `i_name`) VALUES('I005', 'ingredient1');
INSERT INTO `i_ingredients` (`i_id`, `i_name`) VALUES('I006', 'ingredient2');
INSERT INTO `i_ingredients` (`i_id`, `i_name`) VALUES('I007', 'ingredient3');
mi_med-ing:
CREATE TABLE IF NOT EXISTS `mi_med-ing` (
`mi_id` varchar(10) NOT NULL,
`mi_i_id` varchar(10) DEFAULT NULL,
`mi_m_id` varchar(10) DEFAULT NULL,
PRIMARY KEY (`mi_id`),
KEY `mi_i_id` (`mi_i_id`),
KEY `mi_m_id` (`mi_m_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO mi_med-ing (mi_id, mi_i_id, mi_m_id) VALUES('MI001', 'I005', 'M00001');
INSERT INTO mi_med-ing (mi_id, mi_i_id, mi_m_id) VALUES('MI002', 'I006', 'M00001');
INSERT INTO mi_med-ing (mi_id, mi_i_id, mi_m_id) VALUES('MI003', 'I007', 'M00001');
INSERT INTO mi_med-ing (mi_id, mi_i_id, mi_m_id) VALUES('MI004', 'I005', 'M00002');
INSERT INTO mi_med-ing (mi_id, mi_i_id, mi_m_id) VALUES('MI005', 'I006', 'M00002');
INSERT INTO mi_med-ing (mi_id, mi_i_id, mi_m_id) VALUES('MI006', 'I007', 'M00002');
Foreign Keys:
ALTER TABLE `mi_med-ing`
ADD CONSTRAINT `mi_med-ing_ibfk_1` FOREIGN KEY (`mi_i_id`) REFERENCES `i_ingredients` (`i_id`),
ADD CONSTRAINT `mi_med-ing_ibfk_2` FOREIGN KEY (`mi_m_id`) REFERENCES `m_medication` (`m_id`);
To find all the medicines that have all the required ingredients, you need to perform a grouped query in the join table; see How to return rows that have the same column values in MySql.
To exclude the unallowed ingredients, use a subquery that returns any medicines that have any of these ingredients, and then use m_id NOT IN (subquery) to filter them out.
CREATE PROCEDURE `getMeds` (IN all1 VARCHAR(10), IN all2 VARCHAR(10), IN all3 VARCHAR(10),
IN unall1 VARCHAR(10), IN unall2 VARCHAR(10), IN unall3 VARCHAR(10))
BEGIN
DECLARE all_count INT DEFAULT (all1 != '') + (all2 != '') + (all3 != '');
SELECT m_id, m_name, i_id, i_name
FROM (SELECT mi_m_id
FROM `mi_med-ing`
WHERE mi_i_id IN (all1, all2, all3)
GROUP BY mi_m_id
HAVING COUNT(*) = all_count) AS a
INNER JOIN `mi_med-ing` AS mi ON mi.mi_m_id = a.mi_m_id
INNER JOIN `m_medication` ON mi.mi_m_id = m_id
INNER JOIN `i_ingredients` ON mi.mi_i_id = i_id
WHERE m_id NOT IN (
SELECT mi_m_id
FROM `mi_med-ing`
WHERE mi_i_id IN (unall1, unall2, unall3)
)
ORDER BY m_id ASC;
END
There are three tables:
m_medication = drug
i_ingredients = ingedient
mi_med-ing = bridge table for their m:n relation
You want to return drugs with all their ingredients, where the following applies for the drug:
all desired ingredients are in the drug
no undesired ingredients are in the drug
Two steps:
Aggregate the bridge table per drug to find all drugs that fulfill all the requirements.
Select all thus found drugs and their ingredients.
The procedure:
CREATE PROCEDURE getMeds (IN all1 VARCHAR(10), IN all2 VARCHAR(10), IN all3 VARCHAR(10),
IN unall1 VARCHAR(10), IN unall2 VARCHAR(10), IN unall3 VARCHAR(10))
BEGIN
SELECT m.*, i.*
FROM epharmacy.m_medication m
JOIN epharmacy.`mi_med-ing` mi ON mi.mi_m_id = m.m_id
JOIN epharmacy.i_ingredients i ON i.i_id = mi.mi_i_id
WHERE m.m_id IN
(
SELECT mi_m_id
FROM epharmacy.`mi_med-ing`
GROUP BY mi_m_id
HAVING (all1 = '' OR SUM(mi_i_id = all1) > 0)
AND (all2 = '' OR SUM(mi_i_id = all2) > 0)
AND (all3 = '' OR SUM(mi_i_id = all3) > 0)
AND (unall1 = '' OR SUM(mi_i_id = unall1) = 0)
AND (unall2 = '' OR SUM(mi_i_id = unall2) = 0)
AND (unall3 = '' OR SUM(mi_i_id = unall3) = 0)
)
ORDER BY m.m_id, i.i_id;
END
How the aggregation works: In MySQL true = 1 and false = 0. I add up boolean expressions and hence get 0 when there is no match at all or > 0 when there is a match in the group.
Demo: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=2e623f39daac369e3ac58ff1b18d992b

mysql select function running twice

I want to use a function inside a select query.
This is my test database.
When I use a select, get a result, but the function is running twice... why? I want to insert one row in this case.
Help, please!
create database db1_test;
use db1_test;
create table t1(
id int(11) primary key auto_increment,
t1col1 varchar(20) not null,
t1col2 int(1) not null
);
create table t2(
id int(11) primary key auto_increment,
t2col1 int(11) not null,
t2col2 datetime
);
insert into t1 (t1col1, t1col2) values ('row1', 1);
insert into t1 (t1col1, t1col2) values ('row2', 0);
insert into t1 (t1col1, t1col2) values ('row4', 1);
drop function if exists func1;
DELIMITER $$
CREATE FUNCTION func1(id int) RETURNS datetime
BEGIN
insert into t2 (`t2col1`, `t2col2`) values (id, now());
RETURN now();
END $$
DELIMITER ;
TEST :
SELECT id, t1col2, func1(id) FROM `t1` WHERE 1 and `t1`.`t1col1`='row1';
SELECT id, t1col2, func1(id) FROM `t1` WHERE 1 and `t1`.`t1col1`='row2';
SELECT id, t1col2, func1(id) FROM `t1` WHERE 1 and `t1`.`t1col1`='row4';
Functions are generally used to store reuseable code which returns a scalar value from a calculation or transformation. I think you could
insert into t2(t2col1,t2col2)
SELECT id, now()
FROM `t1`
WHERE `t1`.`t1col1`='row1';

How shall I modify my trigger so that I can get the total_employees according to their departments?

tables are given below.
CREATE TABLE `departments` (
department_id INT(2) NOT NULL AUTO_INCREMENT,
department_name VARCHAR(30) NOT NULL,
total_employees INT(4),
PRIMARY KEY (department_id),
UNIQUE (department_name));
CREATE TABLE `employees` (
employee_id INT(4) NOT NULL AUTO_INCREMENT,
employee_email VARCHAR(30) NOT NULL,
employee_first_name VARCHAR(30) NOT NULL,
employee_last_name VARCHAR(30) NOT NULL,
department_name VARCHAR(30) NOT NULL,
PRIMARY KEY (employee_id),
UNIQUE (employee_email),
FOREIGN KEY (department_name)
REFERENCES departments (department_name)
ON DELETE CASCADE);
this is the trigger, I want it to be showing the sum of total employees in each department.
delimiter $$
create trigger department_wise_total_employee_counting
after insert on employees
for each row begin update departments set total_employees=total_employees+1
where department_id=department_id; end$$ delimiter ;
INSERT INTO `departments`
VALUES
(1,'HRM',0),(2,'Accounting',0);
INSERT INTO `employees`
VALUES
(1,'bh#gmail.com','A','B','HRM'),
(2,'ak#gmail.com','C','D','HRM'),
(3,'mr#gmail.com','E','F','HRM'),
(4,'pr#gmail.com','G','H','Accounting');
On running the following query :
select * from departments;
I'm getting this output, which just gives the total employee count rather than the total for each department.
I am trying to get total_employees=3 for HRM and total_employees=1 for Accounting.
Would appreciate any sort of suggestions.
As was pointed out by #P.Salmon, in general you shouldn't store data you can easily calculate. For this application, a VIEW (as suggested by #TamilSelvanC) is a good solution. For example:
CREATE VIEW departments_view AS
SELECT d.department_id, d.department_name, COUNT(e.employee_id) AS total_employees
FROM departments d
LEFT JOIN employees e ON e.department_name = d.department_name
GROUP BY d.department_id;
SELECT * FROM departments_view
Output:
department_id department_name total_employees
1 HRM 3
2 Accounting 1
3 Engineering 0
Demo on dbfiddle

Error in creating a stored procedure

I'm trying to retrieve values by joining two tables (the customer and enquiry table),then i'm trying to store the retrieved values into another table that would come in handy for reasons irrelevant here.And then i'm finally deleting the retrieved values from the enquiry table. When i'm trying to execute the stored procedure i'm getting the following error shown in the screenshot below.
how do i resolve this error?
Stored Procedure:-
CREATE PROCEDURE `backup_eq`(
IN `eq` VARCHAR(15), IN `mail` VARCHAR(30), IN `dates` DATE, IN `cmp` VARCHAR(10), IN `rea` VARCHAR(50))
NOT DETERMINISTIC MODIFIES SQL DATA SQL SECURITY DEFINER
BEGIN
SELECT eqno into #eno,Date1 into #d,cmpname into #c,subject into #s,cid into #cd
FROM `enquiry` NATURAL JOIN `customer`
WHERE eqno=eq and email=mail and cmpname=cmp and Date=dates;
INSERT INTO `enquiryBin`(`Eqno`, `Date1`, `Cmpname`, `Subject`, `CID`, `Reason`)
VALUES (#eno,#d,#c,#s,#cd,rea);
DELETE FROM `enquiry`
WHERE eqno=eq and cid=#cd and cmpname=cmp and Date1=dates;
END
The create table statements of the two tables are given below
CREATE TABLE `customer` (
`CID` int(15) NOT NULL,
`Address` varchar(100) NOT NULL,
`Name` varchar(20) NOT NULL,
`email` varchar(30) NOT NULL,
`phone` bigint(20) NOT NULL
)
ALTER TABLE `customer`
ADD PRIMARY KEY (`CID`);
CREATE TABLE `enquiry` (
`Eqno` varchar(15) NOT NULL,
`Date1` date NOT NULL,
`Cmpname` varchar(10) NOT NULL,
`Subject` varchar(100) NOT NULL,
`CID` int(15) NOT NULL
)
ALTER TABLE `enquiry`
ADD PRIMARY KEY (`Eqno`,`Cmpname`,`CID`,`Date1`)
SELECT eqno into #eno,Date1 into #d,cmpname into #c,subject into #s,cid into #cd
Should be
SELECT eqno, Date1, cmpname, subject, cid INTO #eno, #d, #c, #s, #cd
That is, name all columns in the select-list separately from the INTO clause.
Refer to syntax documentation: https://dev.mysql.com/doc/refman/5.7/en/select-into.html
There's no need for all those variables, just use an INSERT INTO ... SELECT query, and a JOIN in the DELETE query.
INSERT INTO enquiryBin (`Eqno`, `Date1`, `Cmpname`, `Subject`, `CID`, `Reason`)
SELECT eqno, Date1, cmpname, subject, cid, rea
FROM FROM `enquiry` NATURAL JOIN `customer`
WHERE eqno=eq and email=mail and cmpname=cmp and Date1 = dates;
DELETE e FROM enquiry AS e
NATURAL JOIN customer
WHERE eqno = eq AND email = mail AND cmpname = cmp AND Date1 = dates

MySQL stored procedure to insert or update table

I have two tables:
CREATE TABLE EMPLOYEE (
EMPLOYEE_ID bigint NOT NULL AUTO_INCREMENT,
EMPLOYEE_NO VARCHAR(30),
EMPLOYEE_TYPE VARCHAR(20),
PRIMARY KEY(EMPLOYEE_ID)
);
CREATE TABLE EMP_DETAIL(
EMPLOYEE_ID BIGINT NOT NULL ,
INS_ID VARCHAR(20) ,
SALARY int,
PRIMARY KEY(EMPLOYEE_ID ,INS_ID),
FOREIGN KEY(EMPLOYEE_ID) REFERENCES EMPLOYEE(EMPLOYEE_ID)
);
I want to insert a value in the emp table and the emp_detail table. If the employee already exists, then only insert a record in the emp_details table.
This is the stored procedure:
CREATE PROCEDURE INSERTEMP(
IN EMPLOYEE_NO VARCHAR(30),
IN EMPLOYEE_TYPE VARCHAR(20),
IN INS_ID VARCHAR(20),
IN SALARY INT
)
BEGIN
DECLARE EMPLOYEE_ID BIGINT;
SET #EMPLOYEE_ID= (SELECT IFNULL((SELECT EMPLOYEE_ID FROM EMPLOYEE WHERE EMPLOYEE_NO=EMPLOYEE_NO AND EMPLOYEE_TYPE=EMPLOYEE_TYPE) ,'0'));
IF #EMPLOYEE_ID=0 THEN
INSERT INTO EMPLOYEE (EMPLOYEE_NO ,EMPLOYEE_TYPE ) VALUES (EMPLOYEE_NO,EMPLOYEE_TYPE);
SET #EMPLOYEE_ID=(SELECT LAST_INSERT_ID());
END IF;
INSERT INTO EMP_DETAIL(EMPLOYEE_ID,INS_ID,SALARY) VALUES (#EMPLOYEE_ID,INS_ID,SALARY);
END
If I call the procedure:
CALL INSERTEMP(100, 'PERM','AAA',100);
first execute it created id as 1 in emp table if execute it in second time also insert with new id and third time it fails.
Can someone help?