Mysql replace field from another table's field [duplicate] - mysql

This question already has answers here:
Oracle Replace function
(3 answers)
Closed 9 years ago.
I need to replace the Table1's filed values from Table2's values while select query.
Eg:
Table1:
Org Permission
--------------------------------------
Company1 1,3,7
Company2 1,3,8
Table2:
Permission Permission
--------------------------------------
1 Read
3 Write
7 Execute
8 Delete
I need like this:
Org Permission
--------------------------------------
Company1 Read,Write,Execute
Company2 Read,Write,Delete

I have been following your post since it was tagged in Oracle :D
In oracle it was looking in much possible ways, But in mysql you have to follow it with the help of procedure:
Schema:
create table table1 (org varchar(50), permission_id varchar(50));
create table table2 (permission_id int, permission_name varchar(50));
insert into table1 values ('Company1','1,3,7'),('Company2','1,3,8');
insert into table2 values (1,'Read'),(3,'Write'),(7,'Execute'),(8,'Delete');
Procedure:
DELIMITER $$
DROP PROCEDURE IF EXISTS `Update_Table_data`$$
CREATE PROCEDURE `Update_Table_data`()
BEGIN
declare max_row int;
declare p1 int;
Set p1 = 0;
SET max_row = (SELECT max(#i:=#i+1) AS row_num FROM table2 AS t,(SELECT #i:=0) AS foo);
label1: LOOP
set p1 = p1 + 1;
IF p1 <= max_row THEN
UPDATE Table1
SET permission_id =
replace(permission_id, (select permission_id from
(SELECT #i:=#i+1 AS row_num ,t.* FROM table2 AS t,(SELECT #i:=0) AS foo) a
where row_num = p1),
(select permission_name from
(SELECT #i:=#i+1 AS row_num ,t.* FROM table2 AS t,(SELECT #i:=0) AS foo) a
where row_num = p1));
Iterate label1;
END IF;
LEAVE label1;
END LOOP label1;
-- SET #x = p1;
END$$
DELIMITER ;
and then make a call to update your values :
call Update_Table_data;
Hope it helps :)

See SQLFiddle for initial data and this is resultant data SQLFiddle
UPDATE
organization
SET
permisson = (SELECT
GROUP_CONCAT(VALUE)
FROM
( SELECT
org,
SUBSTRING_INDEX(permisson,',',1) AS `permisson`
FROM
organization
UNION
SELECT
org,
SUBSTRING_INDEX(SUBSTRING_INDEX(permisson,',',2),',',-1) AS `permisson`
FROM
organization
UNION
SELECT
org,
SUBSTRING_INDEX(permisson,',',-1) AS `permisson`
FROM
organization
) AS t
JOIN
permission p
WHERE
p.p_id = t.permisson AND
t.org = organization.org
GROUP BY org
)

Try to replace your numbers using REPLACE.It work properly only when you are using single digit values for permission.
SQL = " SELECT Org, REPLACE(REPLACE(REPLACE(REPLACE(Permission,"1","Read'"),"3","Write'"),"7","Execute'"),"8","Delete'") as Permission FROM myTable "
REPLACE()

Related

Mysql On trigger each row

i need help for the below code. My problem is that i want only that code executes once per statement (after i search i checked that expression don't exists anymore only once per row).
So i tried to add:
IF NOT EXISTS
(Select count(*) FROM replay_replays_access WHERE id_game = new.id_game GROUP BY id_game HAVING count(*) <5)
THEN
But didn't work either what can i do, its duplicating sometime triplicating the information?
TRIGGER replay
AFTER UPDATE
ON table_replays FOR EACH ROW
begin
IF EXISTS
(SELECT
replay_games.room_name
FROM replay_games
WHERE replay_games.room_name = 'Tournament Room' and replay_games.id = new.id_game)
THEN
IF NOT EXISTS
(Select
count(*)
FROM replay_replays_access
WHERE id_game = new.id_game
GROUP BY id_game
HAVING count(*) <5)
THEN
INSERT INTO replay_replays_access(id_game, id_player, replay_name, do_not_hide)
SELECT
new.id_game,
replay_users.id ,
CONCAT(
(SELECT game_types
FROM replay_games
WHERE id=new.id_game),
': ',
(SELECT
descr
FROM replay_games
WHERE id=new.id_game)) ,
0
FROM replay_users
WHERE
(replay_users.admin > 0 OR
replay_users.privlevel = 'TOURNAMENT MEMBER')
AND NOT replay_users.name = (
SELECT
replay_games.creator_name
FROM replay_games
WHERE replay_games.id = new.id_game);
END IF;
END IF;
END

Appending additional SQL tigger to existing trigger

I have the following SQL update trigger that works properly:
BEGIN
DECLARE myID INT;
SELECT user_id INTO myID FROM writer WHERE writer_id = NEW.writer_id;
IF (NEW.status_id = 2) THEN
INSERT INTO activity (
user_id,
work_id,
activity,
date_created
) VALUES (
myID,
NEW.work_id,
'confirmed',
now()
);
ELSE
INSERT INTO activity (
user_id,
work_id,
activity,
date_created
) VALUES (
myID,
NEW.work_id,
'modified',
now()
);
END IF;
END
I need to add an additional trigger as the following:
CREATE TRIGGER updateWorkStatus AFTER UPDATE ON writer_split
FOR EACH ROW
BEGIN
UPDATE work a
JOIN writer_split b
ON a.work_id = b.work_id AND a.current_version = b.version
SET a.status_id = 2
WHERE a.work_id NOT IN (
SELECT ab.work_id
FROM (SELECT s.work_id
FROM work w INNER JOIN writer_split s
ON w.work_id = s.work_id AND s.status_id != 2) ab
);
END;
when I run this create script, I am getting a syntax error. Any ideas?
For me i will use UPDATE work as a

SQL IDENTITY column based on another column

Is there a way to define an identity column on another column? What I want to accomplish is a table that holds positions of an order and these orders can be put there anytime. So it could be that there are already lets say three positions in the table and it would look somewhat like this:
OrderNumber | OrderPosition
10001 1
10001 2
10001 3
And now I want to add another position without calculating the right value for the OrderPosition column. This is because I want to write new positions for multiple orders into the table and would like to avoid cursoring over the individual orders. I would prefer a solution wher OrderPosition is an identity column that is reseeded based on the OrderNumber column. So that If i add an order position for a new order it would start with 1 and if I add another position for order 10001 it would continue with 4.
Write a Scalar Function that returns the MAX(OrderPosition) based on OrderNumber. Then reference that function in the insert statement of orders
your requirement will not work for identity column.
You need to create custom logic to get from the normal columns and on combination based new no will generate.. like (read comments, only choose one logic)
declare #t table(OrderNumber int, OrderPosition int)
insert into #t values (10001, 1),(10001, 2),(10001, 3),(10001, 4)
select * from #t
--now insert new record with old orderno
declare #seq int = 1
declare #ordernumberNew int = 10001
--Eigher you can use :- insert to more understand
if( exists(select orderposition from #t where OrderNumber = #ordernumberNew ))
begin
set #seq = (select max(OrderPosition) + 1 from #t where OrderNumber = #ordernumberNew )
end
insert into #t values (#ordernumberNew , #seq )
select * from #t
--or another twist of above statement, insert directly as
insert into #t
values
(
#ordernumberNew,
case when exists (select orderposition from #t where OrderNumber = #ordernumberNew )
then (select max(OrderPosition) + 1 from #t where OrderNumber = #ordernumberNew )
else 1 end
)
select * from #t
--Now enter the not exist order no
set #ordernumberNew = 10006
insert into #t
values
(
#ordernumberNew,
case when exists (select orderposition from #t where OrderNumber = #ordernumberNew )
then (select max(OrderPosition) + 1 from #t where OrderNumber = #ordernumberNew )
else 1 end
)
select * from #t

Insert query based on number of rows

I want a query to insert a row into a table I know it is simple but the scenario is the table should not have more than 5 rows. If table has more than five rows I need to remove the old row(Or replace with new row ) (Based on the insert time stamp) then i need to insert a new row.If number of rows less than count 5 then i can directly insert a row.
Please share me the query.
How about something like this.
declare #count int
SELECT #count=COUNT(*)
from EP_ANSWERS
IF (#count<5)
// DO your insert here
ELSE
DELETE FROM TABLE
WHERE inserttimestamp = (SELECT x.inserttimestamp
FROM (SELECT MAX(t.inserttimestamp) AS inserttimestamp
FROM TABLE t) x)
// DO your insert here
If it is impossible for the table to have more than 5 rows:
DELETE FROM yourtable
WHERE 5 <= (SELECT COUNT(*) FROM yourtable)
AND yourtimestamp = (SELECT MIN(yourtimestamp) FROM yourtable)
;
INSERT INTO yourtable ...
;
If it is possible for the table to have more than 5 rows:
DELETE FROM yourtable
WHERE 5 <= (SELECT COUNT(*) FROM yourtable)
AND yourtimestamp NOT IN (SELECT yourtimestamp
FROM yourtable
ORDER BY yourtimestamp DESC
LIMIT 4)
;
INSERT INTO yourtable ...
;
It sounds like you want to put a trigger on the table to maintain this rule, in MySQL the something like this should work
CREATE TRIGGER trg__my_table__limit_rows
BEFORE INSERT
ON my_table
FOR EACH ROW
BEGIN
IF ((SELECT COUNT(1) FROM my_table) = 5)
BEGIN
DELETE FROM my_table
WHERE id = (SELECT MIN(id) FROM my_table) -- change this to fit your logic for which record should be removed
END
END
Some of the code here is in pseudo (you didn't wrote your schema), but i wrote where you need to complete your own code.
DECLARE #NumberOfRowsToInsert INT = -- select from the data you want to insert
DECLARE #MaxNumberOfRows INT = 5
DECLARE #NumberOfExistingRows INT
DECLARE #Query VARCHAR(MAX) = 'SELECT TOP #rows id FROM SomeTable ORDER BY createdDate ASC'
SELECT #NumberOfExistingRows = COUNT(*)
FROM SomeTable
SET #Query = REPLACE(#Query,'#rows',
CAST(#NumberOfRowsToInsert - (#MaxNumberOfRows - #NumberOfExistingRows))) AS VARCHAR(1))
CREATE TABLE #IdsToDelete(id INT PRIMARY KEY)
INSERT INTO #IdsToDelete
EXEC(#Query)
DELETE FROM SomeTable
WHERE id IN (SELECT * FROM #IdsToDelete)
-- insert here..

MySQL - Insert multiple rows based on column value

I have the query working, just wondering if there is a better way to do this without cursors/loops/php side. I've been a DBA for 5+ years and just came across the := statement. Very cool.
Table (tblPeople) with the person ID and the number of tickets they bought.
PersonId NumTickets
1 3
2 1
3 1
I then want to assign individual tickets to each person in a new table (tblTickets), depending on how many tickets they bought. The TicketId is a key, auto increment column.
TicketId PersonId
100 1
101 1
102 1
103 2
104 3
Here is the code. It loops through the whole tblPeople over and over again incrementing a new calculated column called rowID. Then I filter out the rows based on the number of tickets they bought in the WHERE clause. The problem I see is the subquery is huge, the more people I have, the bigger the subquery gets. Just not sure if there is a better way to write this.
INSERT INTO tblTickets (PersonId)
SELECT PersonId
FROM (
SELECT s.PersonId, s.NumTickets,
#rowID := IF(#lastPersonId = s.PersonId and #lastNumTickets = s.NumTickets, #rowID + 1, 0) AS rowID,
#lastPersonId := s.PersonId,
#lastNumTickets := s.NumTickets
FROM tblPeople m,
(SELECT #rowID := 0, #lastPersonId := 0, #lastNumTickets := 0) t
INNER JOIN tblPeople s
) tbl
WHERE rowID < NumTickets
I'd add a utility table Numbers which contains all the numbers from 1 up to the maximal number of tickets a person may buy. Then you can do something like this:
INSERT INTO tblTickets (PersonId)
SELECT s.PersonId
FROM tblPeople s, Numbers n
WHERE n.number <= s.NumTickets
Following Stored procedure will serve your purpose...
DELIMITER $$
USE <your database name> $$
DROP PROCEDURE IF EXISTS `update_ticket_value2`$$
CREATE PROCEDURE `update_ticket_value2`()
BEGIN
DECLARE index_value INT;
DECLARE loop_variable INT;
SET #KeyValue = 100;
SET #LastPersonID = 0;
SET #TicketNum = 0;
SET #PersonIDToHandle = 0;
SELECT #PersonIDToHandle = PersonID, #TicketNum = NumTickets
FROM tblPeople
WHERE PersonId > #LastPersonID
ORDER BY PersonId
LIMIT 0,1;
WHILE #PersonIDToHandle IS NOT NULL
DO
SET loop_variable = 0;
WHILE(loop_variable < #TicketNum) DO
INSERT INTO tblTickets(TicketId, PersonId) VALUES(#KeyValue + loop_variable, #PersonIDToHandle);
SET loop_variable = loop_variable + 1;
END WHILE;
SET #LastPersonID = #PersonIDToHandle;
SET #PersonIDToHandle = NULL;
SET #KeyValue = #KeyValue + #TicketNum;
SELECT #PersonIDToHandle := PersonID, #TicketNum := NumTickets
FROM tblPeople
WHERE PersonId > #LastPersonID
ORDER BY PersonId
LIMIT 0,1;
END WHILE;
END$$
DELIMITER ;
Call the procedure as:
CALL update_ticket_value2();
Hope it helps...