MariaDB 根据列值连接来自不同数据库的表

Posted

技术标签:

【中文标题】MariaDB 根据列值连接来自不同数据库的表【英文标题】:MariaDB JOIN tables from different databases based on column value 【发布时间】:2018-01-02 13:55:29 【问题描述】:

我如何使用列值作为数据库名称JOIN这两个不同数据库中的两个表?

我已经使用静态定义的(第二个)数据库名称成功地连接了两个数据库之间的两个表:

SELECT * 
FROM db1.table_a AS ta
INNER JOIN db2.table_b AS tb on (ta.db_table_name = b.user_id) 

但是,db2.table_b 在该查询中的位置我需要以某种方式让db2 成为第一个数据库中第一个表的值; 表名 将被静态定义。所有这类相关的线程都完全没用,而且非常复杂。


详细信息:有一个通用数据库,所有其他数据库都代表相同的应用程序,但用于不同的帐户。为了使所有不同帐户上的所有用户能够相互交互(例如 database_2.accounts.user.43 (DB->Table->Column->ID (43)),公共数据库(@ 987654326@以上)不仅要存储用户的id,还要存储必须加入的数据库的名称。

为了帮助可视化事物:

数据库:通用 数据库:db2
SELECT id, database_name 
FROM common.table_a AS ct 
INNER JOIN [database_name].table_b AS dn ON (ct.user_id = [database_name].users.id)

返回的数据看起来应该是这样的:

+----------+------------+----------+
| database | account_id | username |
+----------+------------+----------+
| db1      | 1          | John     |
+----------+------------+----------+
| db2      | 1          | Sally    |
+----------+------------+----------+
| db3      | 43         | John     |
+----------+------------+----------+
| db4      | 1          | Sally    |
+----------+------------+----------+

那么 html 输出应该是这样的:

来自 db1 的 John 的评论。 来自 db2 的 Sally 的评论。 来自 db3 的 John 的评论。 来自 db4 的 Sally 的评论。

我可以担心在视觉上确保 db1 中的 John 和 db3 中的 John(以及 db2 中的 Sally 和 db4 中的 Sally)这四个人在现实生活中都是不同的人。重要的是根据包含要用于 JOIN 的数据库名称的列值的值来选择它们的动态方面。

【问题讨论】:

我没有完全理解,但这听起来你需要为此使用一些动态 SQL。 @TimBiegeleisen 每个数据库都有自己的应用程序,尽管有时所有这些数据库及其各自的用户都使用一个通用应用程序。为了显示他们是谁,需要加入的数据库的名称存储在公共(本例中为db1)数据库中,因此系统将知道每行将JOIN 的第二个数据库。 所以 db1.table_a 包含一列,指示哪个 db table_b 存在。通过这种设计,解决方案将是“复杂的”。也许你可以用一些样本数据来澄清一下。 @P.Salmon 更新。 创建一个视图。详情见这里:***.com/questions/10694601/… 【参考方案1】:

您有数百个数据库吗?那将是一个“糟糕”的设计。为了进一步讨论,请解释为什么你有这么多。

如果你没有很多数据库,但你需要动态选择哪个数据库,同样,糟糕的设计;让我们进一步讨论。

如果您必须执行其中一项操作,请将其隐藏在存储例程中(正如 P.Salmon 几乎建议的那样;他的代码需要一些润色)或应用程序库(php、Java 等)。

否则,无论您可以说table_a,您都可以将其替换为db1.table_a。事实上,您可以看到 mysql 这样做:EXPLAIN EXTENDED SELECT ...; SHOW WARNINGS; 示例:

mysql> EXPLAIN EXTENDED SELECT province FROM canada; SHOW WARNINGS;
+----+-------------+--------+-------+---------------+----------+---------+------+------+----------+-------------+
| id | select_type | table  | type  | possible_keys | key      | key_len | ref  | rows | filtered | Extra       |
+----+-------------+--------+-------+---------------+----------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | canada | index | NULL          | province | 105     | NULL | 5484 |   100.00 | Using index |
+----+-------------+--------+-------+---------------+----------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.01 sec)

+-------+------+---------------------------------------------------------------------------------------+
| Level | Code | Message                                                                               |
+-------+------+---------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select `world`.`canada`.`province` AS `province` from `world`.`canada` |
+-------+------+---------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

在此示例中,表 canada 已替换为 world.canada,因为 world 是数据库。

【讨论】:

【参考方案2】:

所有事情都是平等的(我敢打赌他们不是)并且假设所有的模式/数据库都在同一台服务器上,您应该能够构造一个简单的动态 sql 语句。

给定

+----+------+
| id | name |
+----+------+
|  1 | aaa  |
|  2 | bbb  |
+----+------+
2 rows in set (0.00 sec)

如果 name 用作 db name 的代理,我们可以首先选择所有不同的名称并创建一个 sql 语句,将所有 dbs 中的所有表联合起来。像这样。

SET @SQL =
( 
SELECT  GROUP_CONCAT(GCSTRING)
FROM
(
SELECT 'A' AS GC,CONCAT('SELECT ID,NAME FROM USERS U1 ',JSTRING,' ',DBNAME,' AS  ',NAMEALIAS,'  ON ',NAMEPREFIX,'.',USTRING) GCSTRING
FROM
(
SELECT DISTINCT 'JOIN ' AS JSTRING,NAME DBNAME , 
        NAME AS NAMEALIAS, NAME AS NAMEPREFIX, 'TABLEB.USER_ID = UI.NAME UNION' USTRING 
FROM USERS
) S
) T
GROUP BY GC
)
;

SET @SQL = REPLACE(@SQL,',',' ');
SET @SQL = SUBSTRING(@SQL,1,LENGTH(@SQL) - 5);
SET @SQL = CONCAT(@SQL,';');
SELECT @SQL

+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| @SQL                                                                                                                                                                    |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| SELECT ID NAME FROM USERS U1 JOIN  aaa AS  aaa  ON aaa.TABLEB.USER_ID = UI.NAME UNION SELECT ID NAME FROM USERS U1 JOIN  bbb AS  bbb  ON bbb.TABLEB.USER_ID = UI.NAME ; |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

【讨论】:

哇,好的,用我现在剩下的时间复习一下。如果我今天不明白这一点,我明天会第一件事。 我无法找到诸如SET @SQL 之类的文档(即使在添加了 -mssql 和其他搜索标志之后),并且在您的示例中列名和表名都是大写的。请问有没有机会对上面代码中发生的事情有所了解?我从来没有做过这样的事情。我是使用一个还是多个 PHP MySQLi mysqli_query 命令? 对不起,约翰,问题中没有提到 php,也没有这样标记。我根本没有 php,所以我无法帮助你,答案是纯 mysql/mariadb,我认为 php 的主体是相同的。 所有数据库都位于来自同一个 MariaDB 服务的同一台服务器上,并且它们都使用相同的一切。您不需要了解 PHP;我在这方面的问题是,这个巨大的代码块中的所有内容是单个 SQL 查询还是多个 SQL 查询?如果是多个查询,那么我猜分号是分隔符?如果有多个查询,那么这是仅在连接期间保持活动状态还是像用户定义的函数一样持续存在? @P.Salmon - 我认为你需要做准备+执行+释放,而不仅仅是SELECT @sql

以上是关于MariaDB 根据列值连接来自不同数据库的表的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 4:连接来自不同数据库的表

如何内部连接来自不同数据上下文的表? [复制]

SQLite - 你如何连接来自不同数据库的表?

连接来自两个不同数据库的表

SQL 查询连接来自不同 fdb 数据库的表

oracle数据库:表连接