Find the Supplier number for those suppliers who supply every part - mysql

I have the following tables:
Suppliers(Sno, Sname, Address)
Parts(Pno, Pname, Colour)
Catalogue(Sno, Pno, Price)
and I want to find the Sno of the suppliers who supply every part.
So far, I've written this:
SELECT s.sname
FROM suppliers s JOIN catalogue c
USING s.sno
Now how do I write the part "suppliers that supply every part"?
I was thinking about having the count(*) from parts = count(pno) for each supplier Sno. Could someone please give me a hint/write the first part of the equality?
Thanks!

SELECT s.sname
FROM suppliers s
INNER JOIN catalogue c
ON s.Sno = c.Sno
GROUP BY s.sname
HAVING COUNT(c.Pno) = (SELECT COUNT(Pno) FROM Parts)

You're close. You need to add a group by/having clause with a subquery:
group by s.sname having count(*) = (select count(*) from catalogue)

Off the top of my head, you could write
SELECT s.Sno
FROM suppliers s
WHERE NOT EXISTS (
SELECT p.Pno
FROM parts p
WHERE NOT EXISTS (
SELECT c.*
FROM catalogue c
WHERE c.Pno = P.Pno
AND c.Sno = S.Sno
)
)
i.e. supplier where not exists (part that we don't supply), for a solution avoiding counts. No idea if this would be more or less efficient than the counts.

SELECT s.Sno, s.Sname
FROM Suppliers s
CROSS JOIN Parts p
LEFT JOIN Catalogue c ON s.Sno = c.Sno AND p.Pno = c.Pno
GROUP BY s.Sno, s.Sname
HAVING COUNT(*) = COUNT(c.Pno)

Try this:
alter proc clr
#c char(10),
#pno int output
as
begin
declare #f int
if exists(select p# from p where colour=#c)
begin
select #pno=p# from p where colour=#c
--set #f=1
end
-- else
-- set #f=0
-- return #f
end
--clr 'red',2
select p# from p where colour='red'
alter proc prcs
#c char(20)
as
begin
declare #pno numeric(2)
declare #f int
exec #f=clr #c,#pno output
--if #f=1
-- begin
select #pno
select s# from sp where p#=#pno
--set #i=1
-- end
--set #i=0
--return #i
end
prcs 'red'
select * from sp
select * from p,sp where p.p#=sp.p# and colour='red'
alter proc prcj
#c char(10)
as
begin
declare #i int
exec #i=prcs #c
if #i=1
begin
print'list of supplier'
select sname from s
where s#=#c
end
else
print'this record is not found'
end

Related

Comparing primary Id of the same row in same table

Can't find the same questions as mine I'm hoping you guys can help me.
I have this query for my SP what I need to do is check if the company Id is the same based on the parameter given by the user.
I have two parameters which are paramOrgA and paramOrgB which will be supplied by the user.
What I did was repeat the same query and set the returned value in two variables which is
orgAId and orgBId then use the IF statement to compare the value.
is there another way to accomplish this or should I say optimized way to do this?
Below is the query I wrote.
BEGIN
declare orgAId int;
declare orgBId int;
declare orgStatus bool;
SET orgAId = (SELECT c.Id
FROM Members as `m`
INNER JOIN Company as `c`
ON m.CompanyId = c.Id
WHERE m.Id = paramOrgA);
SET orgBId = (SELECT c.Id
FROM Members as `m`
INNER JOIN Company as `c`
ON m.CompanyId = c.Id
WHERE m.Id = paramOrgB);
IF (orgAId = orgBId) THEN
set orgStatus = true;
ELSE
set orgStatus = false;
END IF;
select orgStatus as 'CompanyStatus';
END IF;
END
One query will do
SELECT count(distinct c.Id) > 1 as 'CompanyStatus'
FROM Members as `m`
INNER JOIN Company as `c` ON m.CompanyId = c.Id
WHERE m.Id IN (paramOrgA, paramOrgB)
Even fewer keystrokes:
SELECT COUNT(DISTINCT CompanyId) > 1 as 'CompanyStatus'
FROM Members
WHERE Id IN (paramOrgA, paramOrgB)

How can I fix this stored procedure in mysql workbench I keep getting error code 1222

Context: I'm basically trying to show the clients that have had two or more appointments and if they do then they are preferred clients but if they have less than two they are no preferred. However, I keep running into the problem stated above.
Use plastic_surgeon;
DROP PROCEDURE IF EXISTS sp_updated_preferred_status;
ALTER TABLE clients
ADD column client_status varchar (60);
DELIMITER //
CREATE PROCEDURE sp_updated_preferred_status ()
BEGIN
DECLARE client_status varchar (20);
Select c.ID, count(a.ID) as number_of_appts
INTO client_status
from clients as c
join appointments as a
on c.ID = a.Client_ID
group by c.ID
having count(a.ID) > 1 ;
IF count(a.ID) > 1 THEN
SELECT 'preferred' as message;
ELSE
SELECT 'not preferred' as message;
END IF;
END//
DELIMITER ;
Call sp_updated_preferred_status ();
SELECT clients.ID,
CASE WHEN COUNT(appointments.Client_ID) > 1
THEN 'preferred'
ELSE 'not preferred'
END AS client_status
FROM clients
LEFT JOIN appointments ON clients.ID = appointments.Client_ID
GROUP BY clients.ID
and respectively
UPDATE clients
JOIN ( SELECT clients.ID,
CASE WHEN COUNT(appointments.Client_ID) > 1
THEN 'preferred'
ELSE 'not preferred'
END AS client_status
FROM clients
LEFT JOIN appointments ON clients.ID = appointments.Client_ID
GROUP BY clients.ID ) AS data_for_update USING (ID)
SET clients.client_status = data_for_update.client_status

Adding procedure in database

I'm trying to create a procedure that adds data into two tables at the same time but using mySQL, but I don't have much experience using if/else statement in database so could someone tell me how I can fix my code
Here the Attributes:
Customer information: ID,Name, Address, Telephone.
Staff information: ID, Name, Phone
Camera/Len Type: ID,Name
Camera: ID, typeID, Model, Status, Color, Hiring Price (per day), Paying Price (in case of loss).
Len: ID, TypeID, Model, Status, Hiring Price (per day), Paying Price (in case of loss).
Order orderID, customerID, employeeID, hireDate, returnDate
OrderDetail: orderID, cameraID, lenID, cameraQuantity, lenQuantity, Status(paid/not paid), pStatus(Lost/Ok)
Here's the Procedure code:
DELIMITER $$
Create Procedure addOrder(IN cust_id int, IN camera_id int, IN len_id int,
IN emp_id int, IN c_quantity int,IN l_quantity int,
IN status char(30), IN p_Status char(30), IN hire_date date, IN return_date
date)
begin
Declare order_id int;
Declare hireTime int;
Declare totalC int;
Declare totalL int;
Declare totalP int;
Select order_id = max(orderID) from orders;
if orderID is null then set order_id = 1;
Set hireTime = DATEDILL(hire_date, return_date);
if hire_date == return_date then set hireTime = 1;
if p_Status = "Lost" then set
select totalC = hireTime*c_quantity*hPrice + pPrice from Camera as C
inner join orderDetail as OD on C.camID = OD.camera_id inner join Orders
as O on O.orderID = OD.order_id;
select totalL = hireTime*l_quantity*hPrice + pPrice from Lens as L
inner join orderDetail as OD on L.lenID = OD.len_id inner join Orders as
O on O.orderID = OD.order_id;
Set totalP = totalL + totalC;
else set
select totalC = hireTime*c_quantity*hPrice + pPrice from Camera as C
inner join orderDetail as OD on C.camID = OD.camera_id inner join Orders
as O on O.orderID = OD.order_id;
select totalL = hireTime*l_quantity*hPrice + pPrice from Lens as L
inner join orderDetail as OD on L.lenID = OD.len_id inner join Orders as
O on O.orderID = OD.order_id;
Set totalP = totalL + totalC;
end if;
insert into Orders(custID, empID, hireDate, returnDate)
values (cust_id, emp_id,hire_date, return_date);
insert into orderDetail(orderID, cameraID, lenID, totalPrice, camQuantity,
lenQuantity, status, pStatus) values (order_id,camera_id, len_id, totalP,
c_quantity, l_quantity, status, p_Status);
end $$
DELIMITER
I think u need to use view table to add all tables after that use stored procedure. And I give you and example I think u can figure out.
CREATE PROCEDURE [dbo].[sp_CMIDByID] #UID INT, #TID INT
AS
BEGIN
DECLARE #CMID INT
IF(#TID IS NULL AND #UID IS NOT NULL)
BEGIN
SELECT #TID = TID, #CMID = CMID FROM tbl_U WHERE UID = #UID
END
IF (#CMID IS NULL AND #TID IS NOT NULL)
BEGIN
SELECT #CMID = CMID FROM tbl_T WHERE TID = #TID
END
SELECT #CMID
END

MySQL summary function on N-th row

I try to create a function, that returns the summary on the n-th row, where n defined by the order a query result.
This is what I have:
CREATE DEFINER=`root`#`localhost` FUNCTION `fn_inventory_stock_on_note`( fIngredient int, fInventory int, fNote int ) RETURNS float
DETERMINISTIC
BEGIN
DECLARE tStock float;
DECLARE tNoteRow int;
DECLARE tDummy int;
DECLARE rStock float;
DECLARE rRow int;
SET tNoteRow = 0;
SET #rRow := 0;
SELECT #rRow := #rRow + 1, b.ID
INTO tNoteRow, tDummy
FROM fn_inventory_book b
LEFT JOIN fn_inventory_book_in bi ON b.id = bi.bookid
LEFT JOIN fn_inventory_book_out bo ON b.id = bo.bookid
LEFT JOIN fn_dict_transactions t ON b.transactionid = t.id
WHERE b.inventoryid = fInventory
AND ( bi.ingredientid = fIngredient OR bo.ingredientid = fIngredient )
HAVING b.ID = fNote
ORDER BY b.date ASC, t.direction ASC;
SET #rRow := 0;
SET #rStock := 0;
SELECT rStock INTO tStock
FROM ( SELECT #rRow := #rRow + 1 as rRow, #rStock := #rStock + ifnull( if( bi.id is not null, bi.quantity, bo.quantity ), 0 ) * t.direction as rStock
FROM fn_inventory_book b
LEFT JOIN fn_inventory_book_in bi ON b.id = bi.bookid
LEFT JOIN fn_inventory_book_out bo ON b.id = bo.bookid
LEFT JOIN fn_dict_transactions t ON b.transactionid = t.id
WHERE b.inventoryid = fInventory
AND ( bi.ingredientid = fIngredient OR bo.ingredientid = fIngredient )
ORDER BY b.date ASC, t.direction ASC ) as q
WHERE rRow = tNoteRow;
RETURN tStock;
END
Where fIngredient and fInventory is an id for the query's filter, and fNote is a PK from the fn_inventory_book table.
The first select gets the required row's number in the order, which works fine.
My problem is in the second query, which in the subquery creates a table with the same filter and order like the first select, with the same row numbers, and the cumulative quantity of each row. And in the main query I filter that with the row number I got in the first select.
At least this is what should happen. But instead of that, when I run the function like:
select fn_inventory_stock_on_note( 1545, 18, 124167 ) as stock from dual;
It returns NULL, but if I run the second query separately with the same params, I get an amount back.
But not the right number because if I only run the second query's subquery, the row numbers aren't in order (1,2,3,6,7,4,5,8,9,10 instead of 1,2,3,..,10).
What am I doing wrong? Any help will be appreciated.
Feel free to ask if my description isn't clear.
I figured out a solution for my problem, but if anyone has a better one, please share it, because I don't think mine is the right one, although it does the job.
DROP function IF EXISTS `fn_inventory_stock_on_note`;
DELIMITER $$
CREATE DEFINER=`root`#`localhost` FUNCTION `fn_inventory_stock_on_note`( fIngredient int, fInventory int, fNote int, fItem int ) RETURNS float
DETERMINISTIC
BEGIN
DECLARE tStock float;
DECLARE tNoteRow int;
DECLARE rStock float;
DECLARE rRow int;
SET #rRow := 0;
DROP TEMPORARY TABLE IF EXISTS stock_temp;
CREATE TEMPORARY TABLE stock_temp ( num int, BookID int, ItemID int, qty float );
INSERT INTO stock_temp ( SELECT #rRow := #rRow + 1 as num, q.*
FROM ( SELECT b.id as BookID, if( bi.id is not null, bi.id, bo.id ) as ItemID,
ifnull( if( bi.id is not null, bi.quantity, bo.quantity ), 0 ) * t.direction as qty
FROM fn_inventory_book b
LEFT JOIN fn_inventory_book_in bi ON b.id = bi.bookid
LEFT JOIN fn_inventory_book_out bo ON b.id = bo.bookid
LEFT JOIN fn_dict_transactions t ON b.transactionid = t.id
WHERE b.inventoryid = fInventory
AND ( bi.ingredientid = fIngredient OR bo.ingredientid = fIngredient )
ORDER BY b.date ASC, t.direction ASC ) as q );
SELECT num INTO tNoteRow
FROM stock_temp st
WHERE st.BookID = fNote
AND st.ItemID = fItem;
SELECT sum( st.qty ) INTO tStock
FROM stock_temp st
WHERE st.num <= tNoteRow;
RETURN tStock;
END$$
DELIMITER ;

MYSQL IN substitute

Good day
I am trying to query the names of employees who work on every project.
My code is as follows:
SELECT CONCAT (fname,' ', minit,'. ' , lname) AS NAME
FROM employee a, works_on b, project c
WHERE pno IN (Select pnumber //WHAT COULD I SUBSTITUTE W/ IN
FROM projet)
AND a.ssn = b.essn
AND b.pno = c.pnumber
The problem with IN is that it is that the values inside are like evaluated as 'OR'... what is the equivalent of IN that makes the value of my subquery evaluated like 'AND'
Thank you in advance.
EDIT:
As reqeusted..
SELECT *
FROM employee e
WHERE NOT EXISTS
(
SELECT NULL
FROM employee ei
CROSS JOIN
project p
LEFT JOIN
works_on wo
ON wo.pno = p.pnumber
AND wo.essn = ei.ssn
WHERE ei.ssn = e.ssn
)
select CONCAT (fname,' ', minit,'. ' , lname) AS NAME
from employee
left join works_on
on works_on.essn=employee.ssn
group by employee.ssn
having count(works_on.essn) = (select count(*) from project);
Simplified example:
create table emp_work_on
(
emp_name varchar(50),
work_on varchar(30)
);
create table works
(
work_on varchar(30)
);
insert into works(work_on) values('apple'),('microsoft'),('google'),('facebook')
insert into emp_work_on values
('john','apple'),('john','microsoft'),('john','google'),('john','facebook'),
('paul','microsoft'),('paul','google'),
('george','apple'),('george','microsoft'),('george','google'),('george','facebook'),
('ringo','apple'),('ringo','facebook');
select e.emp_name
from works w
left join emp_work_on e on e.work_on = w.work_on
group by e.emp_name
having count(e.work_on) = (select count(*) from works)
order by e.emp_name
Output:
emp_name
----------
george
john
(2 rows)
On your table structure, you could use this:
SELECT * FROM employee
WHERE ssn IN
(
SELECT w.essn
FROM project c
LEFT JOIN works_on w ON w.pno = c.pnumber
GROUP BY w.essn
HAVING COUNT(w.pno) = (SELECT COUNT(*) FROM project)
)
Hmm.. but I think this could be the simplest, granting there's no repeating pno on employee's works_on, i.e. there's no pno in works_on that doesn't exists on project, i.e. referential integrity is maintained
SELECT * FROM employee
WHERE ssn IN
(
SELECT essn
FROM works_on
GROUP BY essn
HAVING COUNT(pno) = (SELECT COUNT(*) FROM project)
)