* **【核心概念】:** `STRICT` 表是一种特殊的表，它会像传统 SQL 数据库（如 PostgreSQL）一样，严格强制执行列的数据类型，任何不匹配的类型插入都会直接导致错误。

* **【生活类比】:** 如果说普通表是“社区的公共冰箱”，你可以往里面放各种食物（饮料、水果、剩菜），只要能放进去就行。那么 `STRICT` 表就是一个“专业化学实验室的药品柜”，每个抽屉都贴着精确的标签，比如“盐酸”、“蒸馏水”。你胆敢把一瓶“可乐”放进“盐酸”的抽屉里，警报立刻就会响起！

* **【SQL/Shell实战】:**
  让我们来创建一个药品柜，并看看试图放错东西时会发生什么。

  ```sql
  -- 创建一个名为 "reagent_cabinet" 的 STRICT 表
  CREATE TABLE reagent_cabinet (
      id      INTEGER PRIMARY KEY, -- 在 STRICT 表中，INTEGER 代表严格的整数
      name    TEXT,                -- 严格的文本
      ph_value REAL,               -- 严格的浮点数
      formula BLOB,                -- 严格的二进制数据
      notes   ANY                  -- 特殊的“任意”类型，这是个例外
  ) STRICT; -- 别忘了最后这个关键词！

  -- 尝试一次成功的插入
  INSERT INTO reagent_cabinet (id, name, ph_value, formula)
  VALUES (1, 'Hydrochloric Acid', 0.1, X'48436C'); -- HCL的二进制表示

  -- 尝试一次失败的插入（将文本'low'插入到需要数字的ph_value列）
  INSERT INTO reagent_cabinet (id, name, ph_value)
  VALUES (2, 'Sodium Hydroxide', 'high');
  -- 这里会直接报错！
  -- Error: STRICT table reagent_cabinet may not hold a TEXT value in column ph_value
  ```

* **【原理解析】:** SQLite 的设计者们意识到，虽然类型亲和性在很多场景下非常方便，但在需要强数据一致性和完整性的应用中，它可能成为隐患。`STRICT` 模式的诞生，就是为了给开发者一个选择权：你可以选择动态语言般的灵活性，也可以选择静态语言般的严谨性。这使得 SQLite 能够胜任更多对数据规范有严格要求的场景，比如金融计算、科学数据记录等。

-----

### **STRICT 表中的数据类型指南**

在 `STRICT` 表中，你不能再随意使用 `VARCHAR`、`DECIMAL` 等模糊的类型声明了，必须使用以下五种精确的类型之一：

### 1\. `INTEGER` (或 `INT`)

* **【核心概念】:** 值**必须**是一个完整的整数，不能是浮点数或无法转换为整数的文本。
* **【SQL/Shell实战】:**
  ```sql
  -- 成功: 存入一个纯整数
  INSERT INTO reagent_cabinet (id, name) VALUES (3, 'Pure Water');

  -- 失败: 尝试存入一个浮点数
  INSERT INTO reagent_cabinet (id, name) VALUES (7.0, 'Almost Pure Water');
  -- Error: STRICT table reagent_cabinet may not hold a REAL value in column id

  -- 失败: 尝试存入一个看起来像整数的文本
  INSERT INTO reagent_cabinet (id, name) VALUES ('4', 'Salty Water');
  -- Error: STRICT table reagent_cabinet may not hold a TEXT value in column id
  ```
* **【关键要点/避坑指南】:**
    * `STRICT` 表中的 `INTEGER` 不会自动转换类型。`'123'` 是文本，`123.0` 是浮点数，它们都不能被存入 `INTEGER` 列。
    * `PRIMARY KEY` 列在 `STRICT` 表中隐式地要求为 `INTEGER` 类型（除非你显式声明为别的类型）。

### 2\. `REAL`

* **【核心概念】:** 值必须是数字，可以是整数或浮点数。
* **【SQL/Shell实战】:**
  ```sql
  -- 成功: 存入浮点数
  UPDATE reagent_cabinet SET ph_value = 7.0 WHERE id = 3;
  -- 成功: 存入整数 (它会被存储为REAL类型)
  INSERT INTO reagent_cabinet (id, name, ph_value) VALUES (4, 'Buffer Solution', 7);

  -- 查询实际存储类型
  SELECT id, ph_value, typeof(ph_value) FROM reagent_cabinet WHERE id = 4;
  -- 输出: 4|7.0|real

  -- 失败: 尝试存入非数字文本
  INSERT INTO reagent_cabinet (id, name, ph_value) VALUES (5, 'Unknown Liquid', 'around 7');
  -- Error: STRICT table reagent_cabinet may not hold a TEXT value in column ph_value
  ```
