Skip to content

MySQL - BOOLEAN

在逻辑和编程中,布尔值(Boolean)代表一个真值。它只能是两种可能之一:真(true)或假(false)。这对于控制应用程序流程、过滤数据和表示二进制状态至关重要。

例如,在电商数据库中,你可能需要筛选当前有库存的商品。一个像 is_available 这样的布尔列将非常适合此用途。

/* 虚构产品表示例 */
-- product_name | is_available
----------------|--------------
-- 'Laptop' | true
-- 'Mouse' | false
-- 'Keyboard' | true

在这里,is_available 是一个布尔列,它清晰地指示了库存状态,允许进行简单高效的查询。

需要理解的关键一点是,MySQL 没有原生的内置 BOOLEAN 数据类型。当你将一个列声明为 BOOLEAN 或其同义词 BOOL 时,MySQL 内部会将其映射到 TINYINT(1)。

MySQL 将整数 0 视为 FALSE,将任何非零整数视为 TRUE。为方便起见,MySQL 提供了关键字 TRUE 和 FALSE 作为 1 和 0 的别名。

注意:关键字 TRUE 和 FALSE 不区分大小写。true、True 和 TRUE 都被视为 1。

在创建表时,你可以使用 BOOLEAN 关键字,以提高清晰度并符合标准 SQL 规范。

CREATE TABLE user_settings (
user_id INT AUTO_INCREMENT PRIMARY KEY,
email_notifications BOOLEAN DEFAULT TRUE,
is_premium_member BOOL NOT NULL
);

让我们创建该表,然后使用 DESCRIBE 语句检查其结构。

DESCRIBE user_settings;

如你所见,email_notifications 和 is_premium_member 列,虽然定义为 BOOLEAN 和 BOOL,但都被创建为 tinyint(1)。

FieldTypeNullKeyDefaultExtra
user_idintNOPRINULLauto_increment
email_notificationstinyint(1)YES1
is_premium_membertinyint(1)NO

现在,让我们使用 TRUE 和 FALSE 关键字向 user_settings 表中插入数据。

INSERT INTO user_settings (user_id, email_notifications, is_premium_member)
VALUES
(1, FALSE, TRUE),
(2, TRUE, FALSE),
(3, DEFAULT, FALSE); -- email_notifications 使用默认值 'TRUE'

当我们检索数据时,将看到存储的整数值。

SELECT * FROM user_settings;

结果显示 TRUE 对应 1,FALSE 对应 0。

user_idemail_notificationsis_premium_member
101
210
310

你可以在 WHERE 子句中使用布尔条件进行过滤。

-- 查找所有高级会员
SELECT user_id, is_premium_member FROM user_settings WHERE is_premium_member IS TRUE;
  • 使用 BOOLEAN 或 BOOL: 始终使用 BOOLEAN 或 BOOL 关键字来定义表示真值的列。即使底层类型是 TINYINT(1),这样做也能使模式的意图清晰明了。
  • 使用 IS TRUE / IS FALSE: 过滤时,优先使用 WHERE my_column IS TRUE 或 WHERE my_column IS FALSE,而不是 WHERE my_column = 1 或 WHERE my_column = 0。这种语法更具可读性,并明确处理布尔逻辑。它还能正确处理涉及 NULL 的情况。
  • 处理 NULL: 布尔列可以是 NULL,这表示一种“未知”或“不适用”的状态,与 TRUE 或 FALSE 不同。如果你允许 NULL 值,请确保你的应用程序逻辑正确处理这第三种状态。
  • 应用程序层逻辑: 决定是在数据库中还是在应用程序代码中处理 0/1 到 true/false 的转换。大多数现代应用程序在应用程序层处理此转换,使数据库查询专注于数据检索。

在查询中显示 ‘TRUE’ 和 ‘FALSE’

Section titled “在查询中显示 ‘TRUE’ 和 ‘FALSE’”

虽然应用程序代码通常处理显示逻辑,但你可以在 SQL 查询中使用 CASE 语句,直接从数据库返回布尔值更具可读性的字符串表示。

SELECT
column,
CASE
WHEN boolean_column = 1 THEN 'Yes, Premium'
WHEN boolean_column = 0 THEN 'No, Standard'
ELSE 'Unknown'
END AS member_status
FROM your_table;

让我们将此应用于 user_settings 表,以创建一个描述性的状态。

SELECT
user_id,
CASE is_premium_member
WHEN 1 THEN 'TRUE'
WHEN 0 THEN 'FALSE'
END AS 'Premium Status'
FROM user_settings;
user_idPremium Status
1TRUE
2FALSE
3FALSE
  • 错误: WHERE is_premium_member = 'TRUE'。原因: TRUE 是一个表示 1 的关键字,而不是字符串。不要将其用引号括起来。修正: 使用 WHERE is_premium_member IS TRUE 或 WHERE is_premium_member = TRUE。
  • 混淆: 查询 WHERE non_boolean_column,其中 non_boolean_column 是一个整数。原因: MySQL 的布尔求值(0 为假,非零为真)适用于所有地方,而不仅仅是 TINYINT(1) 列。像 SELECT * FROM products WHERE stock_quantity; 这样的查询将返回所有 stock_quantity 不为 0 的产品。为了避免混淆,请明确表达:SELECT * FROM products WHERE stock_quantity > 0;。

在应用程序代码中处理布尔数据

Section titled “在应用程序代码中处理布尔数据”

