C# SQLite高级功能示例

[复制链接]
发表于 2025-9-6 11:29:44 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
目次
1 重要功能
2 程序布局和流程
3 详细实现说明
3.1 基础设置
3.2 事务演示
3.3 索引演示
3.4 视图演示
3.5 触发器演示
3.6 全文搜索演示
3.7 窗口函数演示
3.8 外键束缚演示
 4 高级功能示例
5 单个方法详细先容
5.1 SetupExampleData()方法
5.2 UseTransactions() 方法
5.3 UseIndexes() 方法
5.4 UseViews() 方法
5.5 UseTriggers() 方法
5.6 UseFTS() 方法
5.7 UseWindowFunctions() 方法
5.8 UseForeignKeys() 方法
5.9 辅助方法
6 使用留意事项
7 数据类型映射

本文给出的C#示例程序,展示了SQLite数据库的各种高级功能使用方法。通过命名空间SQLiteAdvancedDemo下的Program类实现。
1 重要功能

这个程序演示了以下SQLite高级特性:
   

  • 事务管理:展示怎样开始、提交和回滚事务
  • 索引使用:创建和使用索引来优化查询性能
  • 视图:创建和使用SQL视图简化复杂查询
  • 触发器:实现数据变更时自动执行的操作
  • 全文搜索(FTS5):演示SQLite的全文搜索功能
  • 窗口函数:使用高级SQL分析功能
  • 外键束缚:展示怎样正确处理表之间的关系
  2 程序布局和流程


  • 初始化和环境设置

    • 界说数据库文件名和连接字符串
    • 检查数据库文件是否存在,不存在则创建
    • 调用SetupExampleData()方法创建示例数据
       
  • 依次演示各个高级功能

    • 调用各个演示方法:UseTransactions(), UseIndexes(), UseViews(), UseTriggers(), UseFTS(), UseWindowFunctions(), UseForeignKeys()
       
  • 每个演示方法的通用布局

    • 打印功能标题
    • 创建数据库连接
    • 执行相关SQL命令
    • 显示执行效果
    • 捕捉和处理大概的异常
       
  • 辅助方法

    • ExecuteNonQuery: 执行非查询SQL语句
    • DisplayQueryResults: 格式化显示查询效果
       
3 详细实现说明

