🇯🇵 日本語 | 🇺🇸 English | 🇪🇸 Español | 🇵🇹 Português | 🇹🇭 ไทย | 🇨🇳 中文

【SQL BETWEEN子句】掌握范围查询!巧妙指定数值和日期范围的方法

在网站和应用程序开发中,我们经常需要提取某个范围内的数据,比如“价格在1000元以上、5000元以下的商品”或“6月1日至6月30日期间注册的用户”。

WHERE子句中写这样的条件时,你会怎么做?

WHERE price >= 1000 AND price <= 5000

像这样,使用比较运算符(>=, <=)和AND当然可以指定范围。但是,SQL提供了一个专门的命令,能让这种“范围查询”写得更直观、更简洁。它就是我们今天的主角——`BETWEEN`子句

本文将通过大量可即拷即用的代码,从BETWEEN子句的基本用法,到在日期范围中的应用,再到其否定形式NOT BETWEEN,进行全面而详尽的解说。让我们告别冗长的比较运算符写法,掌握编写出谁都能看懂的、更智能的SQL的技能吧!


准备工作:创建用于搜索的订单数据

要尝试范围查询,首先需要有可供查询的数据。这次,我们将创建一个模拟电商网站订单历史的orders表。包含各种价格和订单日期的数据,可以让我们更容易地体会到BETWEEN子句的效果。

-- 如果orders表已存在,则删除(以便重复测试)
DROP TABLE IF EXISTS orders;

-- 创建一个新的orders表
CREATE TABLE orders (
  id INTEGER PRIMARY KEY,
  product_name TEXT NOT NULL,
  price INTEGER NOT NULL,
  order_date DATE NOT NULL,
  quantity INTEGER NOT NULL
);

-- 插入初始数据
INSERT INTO orders (id, product_name, price, order_date, quantity) VALUES
(1, '神奇圆珠笔', 200, '2025-06-05', 3),
(2, '魔法笔记本', 500, '2025-06-10', 5),
(3, '终极电饭煲', 30000, '2025-06-15', 1),
(4, '奇迹苹果', 980, '2025-06-20', 10),
(5, 'USB-C集线器', 4500, '2025-06-25', 2),
(6, '传统毛笔', 12000, '2025-06-30', 1),
(7, '高级巧克力', 3500, '2025-07-01', 4);

这样,用于各种范围数据提取的准备工作就完成了。


【基础】使用`BETWEEN`子句指定数值范围

`BETWEEN`子句的基本语法非常清晰明了。

WHERE 列名 BETWEEN 最小值 AND 最大值;

这里最重要的点是,`BETWEEN`子句的范围包含指定的最小值和最大值本身(即大于等于和小于等于)。也就是说,WHERE price BETWEEN 1000 AND 5000WHERE price >= 1000 AND price <= 5000的含义完全相同。请务必牢记“包含两端”这一点。

场景:“查找所有价格在1,000元到5,000元之间的商品。”

SELECT * FROM orders
WHERE price BETWEEN 1000 AND 5000;

执行结果:

id | product_name  | price | order_date | quantity
---|---------------|-------|------------|----------
5  | USB-C集线器   | 4500  | 2025-06-25 | 2
7  | 高级巧克力    | 3500  | 2025-07-01 | 4

相比使用两个比较运算符,代码更简洁,并且“1,000元到5,000元的范围”这个意图也传达得更直接,不是吗?


【应用】使用`BETWEEN`子句指定日期范围

`BETWEEN`子句的便利之处在于,它不仅能用于数值,也能用于指定日期(DATE类型)和日期时间(DATETIME类型)的范围。在Web应用中,提取特定时间段数据的需求非常多,因此这是一个常用技巧。

场景:“查找所有在2025年6月期间产生的订单。”

在这种情况下,我们将范围的开始指定为“2025-06-01”,结束指定为“2025-06-30”。

SELECT * FROM orders
WHERE order_date BETWEEN '2025-06-01' AND '2025-06-30';

