【问题标题】:Delphi support for SQLite manifest typingDelphi 支持 SQLite 清单类型
【发布时间】:2012-12-18 02:20:53
【问题描述】:

SQLite 有一个有趣的“功能”,可以让您在任何字段中存储任何内容,而不管其数据类型如何。

http://www.sqlite.org/different.html#typing

我不得不阅读一些由 (ab) 使用此“功能”创建的外部创建的 SQLite 文件。他们有一个定义为 VARCHAR(30) 的字段,但使用它来存储最多 100 个字符或更多字符的字符串。如果您直接调用 SQLite DLL 来存储您的数据,SQLite 会很高兴地做到这一点而无需进行任何修剪。

我目前正在使用具有 SQLite 支持的 DevArt UniDAC 3.70.0.19 来读取这些文件,但是它非常合理地尊重定义的字段大小,因此创建了一个长度为 30 个字符的 TStringField 对象。我无法访问超过 30 个字符限制的所有字符。

我知道所有适用于 SQLite 的 Delphi 解决方案,但是有人可以告诉我其中哪一个可以处理这个“功能”吗?

【问题讨论】:

    标签: delphi sqlite type-conversion devart


    【解决方案1】:

    您可以使用任何对 sqlite 引擎的直接访问层来执行此操作,而无需任何 TDataset 层。

    例如我们的开源包装器http://blog.synopse.info/post/2011/07/22/SynDBSQLite3%3A-SQLite3-direct-access

    事实上,与大多数 SQL 数据库不同,SQLite 不会根据列的声明类型来限制可以插入到列中的数据类型。相反,SQLite 使用动态类型。列的声明类型仅用于确定列的亲和性。无需 Db.pas 层的直接访问允许使用此独特功能。

    【讨论】:

      【解决方案2】:

      您的解决方案可以放在 sqlite 本身。默认情况下,模式是不可写的(您不能更新 sqlite_master 表),但只要有理智的知识和 PRAGMA writable_schema=ON; 的一点帮助,您就可以做到这一点。所以有些改动是安全的,比如把VARCHAR(N)改成VARCHAR(M),sqlite不关心括号里的数字。

      第 1 步,您的架构限制为 30 个字符

      CREATE TABLE [TestTable] (
      [Id] INTEGER PRIMARY KEY AUTOINCREMENT,
      [Txt] VARCHAR(30)
      )
      

      下面的行允许 sqlite_table 更改

      PRAGMA writable_schema=ON;
      

      以下语句会将限制更改为 100

      Update sqlite_master set sql='CREATE TABLE [TestTable] (
      [Id] INTEGER PRIMARY KEY AUTOINCREMENT,
      [Txt] VARCHAR(100)
      )' where tbl_name='TestTable' and type='table'
      

      但是您应该知道自己在做什么,因为有些更改是不受欢迎的,因为 sqlite 需要基于架构中的信息的某种存储格式。 varchar 到 varchar 的转换不会改变存储格式

      【讨论】:

      • 这对 sqlite 没有任何意义。与大多数 SQL 数据库不同,SQLite 不会根据声明的列类型来限制可以插入到列中的数据类型。相反,SQLite 使用动态类型。列的声明类型仅用于确定列的亲和性。例如,这种伪造表定义的技巧不适用于 sql 请求。
      • @Arnaud_Bouchez,OP 引用:“我无法访问超过 30 个字符限制的所有字符”。这个技巧正好解决了这个问题,因为解析 sqlite 模式的代码(进行大小限制输入的唯一方法)现在将非常乐意显示 100 以下的所有字符
      • 问题标题明确是关于“Delphi 对 SQLite 清单类型的支持”,截断只是问题的一小部分。基于TDataSet 的 SQLite3 单元(如 UniDac 甚至 XE3 提供的最新 DBExpress 驱动程序)将无法使用此功能。 OP 问题是关于在 Delphi 中使用此功能,不仅修复文本字段截断。问题不在于 SQLite3,而在于 Delphi 方面,如何调用 SQlite3 API 并处理返回的数据。这就是为什么您的答案是正确的,但遗憾的是超出了范围。
      【解决方案3】:

      因为我想要一个非常薄的 sqlite3.dll 包装器,所以我自己编写了一个,主要基于 OleVariants:

      https://github.com/stijnsanders/TSQLite

      它还应该像您描述的那样“忽略”列类型,因为除了查询结果提供的内容之外,我没有添加其他类型检查。

      【讨论】:

      • 为什么使用橄榄变体而不是变体?文本的 BSTR 存储非常慢。但是很好的包装。
      • 好问题,我一直在使用 OleVariants,因为我是通过 COM/ActiveX 了解它们的。
      【解决方案4】:

      需要将输出类型更改为TEXT, 使用CAST

      SELECT cast(column as TEXT) FROM `tablename`
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-16
        • 2010-10-01
        • 2010-10-27
        • 2010-12-07
        • 1970-01-01
        • 2011-04-19
        相关资源
        最近更新 更多