* **【关键要点/避坑指南】:**
    * `REAL` 列是唯一可以同时接受整数和浮点数值的数字类型。当你存入一个整数时，它会被自动提升并存储为 `REAL`（例如，`7` 存为 `7.0`）。

### 3\. `TEXT`

* **【核心概念】:** 值必须是文本字符串。
* **【SQL/Shell实战】:**
  ```sql
  -- 成功
  UPDATE reagent_cabinet SET name = 'Distilled Water' WHERE id = 3;

  -- 失败: 尝试存入一个数字 (即使它能被表示为文本)
  INSERT INTO reagent_cabinet (id, name) VALUES (6, 123);
  -- Error: STRICT table reagent_cabinet may not hold an INTEGER value in column name
  ```
* **【关键要点/避坑指南】:**
    * 规则非常简单：必须是文本。如果你想存数字 `123`，你必须以文本的形式提供它，即 `'123'`。

### 4\. `BLOB`

* **【核心概念】:** 值必须是二进制数据。
* **【SQL/Shell实战】:**
  ```sql
  -- 成功
  UPDATE reagent_cabinet SET formula = X'48324F' WHERE id = 3; -- H2O的二进制表示

  -- 失败: 尝试存入一个文本字符串
  INSERT INTO reagent_cabinet (id, name, formula) VALUES (8, 'Ethanol', 'C2H5OH');
  -- Error: STRICT table reagent_cabinet may not hold a TEXT value in column formula
  ```
* **【关键要点/避坑指南】:**
    * 和 `TEXT` 一样，规则简单明了。只能通过 `X'...'` 语法或绑定的二进制参数存入。

### 5\. `ANY`

* **【核心概念】:** `ANY` 类型是 `STRICT` 表中的一个“后门”，被标记为 `ANY` 的列会退回到我们之前学习的“类型亲和性”模式。

* **【生活类比】:** 在我们那个纪律森严的化学药品柜里，`ANY` 类型的列就像一个贴着“杂物”标签的抽屉。在这个抽屉里，你可以放任何东西：实验笔记（TEXT）、备用电池（INTEGER）、温度读数（REAL），甚至是样品照片（BLOB）。

* **【SQL/Shell实战】:**

  ```sql
  -- 在 'notes' (ANY类型) 列中存入各种类型的数据，全都会成功！
  INSERT INTO reagent_cabinet (id, name, notes) VALUES (10, 'Note 1', 'Handle with care');      -- TEXT
  INSERT INTO reagent_cabinet (id, name, notes) VALUES (11, 'Note 2', 100);                    -- INTEGER
  INSERT INTO reagent_cabinet (id, name, notes) VALUES (12, 'Note 3', 25.5);                   -- REAL
  INSERT INTO reagent_cabinet (id, name, notes) VALUES (13, 'Note 4', X'CAFEBABE');            -- BLOB
  INSERT INTO reagent_cabinet (id, name, notes) VALUES (14, 'Note 5', NULL);                   -- NULL

  -- 查询它们的真实类型
  SELECT id, notes, typeof(notes) FROM reagent_cabinet WHERE id >= 10;
  -- 输出:
  -- 10|Handle with care|text
  -- 11|100|integer
  -- 12|25.5|real
  -- 13|...|blob
  -- 14||null
  ```

* **【原理解析】:** `ANY` 类型的存在，体现了 SQLite 设计的 pragmatism（实用主义）。它承认，即使在需要严格模式的场景下，也总有一些字段需要灵活性（比如存储 JSON 或用户自定义的元数据）。`ANY` 提供了一个受控的“出口”，让你在享受 `STRICT` 带来的数据完整性的同时，又不失 SQLite 标志性的灵活性。

* **【思考时间】:** 既然有了 `ANY` 类型，我们似乎可以在 `STRICT` 表里随意创建一个 `ANY` 类型的列来存储任何数据。你认为在设计数据库时，应该拥抱 `ANY` 的便利性，还是应该尽可能避免使用它？为什么？