执行结果:

id | product_name  | price | order_date | quantity
---|---------------|-------|------------|----------
1  | 神奇圆珠笔    | 200   | 2025-06-05 | 3
2  | 魔法笔记本    | 500   | 2025-06-10 | 5
3  | 终极电饭煲    | 30000 | 2025-06-15 | 1
4  | 奇迹苹果      | 980   | 2025-06-20 | 10
5  | USB-C集线器   | 4500  | 2025-06-25 | 2
6  | 传统毛笔      | 12000 | 2025-06-30 | 1

如你所见,6月1日和6月30日的订单也ちゃんと结果に含まれています。これも「両端を含む」という`BETWEEN`句の性質のおかげです。


【反向条件】使用`NOT BETWEEN`子句指定范围之外的数据

如果你想查找`BETWEEN`的反向条件,即“位于指定范围**之外**的数据”,可以使用NOT BETWEEN子句。

这里有一个注意事项。price BETWEEN 1000 AND 5000的含义是“大于等于1000且小于等于5000”,而price NOT BETWEEN 1000 AND 5000的含义则是“**小于**1000或**大于**5000”(即price < 1000 OR price > 5000)。也就是说,范围的两端值不包含在结果中。

场景:“查找所有价格非常便宜(低于1,000元)或非常昂贵(高于5,000元)的商品。”

SELECT * FROM orders
WHERE price NOT BETWEEN 1000 AND 5000;

执行结果:

id | product_name  | price | order_date | quantity
---|---------------|-------|------------|----------
1  | 神奇圆珠笔    | 200   | 2025-06-05 | 3
2  | 魔法笔记本    | 500   | 2025-06-10 | 5
3  | 终极电饭煲    | 30000 | 2025-06-15 | 1
4  | 奇迹苹果      | 980   | 2025-06-20 | 10
6  | 传统毛笔      | 12000 | 2025-06-30 | 1

虽然我们的示例数据中没有价格正好是1,000元或5,000元的商品,但请记住,即使有,它们也不会包含在这个结果中。


【体验环节】在浏览器中运行SQL,掌握范围查询!

现在,是时候把知识变成技能了!将下面的HTML代码完整复制,保存为sql_between_test.html之类的文件名,然后在浏览器中打开它。你专属的SQL执行环境将会启动,并且本文中使用的orders表已经为你准备好了。

