我有名为company_abc
,company_xyz
等的数据库。这些company_*
数据库具有相同的结构,并且包含users
表。
我需要做的是从仅company_*
数据库聚合所有用户数据,并将此视图复制到另一台服务器。视图就像是
COMPANY NAME | USERNAME
abc | user@email.com
abc | user1@email.com
xyz | user2@email.com
company3 | user3@email.com
在MySQL中是否可以这样?
动态创建数据库以及用户,因此我无法仅使用静态数据库集创建视图。
答案 0 :(得分:1)
要查找数据库名称列表:
SELECT SCHEMA_NAME
FROM information_schema.`SCHEMATA`
WHERE SCHEMA_NAME LIKE 'company%';
如果您可以编写类似PHP的代码,其余的很简单 - 从每个数据库构建一个UNION of SELECTs。但是,如果你必须在SQL中做到这一点......
要构建UNION,请编写存储过程。它将在CURSOR中执行上述查询。在遍历游标的循环内部,CONCAT()将构造的SELECT构建到您正在构建的UNION上。
循环结束后,PREPARE并执行构造的UNION。这将提供类似你的输出示例。
但是,如果您现在需要将其结果插入到另一台服务器中,则应该保留存储过程的范围并使用其他语言。
好的,好的,如果你必须保留在SQL中,那么你需要一些设置:创建一个" Federated"连接到其他服务器的表。现在,在您的SP中,在UNION前面连接INSERT INTO fed_tbl
。然后执行应该完成整个任务。
如果您在使用FEDERATED引擎时遇到问题,则可能需要切换到MariaDB中的FederatedX。
"详细信息留给读者练习。"
答案 1 :(得分:1)
正如您所说,您希望使用动态数据库名称创建视图 - 因此在当前版本的mysql中无法实现您想要实现的结果。
所以你有以下例子:
选项1
如果要获取所有数据库用户表的结果,可以定义使用预准备语句的存储过程。此过程需要参数db_prefix,在您的情况下 company _%。基本上,当数据库名称类似于db_prefix参数值时,此过程从 information_schema 中选择名为用户的所有表。之后,它循环遍历结果并创建查询字符串作为union all users表并执行此查询。在创建查询字符串时,我还添加了一个名为source的字段,因此我可以从哪个数据库中识别此结果。在我的示例中,我的数据库都是默认排序规则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
如果你确实需要查看,那么你可以修改第一个程序而不是执行选择你可以创建视图。像这样的例子:
-- 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 的视图,所以基本上每次执行此过程时它都会更新视图。 在我的测试用例中,它创建了这样的视图:
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
答案 2 :(得分:0)
我已将此标记为Mysql union from multiple database tables
的副本(SELECT *, 'abc' as COMPANY_NAME from company_abc.users)
union
(SELECT *, 'xyz' as COMPANY_NAME from company_xyz.users)
union
(SELECT *, 'company3' as COMPANY_NAME from company_company3.users)
...
答案 3 :(得分:0)
我认为唯一的方法是编写一个从information_schema.table读取所有数据库和表名的存储过程,使用union select * from company_abc.users union all select * from company_xyz
构建一个字符串,然后使用prepared statement执行命令:{ {3}}