Node.js - MySQL Join



在本章中,您将学习如何在 Node.js 应用程序中对 MySQL 数据库中的表实现 JOIN 查询。关系数据库由多个相关表组成,这些表使用公共列(称为外键列)链接在一起。MySQL支持JOIN查询,通过该查询,可以在Node.js应用程序中从多个表中提取和使用数据。与前面的示例一样,我们应该调用 mysql.query() 方法,并将 SQL 查询字符串传递给 mysql.query() 方法,该字符串应表示 MySQL JOIN 查询语法。

在本章中,我们将使用以下表格:

Members 表格


CREATE TABLE members (
	 	member_id INT AUTO_INCREMENT,
	 	name VARCHAR(100),
	 	PRIMARY KEY (member_id)
);

INSERT INTO members(name)
VALUES('John'),('Jane'),('Mary'),('David'),('Amelia');

成员表中的数据 -


mysql> select * from members;
+-----------+--------+
| member_id | name 	 |
+-----------+--------+
| 	 	  1 | John 	 |
| 	 	  2 | Jane 	 |
| 	 	  3 | Mary 	 |
| 	 	  4 | David  |
| 	 	  5 | Amelia |
+-----------+--------+

委员会表格


CREATE TABLE committees (
	 	committee_id INT AUTO_INCREMENT,
	 	name VARCHAR(100),
	 	PRIMARY KEY (committee_id)
);
INSERT INTO committees(name)
VALUES('John'),('Mary'),('Amelia'),('Joe');

委员会表中的数据 -


mysql> select * from committees;
+--------------+--------+
| committee_id | name 	|
+--------------+--------+
| 	 	 	 1 | John 	|
| 	 	 	 2 | Mary   |
| 	 	 	 3 | Amelia |
| 	 	 	 4 | Joe    |
+--------------+--------+

有些成员是委员会成员,有些则不是。另一方面,有些委员会成员在成员表中,有些则不在。

MySQL 内部联接

在SELECT语句中使用内部join子句的语法如下 -


SELECT column_list
FROM table_1
INNER JOIN table_2 ON join_condition;

Members

内部联接子句将第一个表中的每一行与第二个表中的每一行进行比较。如果两行的值都满足联接条件,则在 resuleset 中创建一个新行,其列包含两个表中两行的所有列,并将此新行包含在结果集中。换言之,内部联接子句仅包含两个表中的匹配行。

如果联接条件使用相等运算符 (=),并且两个表中的匹配列名相同,则可以使用 USING 子句而不是 ON 子句。


SELECT column_list
FROM table_1
INNER JOIN table_2 USING (column_name);

在下面的Node.js代码中,我们将使用 members 和 committees 表并获取它们的 Inner Join。


var mysql = require('mysql');
var con = mysql.createConnection({
	 	host: "localhost",
	 	user: "root",
	 	password: "mypassword",
	 	database: "mydb"
});

var qry =`
SELECT	
	 	m.member_id,	
	 	m.name AS member,	
	 	c.committee_id,	
	 	c.name AS committee
FROM
	 	members m
INNER JOIN committees c ON c.name = m.name;
`;
con.connect(function (err) {
	 	if (err) throw err;
	 	console.log("Connected!");
	 	con.query(qry, function (err, results) {
	 	 	 if (err) throw err;
	 	 	 results.forEach((row) => {
	 	 	 	 	console.log(JSON.stringify(row));
	 	 	 });
	 	});

	 	con.end();
});

输出

{"member_id":1,"member":"John","committee_id":1,"committee":"John"}
{"member_id":3,"member":"Mary","committee_id":2,"committee":"Mary"}
{"member_id":5,"member":"Amelia","committee_id":3,"committee":"Amelia"}

MySQL LEFT JOIN

左联接类似于内部联接。使用左联接两个表时,左联接将从左联接开始选择数据。对于左表中的每一行,左联接将与右表中的每一行进行比较。如果两行中的值满足联接条件,则左联接子句将创建一个新行,其列包含两个表中行的所有列,并将此行包含在结果集中。

如果两行中的值不匹配,则左联接子句仍会创建一个新行,其列包含左表中该行的列,而右表中该行的列为 NULL。

MySQL Left Join

因此,左联接从左表中选择所有数据,无论右表中是否存在匹配的行。

如果未找到右侧表中的匹配行,则左侧联接将对结果集中右侧表中的行的列使用 NULL。

左连接子句的语法如下:


SELECT column_list	
FROM table_1	
LEFT JOIN table_2 USING (column_name);

让我们将代码中的查询字符串更改为以下语句 Node.js -


var qry =`
SELECT	
	 	m.member_id,	
	 	m.name AS member,	
	 	c.committee_id,	
	 	c.name AS committee
FROM
	 	members m
LEFT JOIN committees c USING(name);
`;

输出

{"member_id":1,"member":"John","committee_id":1,"committee":"John"}
{"member_id":2,"member":"Jane","committee_id":null,"committee":null}
{"member_id":3,"member":"Mary","committee_id":2,"committee":"Mary"}
{"member_id":4,"member":"David","committee_id":null,"committee":null}
{"member_id":5,"member":"Amelia","committee_id":3,"committee":"Amelia"}

不匹配的列填充了 NULL 数据。

若要查找不是委员会成员的成员,请添加 WHERE 子句和 IS NULL 运算符。


SELECT	
	 	m.member_id,	
	 	m.name AS member,	
	 	c.committee_id,	
	 	c.name AS committee
FROM
	 	members m
LEFT JOIN committees c USING(name)
WHERE c.committee_id IS NULL;

MySQL正确连接

右联接子句与左联接子句类似,不同之处在于左表和右表的处理方式相反。右联接开始从右表中选择数据,而不是从左表中选择数据。

Right Join

右联接子句从右表中选择所有行,并匹配左表中的行。如果右表中的一行没有左表中的匹配行,则左表的列将在最终结果集中具有 NULL。


SELECT column_list	
FROM table_1	
RIGHT JOIN table_2 USING (column_name);

让我们修改查询字符串变量,如下所示:


var qry =`
SELECT	
	 	m.member_id,	
	 	m.name AS member,	
	 	c.committee_id,	
	 	c.name AS committee
FROM
	 	members m
RIGHT JOIN committees c on c.name = m.name;
`;

结果返回两个表的 RIGHT JOIN -

{"member_id":1,"member":"John","committee_id":1,"committee":"John"}
{"member_id":3,"member":"Mary","committee_id":2,"committee":"Mary"}
{"member_id":5,"member":"Amelia","committee_id":3,"committee":"Amelia"}
{"member_id":null,"member":null,"committee_id":4,"committee":"Joe"}