我有名为 company_abc
、company_xyz
等的数据库。这些 company_*
数据库具有相同的结构,并且包含用户
表。
我需要做的是聚合来自 company_*
数据库的所有用户数据,并将此 View 复制到另一台服务器。 View 就像这样
COMPANY NAME | USERNAME
abc | user@email.com
abc | user1@email.com
xyz | user2@email.com
company3 | user3@email.com
MySQL 中可能有类似的事情吗?
数据库和用户都是动态创建的,因此我无法仅使用一组静态数据库创建 View 。
最佳答案
正如你所说,你想创建具有动态数据库名称的 View - 所以你想要实现的结果在当前版本的 mysql 中是不可能的。
因此您有以下选项示例:
选项 1
如果您想获取所有数据库用户表的结果,您可以定义一个使用预准备语句的存储过程。此过程需要参数 db_prefix,在您的情况下是 company_%。基本上,当数据库名称类似于 db_prefix 参数值时,此过程会从 information_schema 中选择所有名为 users 的表。之后,它循环遍历结果并创建查询字符串作为所有用户表的联合并执行此查询。创建查询字符串时,我还添加了名为“源”的字段,这样我就可以识别该结果来自哪个数据库。在我的示例中,我的数据库均采用默认排序规则 utf8_unicode_ci。
在这种情况下,您可以定义过程示例“getAllUsers”
-- Dumping structure for procedure company_abc1.getAllUsers
DELIMITER //
CREATE DEFINER=`root`@`localhost` PROCEDURE `getAllUsers`(IN `db_prefix` TEXT)
DETERMINISTIC
COMMENT 'test'
BEGIN
DECLARE qStr TEXT DEFAULT '';
DECLARE cursor_VAL VARCHAR(255) DEFAULT '';
DECLARE done INTEGER DEFAULT 0;
DECLARE cursor_i CURSOR FOR SELECT DISTINCT (table_schema) FROM information_schema.tables WHERE table_name = 'users' AND table_schema LIKE db_prefix COLLATE utf8_unicode_ci;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cursor_i;
read_loop: LOOP
FETCH cursor_i INTO cursor_VAL;
IF done = 1 THEN
LEAVE read_loop;
END IF;
IF qStr != '' THEN
SET qStr = CONCAT(qStr, ' UNION ALL ');
END IF;
SET qStr = CONCAT(qStr, ' SELECT *, \'', cursor_VAL ,'\' as source FROM ', cursor_VAL, '.users');
END LOOP;
CLOSE cursor_i;
SET @qStr = qStr;
PREPARE stmt FROM @qStr;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @qStr = NULL;
END//
DELIMITER ;
现在您可以获得所有用户的结果:
CALL getAllUsers('company_%');
在我的示例数据库中,结果为:
id name source
1 User 1 company_abc1
2 User 2 company_abc1
3 User 3 company_abc1
1 User 1 company_abc2
2 User 2 company_abc2
3 User 3 company_abc2
1 User 1 company_abc3
2 User 2 company_abc3
3 User 3 company_abc3
1 User 1 company_abc4
2 User 2 company_abc4
3 User 3 company_abc4
1 User 1 company_abc5
2 User 2 company_abc5
3 User 3 company_abc5
选项 2
如果您真的非常需要 View ,那么您可以修改第一个过程,而不是执行选择,您可以创建 View 。像这样的例子:
-- Dumping structure for procedure company_abc1.createAllUsersView
DELIMITER //
CREATE DEFINER=`root`@`localhost` PROCEDURE `createAllUsersView`(IN `db_prefix` TEXT)
DETERMINISTIC
COMMENT 'test'
BEGIN
DECLARE qStr TEXT DEFAULT '';
DECLARE cursor_VAL VARCHAR(255) DEFAULT '';
DECLARE done INTEGER DEFAULT 0;
DECLARE cursor_i CURSOR FOR SELECT DISTINCT (table_schema) FROM information_schema.tables WHERE table_name = 'users' AND table_schema LIKE db_prefix COLLATE utf8_unicode_ci;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cursor_i;
read_loop: LOOP
FETCH cursor_i INTO cursor_VAL;
IF done = 1 THEN
LEAVE read_loop;
END IF;
IF qStr != '' THEN
SET qStr = CONCAT(qStr, ' UNION ALL ');
END IF;
SET qStr = CONCAT(qStr, ' SELECT *, \'', cursor_VAL ,'\' as source FROM ', cursor_VAL, '.users');
END LOOP;
CLOSE cursor_i;
SET @qStr = CONCAT('CREATE OR REPLACE VIEW allUsersView AS ', qStr);
PREPARE stmt FROM @qStr;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @qStr = NULL;
END//
DELIMITER ;
在此存储过程中,我们创建/替换名为 allUsersView 的 View ,因此基本上每次执行此过程时,它都会更新 View 。 在我的测试用例中,它创建如下 View :
CREATE OR REPLACE VIEW `allusersview` AS
SELECT *, 'company_abc1' as source FROM company_abc1.users
UNION ALL SELECT *, 'company_abc2' as source FROM company_abc2.users
UNION ALL SELECT *, 'company_abc3' as source FROM company_abc3.users
UNION ALL SELECT *, 'company_abc4' as source FROM company_abc4.users
UNION ALL SELECT *, 'company_abc5' as source FROM company_abc5.users ;
现在您可以使用 View 了。
SELECT * FROM allusersview
结果与第一个选项相同。
所有测试均在:
Mysql 5.6.16
关于MySQL 在所有带前缀的数据库表中创建 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28676723/