1

I'm working on the multi-tenant application and each user has its database.
Assume we have more tenants and each tenant has schema (schema1, schema2, schema3,....)
and each schema has the same structure of tables.
Each schema has a customer table with the same structure(id, name, age,...).
I have a table called tenants in the shared schema (shared_schema) that has all schema names in a column called tenant_id.
So how can get all schema from tenants table and then get customer count for each schema
in single (query, procedure, view,... any workaround).

tenants table:-

tenant_id
schema1
schema2
...

schema1, schema2,....
customer table

id
1
2
..

Expected result

tenant_id customer counts
schema1 10
schema2 20
... ..

procedure workaround

DROP PROCEDURE IF EXISTS `tradeTypeStats`;

DELIMITER $$

CREATE PROCEDURE `tradeTypeStats`()
BEGIN
    declare scName varchar(250);
    declare q varchar(2000);

    DROP TABLE IF EXISTS ResultSet;
    create temporary table ResultSet (
     id bigint
    );

    DROP TABLE IF EXISTS MySchemaNames;
    create temporary table MySchemaNames (
        schemaName varchar(250)
    );

    insert into MySchemaNames(schemaName)
    SELECT distinct
        ms.tenant_id as SchemaName FROM shared_schema.tenants ms;

label1:
    LOOP
        set scName = (select schemaName from MySchemaNames limit 1);
        set @q = concat('select id from ', scName, '.customer');
        PREPARE stmt1 FROM @q;
        EXECUTE stmt1;
        DEALLOCATE PREPARE stmt1;

        delete from MySchemaNames where schemaName = scName;
        IF ((select count(*) from MySchemaNames) > 0) THEN
            ITERATE label1;
        END IF;
        LEAVE label1;

    END LOOP label1;

    SELECT * FROM ResultSet;

    DROP TABLE IF EXISTS MySchemaNames;
    DROP TABLE IF EXISTS ResultSet;
END
$$

DELIMITER ;

CALL tradeTypeStats();

But it gives me an error

Error
Static analysis:

1 errors were found during analysis.

Missing expression. (near "ON" at position 25)
SQL query: Copy Edit Edit

SET FOREIGN_KEY_CHECKS = ON;

MySQL said: Documentation

#2014 - Commands out of sync; you can't run this command now
Isaac Bennetch
  • 11,830
  • 2
  • 32
  • 43
java dev
  • 313
  • 1
  • 3
  • 12
  • 1
    You need to write dynamic SQL in a stored procedure, since schema and table names can't be dynamic in normal SQL. – Barmar Feb 01 '22 at 16:55
  • Can you help me with this procedure I will be pleased? – java dev Feb 01 '22 at 16:57
  • If you try to write it, I'll help you fix it if it doesn't work. – Barmar Feb 01 '22 at 16:57
  • https://stackoverflow.com/questions/2132654/querying-multiple-databases-at-once. I tried this procedure first procedure but always give me this error ```Commands out of sync; you can't run this command now``` – java dev Feb 01 '22 at 16:59
  • Then maybe you should ask the poster of the answer you tried to use. – Barmar Feb 01 '22 at 17:03
  • Question is very old. What the benefit of ResultSet table there? – java dev Feb 01 '22 at 17:05
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/241626/discussion-between-devloper152-and-barmar). – java dev Feb 01 '22 at 19:26

1 Answers1

1

I could not figure out what the point of the intermediate MySchemaNames table is. I would just use a cursor -

DELIMITER $$
CREATE PROCEDURE `tradeTypeStats`()
BEGIN
  DECLARE done BOOLEAN DEFAULT FALSE;
  DECLARE _schema_name VARCHAR(250);
  DECLARE _q VARCHAR(2000);

  DECLARE `cur` CURSOR FOR
    SELECT DISTINCT tenant_id AS SchemaName FROM shared_schema.tenants;

  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
  
  DROP TABLE IF EXISTS ResultSet;
  CREATE TEMPORARY TABLE ResultSet (
    tenant_id VARCHAR(250) NOT NULL,
    customer_counts INT NOT NULL
  );

  OPEN cur;

  read_loop: LOOP

    FETCH cur INTO _schema_name;
    IF done THEN
      LEAVE read_loop;
    END IF;
    
    SET @q = CONCAT('INSERT INTO ResultSet SELECT \'', _schema_name,'\', COUNT(*) FROM ', _schema_name, '.customer');
    PREPARE stmt1 FROM @q;
    EXECUTE stmt1;
    DEALLOCATE PREPARE stmt1;

  END LOOP;
  CLOSE cur;
  
  SELECT * FROM ResultSet;
  DROP TABLE ResultSet;

END$$
DELIMITER ;
user1191247
  • 10,808
  • 2
  • 22
  • 32
  • Can I put a row in cur (put multi-field) and If it is acceptable please how to access each field from cur like SchemaName or any other field – java dev Feb 02 '22 at 10:40
  • 1
    I assume you meant column, not row. You can add as many columns (expressions) as you want to the query in the cursor declaration but you must also add them to the `FETCH cur INTO ...` statement. So, if you change the original query to `SELECT DISTINCT tenant_id AS SchemaName, other_col FROM shared_schema.tenants;` you must add another variable to the fetch - `FETCH cur INTO _schema_name, _other_col;` You must also add the declaration for the new variable. [13.6.6.3 Cursor FETCH Statement](https://dev.mysql.com/doc/refman/5.7/en/fetch.html) – user1191247 Feb 02 '22 at 11:28
  • 1
    Exactly I meant column thanx again – java dev Feb 02 '22 at 11:44