大多数现代数据库驱动和 ORM 会自动处理数据库的 0/1 表示与编程语言的本地布尔类型(true/false)之间的转换。以下是一些安全、现代的示例。

Node.js (async/await)
Python (mysql-connector)
Java (JDBC)
PHP (PDO)
此示例使用流行的 `mysql2/promise` 库,结合 async/await 编写清晰、非阻塞的代码。它使用预处理语句来防止 SQL 注入。
```javascript
// main.js
import mysql from 'mysql2/promise';
async function main() {
let connection;
try {
connection = await mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'your_database'
});
// Insert data using prepared statements (使用预处理语句插入数据)
const insertQuery = 'INSERT INTO user_settings (email_notifications, is_premium_member) VALUES (?, ?)';
await connection.execute(insertQuery, [true, false]);
console.log('New user setting inserted successfully.'); // 新的用户设置插入成功。
// Fetch and process boolean data (获取并处理布尔数据)
const [rows] = await connection.execute('SELECT user_id, is_premium_member FROM user_settings WHERE is_premium_member = ?', [false]);
console.log('Standard members:'); // 标准会员:
rows.forEach(row => {
// The driver converts 0/1 to false/true automatically (驱动程序会自动将 0/1 转换为 false/true)
console.log(`User ID: ${row.user_id}, Is Premium: ${row.is_premium_member}`); // 用户ID:${row.user_id},是否高级:${row.is_premium_member}
});
} catch (error) {
console.error('Database operation failed:', error); // 数据库操作失败:
} finally {
if (connection) await connection.end();
}
}
main();

此 Python 示例使用 mysql-connector-python 和参数化查询来确保安全性。with 语句确保资源得到正确管理。

main.py
import mysql.connector
from mysql.connector import errorcode
config = {
'user': 'root',
'password': 'password',
'host': '127.0.0.1',
'database': 'your_database'
}
try:
with mysql.connector.connect(**config) as cnx:
with cnx.cursor(dictionary=True) as cursor:
# Insert data using parameter substitution (protects against SQL injection) (使用参数替换插入数据(防止 SQL 注入))
add_setting = ("INSERT INTO user_settings "
"(email_notifications, is_premium_member) VALUES (%s, %s)")
data_setting = (True, True) # Booleans are handled correctly (布尔值处理正确)
cursor.execute(add_setting, data_setting)
cnx.commit()
print(f"Inserted new setting for user ID: {cursor.lastrowid}") # 为用户 ID 插入新设置:{cursor.lastrowid}
# Fetch and process data (获取并处理数据)
query = "SELECT user_id, is_premium_member FROM user_settings WHERE is_premium_member = %s"
cursor.execute(query, (True,))
print("\nPremium members:") # 高级会员:
for row in cursor:
// The connector returns 1/0, which Python evaluates as True/False (连接器返回 1/0,Python 会将其评估为 True/False)
print(f"User ID: {row['user_id']}, Is Premium: {bool(row['is_premium_member'])}") # 用户ID:{row['user_id']},是否高级:{bool(row['is_premium_member'])}
except mysql.connector.Error as err:
print(f"Something went wrong: {err}") # 出现错误:{err}

此现代 Java 示例使用 try-with-resources 进行自动资源管理,并使用 PreparedStatement 确保安全和类型安全。

Main.java
import java.sql.*;
public class MysqlBooleanExample {
private static final String URL = "jdbc:mysql://localhost:3306/your_database";
private static final String USER = "root";
private static final String PASSWORD = "password";
public static void main(String[] args) {
String sql = "SELECT user_id, email_notifications FROM user_settings WHERE is_premium_member = ?";
try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
PreparedStatement pstmt = conn.prepareStatement(sql)) {
// Set boolean parameter (设置布尔参数)
pstmt.setBoolean(1, true);
try (ResultSet rs = pstmt.executeQuery()) {
System.out.println("Users who are premium members:"); // 高级会员用户:
while (rs.next()) {
int id = rs.getInt("user_id");
// Retrieve as a boolean directly (直接检索为布尔值)
boolean hasNotifications = rs.getBoolean("email_notifications");
System.out.printf("User ID: %d, Has Email Notifications: %b\n", id, hasNotifications); // 用户ID:%d,已启用邮件通知:%b
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}

此 PHP 示例使用 PDO (PHP Data Objects),这是与数据库交互的现代推荐方式。它支持预处理语句并为不同的数据库系统提供一致的接口。

config.php
<?php
$host = '127.0.0.1';
$db = 'your_database';
$user = 'root';
$pass = 'password';
$charset = 'utf8mb4';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
try {
$pdo = new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
// main.php
require 'config.php';
// Fetch premium members using a prepared statement (使用预处理语句获取高级会员)
$is_premium = true;
$stmt = $pdo->prepare('SELECT user_id, email_notifications FROM user_settings WHERE is_premium_member = ?');
$stmt->execute([$is_premium]);
$users = $stmt->fetchAll();
echo "Premium members:\n"; // 高级会员:
foreach ($users as $user) {
// PDO can fetch boolean values correctly (PDO 可以正确获取布尔值)
$notifications_enabled = (bool)$user['email_notifications'];
echo sprintf(
"User ID: %d, Notifications Enabled: %s\n", // 用户ID:%d,已启用通知:%s
$user['user_id'],
$notifications_enabled ? 'Yes' : 'No'
);
}
?>