试着改变数值或日期的范围,来掌握BETWEEN子句“包含两端”的感觉。也试试NOT BETWEEN,看看结果会如何变化吧!

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>SQL BETWEEN子句 在线执行环境</title>
  <style>
    body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; line-height: 1.7; color: #333; max-width: 800px; margin: 2rem auto; padding: 0 1rem; }
    h1 { color: #16a085; }
    textarea { width: 100%; height: 180px; font-family: "SF Mono", "Consolas", monospace; font-size: 16px; padding: 12px; border: 1px solid #ccc; border-radius: 6px; box-sizing: border-box; margin-bottom: 1rem; }
    button { background-color: #1abc9c; color: white; border: none; padding: 12px 22px; font-size: 16px; border-radius: 6px; cursor: pointer; transition: background-color 0.2s; }
    button:hover { background-color: #16a085; }
    button:disabled { background-color: #bdc3c7; cursor: not-allowed; }
    #result-container { margin-top: 2rem; border: 1px solid #ddd; padding: 1rem; border-radius: 6px; background: #fdfdfd; min-height: 50px; }
    #error-message { color: #e74c3c; font-weight: bold; }
    table { border-collapse: collapse; width: 100%; margin-top: 1rem; }
    th, td { border: 1px solid #ddd; padding: 10px; text-align: left; }
    th { background-color: #f2f2f2; }
    tr:nth-child(even) { background-color: #f9f9f9; }
  </style>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.3/sql-wasm.js"></script>
</head>
<body>

  <h1>来试试SQL吧!</h1>
  <p>在下方的文本框中输入SQL语句,然后点击“执行”按钮。试试不同的范围吧!</p>

  <textarea id="sql-input">-- 查找6月10日到6月25日之间下单的商品
SELECT * FROM orders
WHERE order_date BETWEEN '2025-06-10' AND '2025-06-25';
  </textarea>
  
  <button id="execute-btn">执行</button>
  
  <div id="result-container">
    <p id="error-message"></p>
    <div id="result-output"></div>
  </div>

  <script>
    const sqlInput = document.getElementById('sql-input');
    const executeBtn = document.getElementById('execute-btn');
    const errorMsg = document.getElementById('error-message');
    const resultOutput = document.getElementById('result-output');

    let db;

    async function initDb() {
      executeBtn.disabled = true;
      executeBtn.textContent = '数据库准备中...';
      try {
        const SQL = await initSqlJs({
          locateFile: file => `https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.3/${file}`
        });
        db = new SQL.Database();
        
        const setupSql = `
          DROP TABLE IF EXISTS orders;
          CREATE TABLE orders (id INTEGER PRIMARY KEY, product_name TEXT NOT NULL, price INTEGER NOT NULL, order_date DATE NOT NULL, quantity INTEGER NOT NULL);
          INSERT INTO orders (id, product_name, price, order_date, quantity) VALUES
          (1, '神奇圆珠笔', 200, '2025-06-05', 3),
          (2, '魔法笔记本', 500, '2025-06-10', 5),
          (3, '终极电饭煲', 30000, '2025-06-15', 1),
          (4, '奇迹苹果', 980, '2025-06-20', 10),
          (5, 'USB-C集线器', 4500, '2025-06-25', 2),
          (6, '传统毛笔', 12000, '2025-06-30', 1),
          (7, '高级巧克力', 3500, '2025-07-01', 4);
        `;
        db.run(setupSql);
        
        executeBtn.disabled = false;
        executeBtn.textContent = '执行';
        resultOutput.innerHTML = '<p>准备就绪!请随意尝试你自己的SQL查询。</p>';

      } catch (err) {
        errorMsg.textContent = '数据库初始化失败:' + err.message;
        console.error(err);
      }
    }

    function executeSql() {
      if (!db) return;
      
      const sql = sqlInput.value;
      errorMsg.textContent = '';
      resultOutput.innerHTML = '';

      try {
        const results = db.exec(sql);
        if (results.length === 0) {
          resultOutput.innerHTML = '<p>查询成功执行,但没有返回结果集。</p>';
          return;
        }
        
        results.forEach(result => {
          const table = document.createElement('table');
          const thead = document.createElement('thead');
          const tbody = document.createElement('tbody');
          
          const headerRow = document.createElement('tr');
          result.columns.forEach(colName => {
            const th = document.createElement('th');
            th.textContent = colName;
            headerRow.appendChild(th);
          });
          thead.appendChild(headerRow);
          
          result.values.forEach(row => {
            const bodyRow = document.createElement('tr');
            row.forEach(cellValue => {
              const td = document.createElement('td');
              td.textContent = cellValue === null ? 'NULL' : cellValue;
              bodyRow.appendChild(td);
            });
            tbody.appendChild(bodyRow);
          });
          
          table.appendChild(thead);
          table.appendChild(tbody);
          resultOutput.appendChild(table);
        });

      } catch (err) {
        errorMsg.textContent = 'SQL错误:' + err.message;
        console.error(err);
      }
    }

    executeBtn.addEventListener('click', executeSql);
    
    initDb();
  </script>
</body>
</html>

注意事项:日期时间处理与值的顺序

BETWEEN子句虽然简洁强大,但也有几点需要注意。


总结

这次,我们学习了能够直观地进行数值和日期范围查询的BETWEEN子句。

熟练运用BETWEEN子句,你写的SQL将变得更简洁、意图更清晰。从简单的比较运算符组合中更进一步,将更精炼的数据提取技巧加入你的工具箱吧!