Not too familiar with the coding inside events, but the goal is:
- Select the “company_id” field of table “companies”. (simple select id from table)
- Use the list of step 1 into a loop to fetch data from a custom table: eq: “
select fid from table_%id% where...
“ - Now create a record in another table from data together “
insert into resulttable (id, fid) values (%id, %fid)
Then create an event to do this every hour
I’d like to do this without creating a procedure, but might need to.
This is as close as I can get:
DECLARE cur_orgs CURSOR FOR SELECT orgId FROM organizations;
OPEN cur_orgs;
Reading_Orgs: LOOP
FETCH cur_orgs INTO _org_id;
DECLARE cur_fids CURSOR FOR SELECT fid FROM organization_+'_org_id';
OPEN cur_fids;
Reading_fids: LOOP
FETCH cur_fids INTO _fid_id;
insert into queue(orgId, fid) values (_org_id, _fid_id);
END LOOP;
CLOSE cur_fids;
insert into queue(orgId) values (_org_id);
END LOOP;
CLOSE cur_orgs;
Several comments:
-
MySQL does not use
+
for string concatenation; that’s a string concatenation operator only in Microsoft SQL Server and Microsoft Access, as far as I know. -
You can’t make a table name from an expression like
organization_+'_org_id'
anyway. Table names are identifiers, not strings. Identifiers must be fixed in the query at the time it is parsed. -
You wrote in a comment that your separate tables are there for a legal requirement, so I won’t give you grief over designing the database this way.
I tested the following with MySQL 8.2.0:
CREATE EVENT myevent
ON SCHEDULE AT current_timestamp + INTERVAL 1 MINUTE
DO
BEGIN
DECLARE org_id BIGINT UNSIGNED;
DECLARE cur_orgs CURSOR FOR SELECT orgId FROM organizations;
OPEN cur_orgs;
Reading_Orgs: LOOP
FETCH cur_orgs INTO org_id;
SET @org_id = org_id;
SET @sql = CONCAT(
'INSERT INTO queue(orgId, fid)
SELECT ?, fid FROM organization_', @org_id);
PREPARE stmt FROM @sql;
EXECUTE stmt USING @org_id;
DEALLOCATE PREPARE stmt;
INSERT INTO queue(orgId) VALUES (@org_id);
END LOOP;
CLOSE cur_orgs;
END
Things to notice:
-
I used
INSERT...SELECT
. This is because cursors in MySQL don’t support dynamic SQL. -
String concatenation of the query string is done with
CONCAT()
, not+
. -
PREPARE and EXECUTE only work with user variables (the type with the
@
sigil), but cursors only work to fetch into declared local variables, so I had to copyorg_id
to@org_id
. These are two different types of variables in MySQL. -
Be careful about the potential SQL injection risk. I assume the
org_id
variable has a numeric type, so there’s no way it can contain risky characters. Iforg_id
is a string instead of a number, then this code has an SQL injection vulnerability, because the value of an org id could cause the prepared statement to do something you don’t intend.
The result:
mysql> show tables;
+------------------+
| Tables_in_test |
+------------------+
| organization_123 |
| organization_456 |
| organizations |
| queue |
+------------------+
mysql> select * from organizations;
+-------+
| orgId |
+-------+
| 123 |
| 456 |
+-------+
mysql> select * from organization_123;
+------+
| fid |
+------+
| 123 |
+------+
mysql> select * from organization_456;
+------+
| fid |
+------+
| 456 |
+------+
… I wait a minute for the event to execute …
mysql> select * from queue;
+-------+------+
| orgId | fid |
+-------+------+
| 123 | 123 |
| 123 | NULL |
| 456 | 456 |
| 456 | NULL |
+-------+------+
I don’t know what your purpose is of inserting rows in the queue table in this fashion, but I’ll trust you that it makes sense for your application. This answer is only meant to show the syntax for your looping routine, not the wisdom of designing your database as it is.
To be honest, I find MySQL stored routines so awkward to use, that I would recommend coding your events in some client language outside the database. It would be easier to develop and debug in practically any other language other than the MySQL stored routine language.
Coding inside events is similar to coding inside stored procedures. But there are no procedure parameters. It’s all documented on the web site.
Do you have a specific question about this? If you show what you tried we’ll help you fix it, we won’t write it for you.
The fact that you need to access table names dynamically suggests a poor schema design. Dynamic information should be in table contents, not table and column names. You shouldn’t have a different table for each company.
If you really have to do it this way, you need to use dynamic SQL using
PREPARE
andEXECUTE
.Like @Barmar said, change your data model. Your current model creates many problems, this is just one of those. Read about 3NF and give it a try
Show 1 more comment