In mySQL stored procedure how can I assign a Query String to a variable, so I can reuse it? In my example I will be using SELECT id FROM audit many times.
CREATE PROCEDURE my_proc()
BEGIN
UPDATE person SET status='Active' WHERE id = (SELECT id FROM audit);
SELECT COUNT(*) FROM (SELECT id FROM audit);
//Multile scenarios the `SELECT id FROM audit` will be used.
END
Something like:
CREATE PROCEDURE my_proc()
BEGIN
myVariable = SELECT id FROM audit;
UPDATE person SET status='Active' WHERE id = (myVariable;
SELECT COUNT(*) FROM (myVariable);
//Multile scenarios the `SELECT id FROM audit` will be used.
END
Is this what you are looking for? Sorry I am not sure what you need.
SELECT #myCount:= count(id) FROM audit;
select #myCount;
Based on your reply, do you need a temporary table to store the ids from the audit and re-use those on the queries?
create temporary table tbl_tmp_audit;
select id from audit;
I am assuming you need this so that you won't join the whole audit columns every time on your succeeding queries.
--first query
UPDATE person AS p
INNER JOIN tbl_tmp_audit t ON p.id = t.id
SET status = 'Active';
--second query
SELECT COUNT(*) FROM tbl_tmp_audit;
Drop temporary table tbl_temp_bookings;
Related
Definitely a basic question, but I couldn't find an example.
I'm writing a procedure which merges two rows into the good row. It moves all child rows' ids to being the correct one, replaces all NULL values with available values in the row being removed before finally deleting the 'bad' row.
What I have so far is this:
CREATE DEFINER=`danielv`#`%`
PROCEDURE `emp_merge`(IN `#core_emp_id` int, IN `#bad_emp_id` int)
BEGIN
UPDATE claim SET employee_id = #core_emp_id
WHERE employee_id = #bad_emp_id;
WITH bad_employee_values AS (
SELECT * FROM employee WHERE employee_id = #bad_emp_id
)
UPDATE employee SET
employee.employment_date = COALESCE(employee.employment_date, bad_employee_values.employment_date),
WHERE employee_id = #core_emp_id;
DELETE FROM employee WHERE employee_id = #bad_emp_id;
END
However, I'm getting non-descript error messages and I'm not sure why. I suspect there's an issue with how I'm handling my CTE and coalesce function, but I'm not sure where the gap in my understanding is.
In this statement :
WITH bad_employee_values AS (SELECT * FROM employee WHERE employee_id = #bad_emp_id)
UPDATE employee SET
employee.employment_date = COALESCE(employee.employment_date, bad_employee_values.employment_date),
WHERE employee_id = #core_emp_id;
You are defining CTE bad_employee_values but you are not using it in the UPDATE part of the query, hence you cannot access its columns : for MySQL, bad_employee_values.employment_date is unknown.
It looks like you could simply avoid a CTE here. You could just self-join the table, like so :
UPDATE employee e_core
INNER JOIN employee e_bad ON e_bad.employee_id = #bad_emp_id
SET e_core.employment_date = e_bad.employment_date,
WHERE employee_id = #core_emp_id AND e_core.employment_date IS NULL
This query will simply select the record identified by #core_emp_id, join it with the corresponding "bad" record, and copy the value of employment_date. The second condition in the WHERE clause prevents records whose employment_date is not null from being selected.
I'm trying to retrieve a single record from my database, BUT I don't know which table name to query until I query another record.
If I knew the table name and ID the end query would look something like this.
SELECT * FROM `materials_sheet_stock` WHERE `id` = 2
But since I do NOT know the table name or the ID in that table I'm trying to break it up a bit.
This query will successfully retrieve the table name for the above query
SELECT tb1.*
FROM (SELECT `tag_table`
FROM `materials_group_tags_mapping`
WHERE `tag_id` IN
(SELECT `materials_group_tags`.`id`
FROM `materials_group_tags`
WHERE `materials_group_tags`.`name` = "frameless_base_side_material_unexposed")) AS tb1
which in this case is materials_sheet_stock
This query will successfully retrieve the ID that I need for the above query
(SELECT `materials_group_tags_mapping`.`tag_value`
FROM `materials_group_tags_mapping`
WHERE `materials_group_tags_mapping`.`tag_id` IN
(SELECT `materials_group_tags`.`id`
FROM `materials_group_tags`
WHERE `materials_group_tags`.`name` = "frameless_base_side_material_unexposed"))
But now when I put them all together in 1 query using IN it keeps throwing errors about not finding columns, or that all tables need an alias. I've tried editing the following code for like an hour with no luck. Hopefully you guys can spot the error. Here's the final code that I am using.
SELECT tb2.*
FROM (SELECT `tag_table`
FROM `materials_group_tags_mapping`
WHERE `tag_id` IN
(SELECT `materials_group_tags`.`id`
FROM `materials_group_tags`
WHERE `materials_group_tags`.`name` = "frameless_base_side_material_unexposed") ) as tb2
WHERE tb2.`id` IN
(SELECT `materials_group_tags_mapping`.`tag_value`
FROM `materials_group_tags_mapping`
WHERE `materials_group_tags_mapping`.`tag_id` IN
(SELECT `materials_group_tags`.`id`
FROM `materials_group_tags`
WHERE `materials_group_tags`.`name` = "frameless_base_side_material_unexposed"))
I have a few tables with exact same schema, the only reason its separate is because they are huge.
So if i do a
select * from
(select * from ptable p1
union select * from ptable2 p2
.. and so on) pp
where pid=1234
, it will take really long time.
I like to write a one where i check ptable(s) for pid value of 1234, if it exist, then select the row from the right table.
How do i do that? pid is unique and will only exist in one table, it is also not in any sorted order.
I manage to solve my problem after some experiment, not sure if its the best way being an amateur but it works.
CREATE PROCEDURE 'sproc'(IN pQryID INT)
BEGIN
select count(*) as count into #rowCountp1 from p1 where pid=pQryID;
select count(*) as count into #rowCountp2 from p2 where pid=pQryID;
.. and so on for other similar tables ..
if #rowCountp1>0 THEN
(SELECT * from p1 where pid=pQryID);
elseif #rowCountp2>0 THEN
(SELECT ( from p2 where pid=pQryID);
end if;
END
I have a table that stores users. Every user has an ID, a Name and an Access Level. The three possible Access Levels are Administrator, Manager and Simple User.
What I want is to conditionally select from this table based on the Access Level value. I demonstrate the logic bellow:
If user is Administrator, then select all users (Administrators, Managers, Simple Users)
Else if user is Manager select all Managers and all Simple Users
Else if user is Simple User select only himself
Is that possible?
Providing Access Level is an integer that increases with the actual access level:
Administrator = 3
Manager = 2
User = 1
Then
SELECT * FROM USERS
WHERE ACCESS_LEVEL <= (SELECT ACCESS_LEVEL FROM USERS WHERE ID = #ID)
And just switch the less than sign to greater than if it is opposite.
Applies to SQL-server
EDIT: To get what you want you can use something like this:
SELECT id,name FROM users where ID = #id
UNION DISTINCT
SELECT id, name from users where access_level <=
(select case when access_level = 1 then 0 else access_level end
from users where id = #id)
With a query like this you will select all users at your current access_level or lower.
Only exception if your access_level is 1 (e.g. normal user), then only your own user is selected.
In Oracle the concept is known as Row Level Security. See articles such as this or this to get you started.
You can use following code
If(access_level=='administrator'){ str query = 'select * from users';}else if(access_level=='manager'){ str query = 'select * from users where access_level!="administrator"'; }else{ str query = 'select * from users where access_level="users"'; }
Might be a little overkill, but the following stored procedure can be used to achieve what you want:
DROP procedure IF EXISTS `listAccessibleUsers`;
DELIMITER $$
CREATE PROCEDURE `listAccessibleUsers`(IN user_id INT)
BEGIN
DECLARE u_access_level INT;
-- Select the user access level
SELECT access_level
FROM users
WHERE users.id = user_id
INTO u_access_level;
-- Result for simple users
IF u_access_level = 1 THEN
SELECT id, name, access_level
FROM users
WHERE users.id = user_id;
-- Result for admistrators and managers
ELSE
SELECT id, name, access_level
FROM users
WHERE access_level <= u_access_level;
END IF;
END$$
DELIMITER ;
Example calling code:
CALL listAccessibleUsers(200);
I tried:
UPDATE giveaways SET winner = '1' WHERE ID = (SELECT MAX(ID) FROM giveaways)
But it gives:
#1093 - You can't specify target table 'giveaways' for update in FROM clause
This article seems relevant but I can't adapt it to my query. How can I get it to work?
Based on the information in the article you linked to this should work:
update giveaways set winner='1'
where Id = (select Id from (select max(Id) as id from giveaways) as t)
This is because your update could be cyclical... what if updating that record causes something to happen which made the WHERE condition FALSE? You know that isn't the case, but the engine doesn't. There also could be opposing locks on the table in the operation.
I would think you could do it like this (untested):
UPDATE
giveaways
SET
winner = '1'
ORDER BY
id DESC
LIMIT 1
Read more
update giveaways set winner=1
where Id = (select*from (select max(Id)from giveaways)as t)
create table GIVEAWAYS_NEW as(select*from giveaways);
update giveaways set winner=1
where Id=(select max(Id)from GIVEAWAYS_NEW);
Make use of TEMP TABLE:
as follows:
UPDATE TABLE_NAME SET TABLE_NAME.IsActive=TRUE
WHERE TABLE_NAME.Id IN (
SELECT Id
FROM TEMPDATA
);
CREATE TEMPORARY TABLE TEMPDATA
SELECT MAX(TABLE_NAME.Id) as Id
FROM TABLE_NAME
GROUP BY TABLE_NAME.IncidentId;
SELECT * FROM TEMPDATA;
DROP TABLE TEMPDATA;
You can create a view of the subquery first and update/delete selecting from the view instead..
Just remember to drop the view after.