3.1 基础设置

   

  • 在Main方法中创建数据库文件(如不存在)并处理大概的异常
  • SetupExampleData方法中创建了两个表(部分和员工),并插入了示例数据
  • 启用外键束缚(PRAGMA foreign_keys = ON)
  3.2 事务演示

   

  • 展示怎样使用事务包装多个SQL操作
  • 演示提交和回滚机制,确保数据同等性
  3.3 索引演示

   

  • 创建索引优化查询
  • 使用EXPLAIN QUERY PLAN展示查询操持
  • 展示带索引的查询执行
  3.4 视图演示

   

  • 创建表连接的视图简化复杂查询
  • 查询视图以获取员工详细信息
  3.5 触发器演示

   

  • 创建审计日志日志
  • 实现插入和更新触发器
  • 通过操作员工表触发这些触发器
  • 显示审计日志日志记录
  3.6 全文搜索演示

   

  • 创建FTS5捏造表用于文本搜索
  • 插入示例文档数据
  • 演示基本搜索和带排名的搜索
  3.7 窗口函数演示

   

  • 使用窗口函数进行分析盘算
  • 展示分区排名、均匀值盘算等高级功能
  3.8 外键束缚演示

   

  • 展示违背外键束缚时的错误处理
  • 演示正确的删除顺序
  
 4 高级功能示例

  1. using System;
  2. using System.Data.SQLite;
  3. using System.IO;
  4. using System.Collections.Generic;
  5. namespace SQLiteAdvancedDemo
  6. {
  7.     class Program
  8.     {
  9.         private static string dbFile = "advanced_demo.db";
  10.         private static string connectionString = $"Data Source={dbFile};Version=3;";
  11.         static void Main(string[] args)
  12.         {
  13.             try
  14.             {
  15.                 // 确保数据库文件存在
  16.                 if (!File.Exists(dbFile))
  17.                 {
  18.                     SQLiteConnection.CreateFile(dbFile);
  19.                 }
  20.                 // 创建示例数据
  21.                 SetupExampleData();
  22.                 // 演示高级功能
  23.                 UseTransactions();
  24.                 UseIndexes();
  25.                 UseViews();
  26.                 UseTriggers();
  27.                 UseFTS();
  28.                 UseWindowFunctions();
  29.                 UseForeignKeys();
  30.                 Console.WriteLine("所有高级功能演示已完成!");
  31.             }
  32.             catch (Exception ex)
  33.             {
  34.                 Console.WriteLine($"发生错误: {ex.Message}");
  35.             }
  36.             Console.ReadKey();
  37.         }
  38.         // 设置示例数据
  39.         static void SetupExampleData()
  40.         {
  41.             using (var connection = new SQLiteConnection(connectionString))
  42.             {
  43.                 connection.Open();
  44.                 // 启用外键约束
  45.                 ExecuteNonQuery(connection, "PRAGMA foreign_keys = ON;");
  46.                 // 创建示例表
  47.                 ExecuteNonQuery(connection, @"
  48.                     CREATE TABLE IF NOT EXISTS Departments (
  49.                         DeptId INTEGER PRIMARY KEY,
  50.                         Name TEXT NOT NULL
  51.                     )");
  52.                 ExecuteNonQuery(connection, @"
  53.                     CREATE TABLE IF NOT EXISTS Employees (
  54.                         EmpId INTEGER PRIMARY KEY,
  55.                         Name TEXT NOT NULL,
  56.                         DeptId INTEGER,
  57.                         Salary REAL,
  58.                         HireDate TEXT,
  59.                         FOREIGN KEY (DeptId) REFERENCES Departments(DeptId)
  60.                     )");
  61.                 // 清空表,以便重复运行
  62.                 ExecuteNonQuery(connection, "DELETE FROM Employees");
  63.                 ExecuteNonQuery(connection, "DELETE FROM Departments");
  64.                 // 添加部门数据
  65.                 ExecuteNonQuery(connection, @"
  66.                     INSERT INTO Departments (DeptId, Name) VALUES
  67.                     (1, '研发部'),
  68.                     (2, '市场部'),
  69.                     (3, '财务部')");
  70.                 // 添加员工数据
  71.                 ExecuteNonQuery(connection, @"
  72.                     INSERT INTO Employees (Name, DeptId, Salary, HireDate) VALUES
  73.                     ('张三', 1, 15000, '2020-01-15'),
  74.                     ('李四', 1, 12000, '2020-03-20'),
  75.                     ('王五', 2, 10000, '2021-05-10'),
  76.                     ('赵六', 2, 9500, '2021-06-01'),
  77.                     ('钱七', 3, 11000, '2022-02-15')");
  78.             }
  79.         }
  80.         // 使用事务
  81.         static void UseTransactions()
  82.         {
  83.             Console.WriteLine("\n=== 事务演示 ===");
  84.             
  85.             using (var connection = new SQLiteConnection(connectionString))
  86.             {
  87.                 connection.Open();
  88.                
  89.                 // 开始事务
  90.                 using (var transaction = connection.BeginTransaction())
  91.                 {
  92.                     try
  93.                     {
  94.                         // 执行多个操作
  95.                         ExecuteNonQuery(connection, "INSERT INTO Departments (DeptId, Name) VALUES (4, '人力资源部')", transaction);
  96.                         ExecuteNonQuery(connection, "UPDATE Employees SET Salary = Salary * 1.1 WHERE DeptId = 1", transaction);
  97.                         
  98.                         // 假设这里有条件判断是否提交
  99.                         bool shouldCommit = true;
  100.                         
  101.                         if (shouldCommit)
  102.                         {
  103.                             transaction.Commit();
  104.                             Console.WriteLine("事务已提交。");
  105.                         }
  106.                         else
  107.                         {
  108.                             transaction.Rollback();
  109.                             Console.WriteLine("事务已回滚。");
  110.                         }
  111.                     }
  112.                     catch (Exception ex)
  113.                     {
  114.                         transaction.Rollback();
  115.                         Console.WriteLine($"发生错误,事务已回滚: {ex.Message}");
  116.                     }
  117.                 }
  118.                
  119.                 // 显示结果
  120.                 Console.WriteLine("部门列表:");
  121.                 DisplayQueryResults(connection, "SELECT * FROM Departments");
  122.             }
  123.         }
  124.         // 使用索引
  125.         static void UseIndexes()
  126.         {
  127.             Console.WriteLine("\n=== 索引演示 ===");
  128.             
  129.             using (var connection = new SQLiteConnection(connectionString))
  130.             {
  131.                 connection.Open();
  132.                
  133.                 // 创建索引
  134.                 ExecuteNonQuery(connection, "CREATE INDEX IF NOT EXISTS idx_employees_dept ON Employees(DeptId)");
  135.                 ExecuteNonQuery(connection, "CREATE INDEX IF NOT EXISTS idx_employees_salary ON Employees(Salary DESC)");
  136.                
  137.                 // 使用EXPLAIN QUERY PLAN查看查询计划
  138.                 Console.WriteLine("查询计划分析:");
  139.                 DisplayQueryResults(connection, "EXPLAIN QUERY PLAN SELECT * FROM Employees WHERE DeptId = 1 AND Salary > 10000");
  140.                
  141.                 // 使用索引的查询
  142.                 Console.WriteLine("\n使用索引的查询结果:");
  143.                 DisplayQueryResults(connection, "SELECT * FROM Employees WHERE DeptId = 1 AND Salary > 10000");
  144.             }
  145.         }
  146.         // 使用视图
  147.         static void UseViews()
  148.         {
  149.             Console.WriteLine("\n=== 视图演示 ===");
  150.             
  151.             using (var connection = new SQLiteConnection(connectionString))
  152.             {
  153.                 connection.Open();
  154.                
  155.                 // 创建视图
  156.                 ExecuteNonQuery(connection, @"
  157.                     CREATE VIEW IF NOT EXISTS EmployeeDetails AS
  158.                     SELECT e.EmpId, e.Name, e.Salary, d.Name AS Department, e.HireDate
  159.                     FROM Employees e
  160.                     JOIN Departments d ON e.DeptId = d.DeptId");
  161.                
  162.                 // 使用视图
  163.                 Console.WriteLine("视图查询结果:");
  164.                 DisplayQueryResults(connection, "SELECT * FROM EmployeeDetails ORDER BY Salary DESC");
  165.             }
  166.         }
  167.         // 使用触发器
  168.         static void UseTriggers()
  169.         {
  170.             Console.WriteLine("\n=== 触发器演示 ===");
  171.             
  172.             using (var connection = new SQLiteConnection(connectionString))
  173.             {
  174.                 connection.Open();
  175.                
  176.                 // 创建审计日志日志
  177.                 ExecuteNonQuery(connection, @"
  178.                     CREATE TABLE IF NOT EXISTS AuditLog (
  179.                         LogId INTEGER PRIMARY KEY,
  180.                         TableName TEXT,
  181.                         Operation TEXT,
  182.                         Timestamp TEXT DEFAULT CURRENT_TIMESTAMP
  183.                     )");
  184.                
  185.                 // 创建触发器
  186.                 ExecuteNonQuery(connection, @"
  187.                     CREATE TRIGGER IF NOT EXISTS after_employee_insert
  188.                     AFTER INSERT ON Employees
  189.                     BEGIN
  190.                         INSERT INTO AuditLog (TableName, Operation)
  191.                         VALUES ('Employees', 'INSERT');
  192.                     END");
  193.                
  194.                 ExecuteNonQuery(connection, @"
  195.                     CREATE TRIGGER IF NOT EXISTS after_employee_update
  196.                     AFTER UPDATE ON Employees
  197.                     BEGIN
  198.                         INSERT INTO AuditLog (TableName, Operation)
  199.                         VALUES ('Employees', 'UPDATE');
  200.                     END");
  201.                
  202.                 // 触发触发器
  203.                 ExecuteNonQuery(connection, "INSERT INTO Employees (Name, DeptId, Salary) VALUES ('新员工', 2, 8000)");
  204.                 ExecuteNonQuery(connection, "UPDATE Employees SET Salary = 8500 WHERE Name = '新员工'");
  205.                
  206.                 // 显示审计日志
  207.                 Console.WriteLine("审计日志:");
  208.                 DisplayQueryResults(connection, "SELECT * FROM AuditLog");
  209.             }
  210.         }
  211.         // 使用全文搜索
  212.         static void UseFTS()
  213.         {
  214.             Console.WriteLine("\n=== 全文搜索(FTS5)演示 ===");
  215.             
  216.             using (var connection = new SQLiteConnection(connectionString))
  217.             {
  218.                 connection.Open();
  219.                
  220.                 try
  221.                 {
  222.                     // 创建FTS5虚拟表
  223.                     ExecuteNonQuery(connection, @"
  224.                         CREATE VIRTUAL TABLE IF NOT EXISTS DocumentsFTS USING fts5(
  225.                             Title,
  226.                             Content,
  227.                             Author,
  228.                             tokenize = 'porter unicode61'
  229.                         )");
  230.                     
  231.                     // 插入示例文档
  232.                     ExecuteNonQuery(connection, @"
  233.                         INSERT INTO DocumentsFTS (Title, Content, Author) VALUES
  234.                         ('SQLite教程', '这是一份关于SQLite数据库的完整教程,包括基本操作和高级功能。', '张三'),
  235.                         ('C#编程入门', 'C#是微软开发的面向对象编程语言,用于.NET平台开发。', '李四'),
  236.                         ('数据库设计', '良好的数据库设计遵循范式和性能优化原则。SQLite是轻量级数据库的首选。', '王五')");
  237.                     
  238.                     // 执行全文搜索
  239.                     Console.WriteLine("搜索'SQLite'的结果:");
  240.                     DisplayQueryResults(connection, "SELECT * FROM DocumentsFTS WHERE DocumentsFTS MATCH 'sqlite'");
  241.                     
  242.                     // 带排名的搜索
  243.                     Console.WriteLine("\n带排名的搜索结果:");
  244.                     DisplayQueryResults(connection, @"
  245.                         SELECT Title, Author, rank
  246.                         FROM DocumentsFTS
  247.                         WHERE DocumentsFTS MATCH 'sqlite OR 数据库'
  248.                         ORDER BY rank");
  249.                 }
  250.                 catch (SQLiteException ex)
  251.                 {
  252.                     Console.WriteLine($"FTS5可能未启用: {ex.Message}");
  253.                     Console.WriteLine("注意: 使用FTS5需要SQLite编译时启用该扩展。");
  254.                 }
  255.             }
  256.         }
  257.         // 使用窗口函数
  258.         static void UseWindowFunctions()
  259.         {
  260.             Console.WriteLine("\n=== 窗口函数演示 ===");
  261.             
  262.             using (var connection = new SQLiteConnection(connectionString))
  263.             {
  264.                 connection.Open();
  265.                
  266.                 try
  267.                 {
  268.                     // 使用窗口函数
  269.                     string windowQuery = @"
  270.                         SELECT
  271.                             e.Name,
  272.                             d.Name AS Department,
  273.                             e.Salary,
  274.                             RANK() OVER (PARTITION BY e.DeptId ORDER BY e.Salary DESC) AS DeptRank,
  275.                             AVG(e.Salary) OVER (PARTITION BY e.DeptId) AS AvgDeptSalary,
  276.                             e.Salary - AVG(e.Salary) OVER (PARTITION BY e.DeptId) AS DiffFromAvg
  277.                         FROM Employees e
  278.                         JOIN Departments d ON e.DeptId = d.DeptId
  279.                         ORDER BY d.Name, DeptRank";
  280.                     
  281.                     Console.WriteLine("窗口函数查询结果:");
  282.                     DisplayQueryResults(connection, windowQuery);
  283.                 }
  284.                 catch (SQLiteException ex)
  285.                 {
  286.                     Console.WriteLine($"窗口函数可能未支持: {ex.Message}");
  287.                     Console.WriteLine("注意: 窗口函数需要SQLite 3.25+版本。");
  288.                 }
  289.             }
  290.         }
  291.         // 使用外键约束
  292.         static void UseForeignKeys()
  293.         {
  294.             Console.WriteLine("\n=== 外键约束演示 ===");
  295.             
  296.             using (var connection = new SQLiteConnection(connectionString))
  297.             {
  298.                 connection.Open();
  299.                
  300.                 // 确保外键约束已开启
  301.                 ExecuteNonQuery(connection, "PRAGMA foreign_keys = ON;");
  302.                
  303.                 // 尝试删除有关联记录的部门
  304.                 try
  305.                 {
  306.                     ExecuteNonQuery(connection, "DELETE FROM Departments WHERE DeptId = 1");
  307.                     Console.WriteLine("删除成功"); // 不应该执行到此处
  308.                 }
  309.                 catch (SQLiteException ex)
  310.                 {
  311.                     Console.WriteLine($"预期的外键约束错误: {ex.Message}");
  312.                 }
  313.                
  314.                 // 正确的删除顺序 - 先删除关联记录
  315.                 Console.WriteLine("\n按正确顺序删除:");
  316.                 ExecuteNonQuery(connection, "BEGIN TRANSACTION");
  317.                 ExecuteNonQuery(connection, "DELETE FROM Employees WHERE DeptId = 3");
  318.                 ExecuteNonQuery(connection, "DELETE FROM Departments WHERE DeptId = 3");
  319.                 ExecuteNonQuery(connection, "COMMIT");
  320.                
  321.                 Console.WriteLine("部门列表:");
  322.                 DisplayQueryResults(connection, "SELECT * FROM Departments");
  323.             }
  324.         }
  325.         // 执行非查询语句的辅助方法
  326.         static void ExecuteNonQuery(SQLiteConnection connection, string sql, SQLiteTransaction transaction = null)
  327.         {
  328.             using (var command = new SQLiteCommand(sql, connection, transaction))
  329.             {
  330.                 command.ExecuteNonQuery();
  331.             }
  332.         }
  333.         // 显示查询结果的辅助方法
  334.         static void DisplayQueryResults(SQLiteConnection connection, string sql)
  335.         {
  336.             using (var command = new SQLiteCommand(sql, connection))
  337.             {
  338.                 using (var reader = command.ExecuteReader())
  339.                 {
  340.                     // 获取列名
  341.                     List<string> columns = new List<string>();
  342.                     for (int i = 0; i < reader.FieldCount; i++)
  343.                     {
  344.                         columns.Add(reader.GetName(i));
  345.                     }
  346.                     
  347.                     // 输出列名
  348.                     Console.WriteLine(string.Join(" | ", columns));
  349.                     Console.WriteLine(new string('-', columns.Count * 15));
  350.                     
  351.                     // 输出行
  352.                     while (reader.Read())
  353.                     {
  354.                         List<string> values = new List<string>();
  355.                         for (int i = 0; i < reader.FieldCount; i++)
  356.                         {
  357.                             values.Add(reader[i]?.ToString() ?? "NULL");
  358.                         }
  359.                         Console.WriteLine(string.Join(" | ", values));
  360.                     }
  361.                 }
  362.             }
  363.         }
  364.     }
  365. }
复制代码
5 单个方法详细先容

5.1 SetupExampleData()方法

  1. static void SetupExampleData()
  2. {
  3.     using (var connection = new SQLiteConnection(connectionString))
  4.     {
  5.         connection.Open();
  6.         // 启用外键约束
  7.         ExecuteNonQuery(connection, "PRAGMA foreign_keys = ON;");
  8.         // 创建示例表
  9.         ExecuteNonQuery(connection, @"
  10.             CREATE TABLE IF NOT EXISTS Departments (
  11.                 DeptId INTEGER PRIMARY KEY,
  12.                 Name TEXT NOT NULL
  13.             )");
  14.         ExecuteNonQuery(connection, @"
  15.             CREATE TABLE IF NOT EXISTS Employees (
  16.                 EmpId INTEGER PRIMARY KEY,
  17.                 Name TEXT NOT NULL,
  18.                 DeptId INTEGER,
  19.                 Salary REAL,
  20.                 HireDate TEXT,
  21.                 FOREIGN KEY (DeptId) REFERENCES Departments(DeptId)
  22.             )");
  23.         // 清空表,以便重复运行
  24.         ExecuteNonQuery(connection, "DELETE FROM Employees");
  25.         ExecuteNonQuery(connection, "DELETE FROM Departments");
  26.         // 添加部门数据
  27.         ExecuteNonQuery(connection, @"
  28.             INSERT INTO Departments (DeptId, Name) VALUES
  29.             (1, '研发部'),
  30.             (2, '市场部'),
  31.             (3, '财务部')");
  32.         // 添加员工数据
  33.         ExecuteNonQuery(connection, @"
  34.             INSERT INTO Employees (Name, DeptId, Salary, HireDate) VALUES
  35.             ('张三', 1, 15000, '2020-01-15'),
  36.             ('李四', 1, 12000, '2020-03-20'),
  37.             ('王五', 2, 10000, '2021-05-10'),
  38.             ('赵六', 2, 9500, '2021-06-01'),
  39.             ('钱七', 3, 11000, '2022-02-15')");
  40.     }
  41. }
复制代码
剖析:
   

  • 连接管理:使用using语句确保连接被正确关闭和资源释放,这是C#中处理IDisposable资源的最佳实践。
  • 启用外键束缚:PRAGMA foreign_keys = ON; - SQLite默认不启用外键束缚,这行代码显式启用它,答应表之间建立引用完备性关系。
  • 创建表布局

    • Departments表:有DeptId(主键)和Name字段
    • Employees表:有EmpId(主键)、Name、DeptId(外键)、Salary和HireDate字段
    • FOREIGN KEY束缚:确保Employees表中的DeptId引用Departments表中存在的DeptId

  • 清空表数据:DELETE FROM语句确保每次运行程序时表是空的,避免重复数据。从有外键束缚的Employees表先删除是必要的,以避免违背引用完备性。
  • 插入示例数据:向两个表添加示例数据。留意:先插入Departments数据,再插入Employees数据,这是因为Employees表的外键引用了Departments表。
  5.2 UseTransactions() 方法

  1. static void UseTransactions()
  2. {
  3.     Console.WriteLine("\n=== 事务演示 ===");
  4.    
  5.     using (var connection = new SQLiteConnection(connectionString))
  6.     {
  7.         connection.Open();
  8.         
  9.         // 开始事务
  10.         using (var transaction = connection.BeginTransaction())
  11.         {
  12.             try
  13.             {
  14.                 // 执行多个操作
  15.                 ExecuteNonQuery(connection, "INSERT INTO Departments (DeptId, Name) VALUES (4, '人力资源部')", transaction);
  16.                 ExecuteNonQuery(connection, "UPDATE Employees SET Salary = Salary * 1.1 WHERE DeptId = 1", transaction);
  17.                
  18.                 // 假设这里有条件判断是否提交
  19.                 bool shouldCommit = true;
  20.                
  21.                 if (shouldCommit)
  22.                 {
  23.                     transaction.Commit();
  24.                     Console.WriteLine("事务已提交。");
  25.                 }
  26.                 else
  27.                 {
  28.                     transaction.Rollback();
  29.                     Console.WriteLine("事务已回滚。");
  30.                 }
  31.             }
  32.             catch (Exception ex)
  33.             {
  34.                 transaction.Rollback();
  35.                 Console.WriteLine($"发生错误,事务已回滚: {ex.Message}");
  36.             }
  37.         }
  38.         
  39.         // 显示结果
  40.         Console.WriteLine("部门列表:");
  41.         DisplayQueryResults(connection, "SELECT * FROM Departments");
  42.     }
  43. }
复制代码
剖析:
   

  • 事务管理:connection.BeginTransaction()创建一个SQLite事务,也用using语句确保适当关闭。
  • 错误处理:try...catch块捕捉任何大概发生的异常,如果有错误发生,会回滚事务。
  • 执行事务操作:在事务中执行两个操作:

    • 插入新部分"人力资源部"
    • 给全部研发部(DeptId=1)的员工加薪10%

  • 提交或回滚:根据条件决定提交或回滚事务。在这个示例中,shouldCommit设为true,以是事务会被提交。在实际应用中,这大概基于业务逻辑或验证效果。
  • 事务的好处

    • 原子性:多个操作要么全部执行,要么全部不执行
    • 同等性:数据库从一个同等状态转换到另一个同等状态
    • 隔离性:事务操作相互隔离
    • 持久性:一旦提交,更改永久生存

  5.3 UseIndexes() 方法

  1. static void UseIndexes()
  2. {
  3.     Console.WriteLine("\n=== 索引演示 ===");
  4.    
  5.     using (var connection = new SQLiteConnection(connectionString))
  6.     {
  7.         connection.Open();
  8.         
  9.         // 创建索引
  10.         ExecuteNonQuery(connection, "CREATE INDEX IF NOT EXISTS idx_employees_dept ON Employees(DeptId)");
  11.         ExecuteNonQuery(connection, "CREATE INDEX IF NOT EXISTS idx_employees_salary ON Employees(Salary DESC)");
  12.         
  13.         // 使用EXPLAIN QUERY PLAN查看查询计划
  14.         Console.WriteLine("查询计划分析:");
  15.         DisplayQueryResults(connection, "EXPLAIN QUERY PLAN SELECT * FROM Employees WHERE DeptId = 1 AND Salary > 10000");
  16.         
  17.         // 使用索引的查询
  18.         Console.WriteLine("\n使用索引的查询结果:");
  19.         DisplayQueryResults(connection, "SELECT * FROM Employees WHERE DeptId = 1 AND Salary > 10000");
  20.     }
  21. }
复制代码
剖析:
   

  • 创建索引

    • idx_employees_dept:在Employees表的DeptId列上创建索引,优化按部分查询
    • idx_employees_salary:在Employees表的Salary列上创建降序索引,优化薪资排序和范围查询

  • 查询筹分别析:EXPLAIN QUERY PLAN显示SQLite将怎样执行查询,包括是否使用索引、使用哪些索引、按什么顺序扫描表等信息。这对于优化查询性能非常有效。
  • 执行索引优化查询:执行一个同时使用DeptId和Salary条件的查询,应该能从创建的索引中受益。
  • 索引优化的好处

    • 加快数据检索操作
    • 减少磁盘I/O
    • 资助执行ORDER BY操作
    • 加快JOIN操作

  • 留意事项:实际应用中需要均衡读写性能,因为索引会减慢写入速度。 
  5.4 UseViews() 方法

  1. static void UseViews()
  2. {
  3.     Console.WriteLine("\n=== 视图演示 ===");
  4.    
  5.     using (var connection = new SQLiteConnection(connectionString))
  6.     {
  7.         connection.Open();
  8.         
  9.         // 创建视图
  10.         ExecuteNonQuery(connection, @"
  11.             CREATE VIEW IF NOT EXISTS EmployeeDetails AS
  12.             SELECT e.EmpId, e.Name, e.Salary, d.Name AS Department, e.HireDate
  13.             FROM Employees e
  14.             JOIN Departments d ON e.DeptId = d.DeptId");
  15.         
  16.         // 使用视图
  17.         Console.WriteLine("视图查询结果:");
  18.         DisplayQueryResults(connection, "SELECT * FROM EmployeeDetails ORDER BY Salary DESC");
  19.     }
  20. }
复制代码
剖析:
   

  • 创建视图:CREATE VIEW语句创建了一个名为EmployeeDetails的视图,这个视图连接Employees和Departments表,并选择特定的列。视图提供了一个预界说的查询,简化了复杂查询的使用。
  • 视图功能:视图将Employees和Departments表联接在一起,显示员工ID、姓名、薪资、所属部分名称和入职日期。
  • 查询视图:通过简朴的SELECT * FROM EmployeeDetails查询视图,就像查询平凡表一样,但实际上视图封装了复杂的JOIN查询。
  • 视图的好处

    • 简化复杂查询
    • 提供抽象和封装
    • 限定对某些列的访问,增强安全
    • 确保数据查询的同等性

  • 留意事项:SQLite视图是只读的,不支持可更新视图。
  5.5 UseTriggers() 方法

  1. static void UseTriggers()
  2. {
  3.     Console.WriteLine("\n=== 触发器演示 ===");
  4.    
  5.     using (var connection = new SQLiteConnection(connectionString))
  6.     {
  7.         connection.Open();
  8.         
  9.         // 创建审计日志表
  10.         ExecuteNonQuery(connection, @"
  11.             CREATE TABLE IF NOT EXISTS AuditLog (
  12.                 LogId INTEGER PRIMARY KEY,
  13.                 TableName TEXT,
  14.                 Operation TEXT,
  15.                 Timestamp TEXT DEFAULT CURRENT_TIMESTAMP
  16.             )");
  17.         
  18.         // 创建触发器
  19.         ExecuteNonQuery(connection, @"
  20.             CREATE TRIGGER IF NOT EXISTS after_employee_insert
  21.             AFTER INSERT ON Employees
  22.             BEGIN
  23.                 INSERT INTO AuditLog (TableName, Operation)
  24.                 VALUES ('Employees', 'INSERT');
  25.             END");
  26.         
  27.         ExecuteNonQuery(connection, @"
  28.             CREATE TRIGGER IF NOT EXISTS after_employee_update
  29.             AFTER UPDATE ON Employees
  30.             BEGIN
  31.                 INSERT INTO AuditLog (TableName, Operation)
  32.                 VALUES ('Employees', 'UPDATE');
  33.             END");
  34.         
  35.         // 触发触发器
  36.         ExecuteNonQuery(connection, "INSERT INTO Employees (Name, DeptId, Salary) VALUES ('新员工', 2, 8000)");
  37.         ExecuteNonQuery(connection, "UPDATE Employees SET Salary = 8500 WHERE Name = '新员工'");
  38.         
  39.         // 显示审计日志
  40.         Console.WriteLine("审计日志:");
  41.         DisplayQueryResults(connection, "SELECT * FROM AuditLog");
  42.     }
  43. }
复制代码
剖析:
   

  • 创建审计日志表:AuditLog表用于记录数据变更操作,包罗字段:LogId、TableName(被修改的表)、Operation(执行的操作)和Timestamp(时间戳)。
  • 创建触发器

    • after_employee_insert:在Employees表插入操作后触发,记录到审计日志
    • after_employee_update:在Employees表更新操作后触发,记录到审计日志

  • 触发操作

    • 向Employees表插入新员工,触发after_employee_insert触发器
    • 更新新员工的薪资,触发after_employee_update触发器

  • 查察效果:查询AuditLog表,显示记录的操作日志。
  • 触发器的应用场景

    • 审计跟踪
    • 业务规则验证
    • 自动维护派生数据
    • 级联更新或删除
    • 逼迫数据同等性

  • 留意事项:触发器会增加数据库复杂性,大概影响性能,特别是在大量数据操作时。
  5.6 UseFTS() 方法

  1. static void UseFTS()
  2. {
  3.     Console.WriteLine("\n=== 全文搜索(FTS5)演示 ===");
  4.    
  5.     using (var connection = new SQLiteConnection(connectionString))
  6.     {
  7.         connection.Open();
  8.         
  9.         try
  10.         {
  11.             // 创建FTS5虚拟表
  12.             ExecuteNonQuery(connection, @"
  13.                 CREATE VIRTUAL TABLE IF NOT EXISTS DocumentsFTS USING fts5(
  14.                     Title,
  15.                     Content,
  16.                     Author,
  17.                     tokenize = 'porter unicode61'
  18.                 )");
  19.             
  20.             // 插入示例文档
  21.             ExecuteNonQuery(connection, @"
  22.                 INSERT INTO DocumentsFTS (Title, Content, Author) VALUES
  23.                 ('SQLite教程', '这是一份关于SQLite数据库的完整教程,包括基本操作和高级功能。', '张三'),
  24.                 ('C#编程入门', 'C#是微软开发的面向对象编程语言,用于.NET平台开发。', '李四'),
  25.                 ('数据库设计', '良好的数据库设计遵循范式和性能优化原则。SQLite是轻量级数据库的首选。', '王五')");
  26.             
  27.             // 执行全文搜索
  28.             Console.WriteLine("搜索'SQLite'的结果:");
  29.             DisplayQueryResults(connection, "SELECT * FROM DocumentsFTS WHERE DocumentsFTS MATCH 'sqlite'");
  30.             
  31.             // 带排名的搜索
  32.             Console.WriteLine("\n带排名的搜索结果:");
  33.             DisplayQueryResults(connection, @"
  34.                 SELECT Title, Author, rank
  35.                 FROM DocumentsFTS
  36.                 WHERE DocumentsFTS MATCH 'sqlite OR 数据库'
  37.                 ORDER BY rank");
  38.         }
  39.         catch (SQLiteException ex)
  40.         {
  41.             Console.WriteLine($"FTS5可能未启用: {ex.Message}");
  42.             Console.WriteLine("注意: 使用FTS5需要SQLite编译时启用该扩展。");
  43.         }
  44.     }
  45. }
复制代码
剖析:
   

  • 创建FTS5捏造表:CREATE VIRTUAL TABLE ... USING fts5创建全文搜索表,FTS5是SQLite中最新的全文搜索引擎。

    • tokenize = 'porter unicode61':指定使用Porter词干提取算法和unicode61标志器,以支持中文等非ASCII字符。

  • 插入示例文档:向DocumentsFTS表中插入三条文档记录,每条记录有标题、内容和作者。
  • 执行基本全文搜索:使用MATCH操作符搜索含有"sqlite"的文档,FTS支持不区分大小写的搜索。
  • 带排名的搜索:使用FTS的rank函数对搜索效果进行排序,包罗更多搜索词或出现频率更高的文档排名更高。
  • 错误处理:捕捉大概的异常,因为FTS5是一个扩展,不是全部SQLite编译版本都默认启用。
  • FTS的上风

    • 快速文本搜索
    • 支持复杂检索语法(短语、AND/OR、靠近度等)
    • 支持效果排名
    • 实用于全文内容检索应用

  • 应用场景:文档搜索、应用内搜索、日志分析等。
  5.7 UseWindowFunctions() 方法

  1. static void UseWindowFunctions()
  2. {
  3.     Console.WriteLine("\n=== 窗口函数演示 ===");
  4.    
  5.     using (var connection = new SQLiteConnection(connectionString))
  6.     {
  7.         connection.Open();
  8.         
  9.         try
  10.         {
  11.             // 使用窗口函数
  12.             string windowQuery = @"
  13.                 SELECT
  14.                     e.Name,
  15.                     d.Name AS Department,
  16.                     e.Salary,
  17.                     RANK() OVER (PARTITION BY e.DeptId ORDER BY e.Salary DESC) AS DeptRank,
  18.                     AVG(e.Salary) OVER (PARTITION BY e.DeptId) AS AvgDeptSalary,
  19.                     e.Salary - AVG(e.Salary) OVER (PARTITION BY e.DeptId) AS DiffFromAvg
  20.                 FROM Employees e
  21.                 JOIN Departments d ON e.DeptId = d.DeptId
  22.                 ORDER BY d.Name, DeptRank";
  23.             
  24.             Console.WriteLine("窗口函数查询结果:");
  25.             DisplayQueryResults(connection, windowQuery);
  26.         }
  27.         catch (SQLiteException ex)
  28.         {
  29.             Console.WriteLine($"窗口函数可能未支持: {ex.Message}");
  30.             Console.WriteLine("注意: 窗口函数需要SQLite 3.25+版本。");
  31.         }
  32.     }
  33. }
复制代码
剖析:
   

  • 窗口函数查询:这个查询使用多种窗口函数来盘算员工数据的聚合和排名:

    • RANK() OVER (PARTITION BY e.DeptId ORDER BY e.Salary DESC) AS DeptRank:盘算每个员工在其部分内按薪资排名
    • AVG(e.Salary) OVER (PARTITION BY e.DeptId) AS AvgDeptSalary:盘算每个部分的均匀薪资
    • e.Salary - AVG(e.Salary) OVER (PARTITION BY e.DeptId) AS DiffFromAvg:盘算每个员工薪资与部分均匀值的差别

  • PARTITION BY:按部分分组盘算,每个部分单独盘算聚合值。
  • ORDER BY:在窗口函数中指定排序方式,这里按薪资降序分列。
  • 错误处理:捕捉大概的异常,因为窗口函数需要SQLite 3.25+版本支持。
  • 窗口函数的上风

    • 在保持原始行的环境下执行聚合盘算
    • 避免复杂的自连接或子查询
    • 实现排名、移动均匀、累计和等复杂分析功能
    • 进步查询可读性和性能

  • 应用场景

    • 排名盘算
    • 移动均匀和累计盘算
    • 同比环比分析
    • 分组内排序和比力

  5.8 UseForeignKeys() 方法

  1. static void UseForeignKeys()
  2. {
  3.     Console.WriteLine("\n=== 外键约束演示 ===");
  4.    
  5.     using (var connection = new SQLiteConnection(connectionString))
  6.     {
  7.         connection.Open();
  8.         
  9.         // 确保外键约束已开启
  10.         ExecuteNonQuery(connection, "PRAGMA foreign_keys = ON;");
  11.         
  12.         // 尝试删除有关联记录的部门
  13.         try
  14.         {
  15.             ExecuteNonQuery(connection, "DELETE FROM Departments WHERE DeptId = 1");
  16.             Console.WriteLine("删除成功"); // 不应该执行到此处
  17.         }
  18.         catch (SQLiteException ex)
  19.         {
  20.             Console.WriteLine($"预期的外键约束错误: {ex.Message}");
  21.         }
  22.         
  23.         // 正确的删除顺序 - 先删除关联记录
  24.         Console.WriteLine("\n按正确顺序删除:");
  25.         ExecuteNonQuery(connection, "BEGIN TRANSACTION");
  26.         ExecuteNonQuery(connection, "DELETE FROM Employees WHERE DeptId = 3");
  27.         ExecuteNonQuery(connection, "DELETE FROM Departments WHERE DeptId = 3");
  28.         ExecuteNonQuery(connection, "COMMIT");
  29.         
  30.         Console.WriteLine("部门列表:");
  31.         DisplayQueryResults(connection, "SELECT * FROM Departments");
  32.     }
  33. }
复制代码
剖析:
   

  • 启用外键束缚:SQLite默认不逼迫执行外键束缚,需要显式启用PRAGMA foreign_keys = ON;。
  • 错误测试:尝试删除有员工关联的部分(DeptId=1),这应该会触发外键束缚错误,因为有员工引用这个部分。
  • 异常处理:捕捉外键束缚违背异常,这是预期的行为,确保数据完备性。
  • 正确的删除顺序

    • 开始事务BEGIN TRANSACTION
    • 先删除引用记录:DELETE FROM Employees WHERE DeptId = 3
    • 再删除被引用记录:DELETE FROM Departments WHERE DeptId = 3
    • 提交事务COMMIT

  • 查察效果:显示部分表数据,确认删除成功。
  • 外键束缚的好处

    • 确保数据同等性和引用完备性
    • 防止孤立记录
    • 配置级联动作(CASCADE、SET NULL等)
    • 提供数据库级别的数据验证

  • 留意事项

    • SQLite外键束缚需要显式启用
    • 多表操作需要考虑正确的顺序
    • 事务可以确保多步操作的原子性

  5.9 辅助方法

  1. // 执行非查询语句的辅助方法
  2. static void ExecuteNonQuery(SQLiteConnection connection, string sql, SQLiteTransaction transaction = null)
  3. {
  4.     using (var command = new SQLiteCommand(sql, connection, transaction))
  5.     {
  6.         command.ExecuteNonQuery();
  7.     }
  8. }
  9. // 显示查询结果的辅助方法
  10. static void DisplayQueryResults(SQLiteConnection connection, string sql)
  11. {
  12.     using (var command = new SQLiteCommand(sql, connection))
  13.     {
  14.         using (var reader = command.ExecuteReader())
  15.         {
  16.             // 获取列名
  17.             List<string> columns = new List<string>();
  18.             for (int i = 0; i < reader.FieldCount; i++)
  19.             {
  20.                 columns.Add(reader.GetName(i));
  21.             }
  22.             
  23.             // 输出列名
  24.             Console.WriteLine(string.Join(" | ", columns));
  25.             Console.WriteLine(new string('-', columns.Count * 15));
  26.             
  27.             // 输出行
  28.             while (reader.Read())
  29.             {
  30.                 List<string> values = new List<string>();
  31.                 for (int i = 0; i < reader.FieldCount; i++)
  32.                 {
  33.                     values.Add(reader[i]?.ToString() ?? "NULL");
  34.                 }
  35.                 Console.WriteLine(string.Join(" | ", values));
  36.             }
  37.         }
  38.     }
  39. }
复制代码
剖析:
   

  • ExecuteNonQuery方法

    • 用于执行不返回效果集的SQL命令(INSERT、UPDATE、DELETE、CREATE等)
    • 参数:数据库连接、SQL命令文本、可选的事务对象
    • 使用using语句确保命令对象被正确释放

  • DisplayQueryResults方法

    • 用于执行查询并漂亮地显示效果
    • 步调:

      • 创建SQL命令并执行查询获取读取器
      • 获取全部列名并显示表头
      • 循环读取每一行数据
      • 将每行格式化为表格情势并输出


  • 数据读取本领

    • 使用reader.FieldCount获取效果集列数
    • 使用reader.GetName(i)获取列名
    • 使用空合并运算符??处理NULL值
    • 使用连接将效果格式化为表格

  • 方法复用:这些辅助方法表现了代码复用的好实践,避免在多个地方重复相似代码。
  6 使用留意事项


  • 连接管理

    • 总是使用using语句确保连接正确关闭
    • 避免长时间保持连接打开
    • 对于多线程应用,考虑使用连接池
       
  • 参数化查询

    • 始终使用参数化查询防止SQL注入
    • 不要通过字符串拼接构建SQL语句
       
  • 事务使用

    • 批量操作使用事务进步性能
    • 保持事务尽大概短小
    • 正确处理事务的异常环境
       
  • 性能考虑

    • 为频繁查询的列创建索引
    • 使用EXPLAIN QUERY PLAN分析查询性能
    • 大量数据操作时考虑批处理
       
  • 版本兼容性

    • 确认目标SQLite版本是否支持需要的功能
    • 窗口函数需要SQLite 3.25+
    • FTS5需要特别编译支持 
       
7 数据类型映射

C#类型和SQLite类型之间的映射:
C#类型SQLite类型int, longINTEGERdouble, floatREALstringTEXTbyte[]BLOBDateTimeTEXT/INTEGERboolINTEGER 在读取时需要留意类型转换,SQLite的动态类型系统大概需要额外的类型转换处理。
以上就是SQLite高级功能的学习资源,在里面已经详细先容了SQLite高级功能的使用以及留意事项等标题!!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告
回复

使用道具 举报

×
登录参与点评抽奖,加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表