【问题标题】:Can I use anything other than BIGINT as Primary Key data type in SQLite?我可以使用 BIGINT 以外的任何东西作为 SQLite 中的主键数据类型吗?
【发布时间】:2010-06-08 20:37:46
【问题描述】:

我对在开发过程中使用 SQLite 作为数据库解决方案的可能性感到兴奋,这样我就可以专注于首先编写代码并在运行时使用 NHibernate 的 ShemaExport 功能动态生成数据库。但是,我遇到了一些问题,其中最重要的是 SQLite 似乎要求我使用 Int64 作为我的主键(例如,Int32 或 Guid)。有没有办法解决这个问题?

注意:我应该指定这是在使用 NHibernate 的应用程序的上下文中。严格来说,不能在 SQLite 中创建具有 INT 数据类型的表,但保存和检索数据时的行为似乎表明它被存储和/或检索为 Int64。

【问题讨论】:

    标签: sqlite


    【解决方案1】:

    SQLite 允许您将表中的任何字段用作PRIMARY KEY。这样做会隐式地在该字段上创建一个UNIQUE 索引。然后,作为开发人员,您可以将此字段视为该字段的主要唯一标识符。它可以是任何受支持的 SQLite 数据类型(如下)。

    SQLite 将始终为每个表创建一个隐式的内部数字标识符。它将有几个别名,包括RowIDOID_ROWID_。如果您将主键创建为 INTEGER PRIMARY KEY,那么它将使用与您的主键和 SQLite 的内部数字标识符相同的字段。

    SQLite 没有 Int32 或 Int64 或 Guid 数据类型的概念。它只有四种数据类型:INTREALTEXTBLOB。当你对 SQLite 运行 DDL 时,如果你使用这四个标识符以外的任何东西,SQLite 将使用一组规则来确定要使用的类型。基本上,Int32Int64 被视为 INT 的别名并最终做完全相同的事情。

    即使您使用为每个字段提到的数据类型创建了表,您设置的只是该字段的类型关联。 SQLite 不强制执行数据类型。无论声明的类型如何,任何数据都可以放入任何字段。如果可能,SQLite 将使用类型关联来转换数据,因此如果将“123”作为文本字符串插入到INT 字段中,它将存储为数字 123。

    类型关联的唯一例外是INTEGER PRIMARY KEY FIELDS。这些必须是整数。

    SQLite 中的整数始终与可变长度字段一起存储。因此,根据整数的大小,您实际上可能会为某些行返回 Int32,而为其他行返回 Int64,所有这些都在同一个字段中。这取决于您使用的包装器,在本例中为 NHibernate(我猜是 System.Data.SQLite)。

    【讨论】:

    • 只是为了结束这个循环,我已将此标记为已接受的答案,因为它确实解决了帖子的标题。现在我知道更多了,我问错了问题。问题是,当您在 SQLite 中使用 INT 数据类型并在代码中检索它(C#,无论如何),它返回为 Int64,因此您的属性必须声明为 long 以避免 InvalidCast 异常(或者,我猜,如果您使用 NHIbernate 或其他 ORM 并显式进行强制转换,您可以做额外的工作来拦截对象检索)。
    【解决方案2】:

    它不要求您使用 Int64,但是,它可能仅在您指定数字主键时才允许。因为 sqlite 并没有真正的引用完整性检查(尽管最近对此进行了讨论,也许 hipp 博士甚至已经实现了,但我最近没有检查过),所有主键意味着“使该列唯一并在它”。它没有什么特别之处。您当然可以使用 varchar 或 text 作为主键。例如,这有效:

    create table t_test (
           theID varchar(36) primary key,
           nm varchar(50)
           )
    

    在上面,您可以使用 ID 以文本形式存储 guid。

    更多信息可以在这里找到:http://www.sqlite.org/lang_createtable.html#rowid

    @weenet ... per your comments, the following code works just fine. 
    

    如果您仍然遇到问题,我认为您需要发布您的代码。

    create table t_test2 (
           theID int32 primary key,
           nm varchar(50)
           );
    insert into t_test2 (theID, nm) values (1, 'don');
    insert into t_test2 (theID, nm) values (2, 'weenet');
    select * from t_test2;
    

    此外,这段代码运行良好(varchar 作为主键):

    create table t_test (
           theID varchar(36) primary key,
           nm varchar(50)
           )
    
    insert into t_test (theID, nm) values ('abcdefg', 'don');
    insert into t_test (theID, nm) values ('hijklmnop', 'weenet');
    select * from t_test
    

    【讨论】:

    • 哦,我应该说我试过这个:create table t_test2 ( theID int32 primary key, nm varchar(50) ) 它工作得很好,所以我想我需要一个创建的样本您用于探索问题的进一步解决方案的声明。
    • 尝试用这样的键创建一个对象,保存并检索它。我相信您会在尝试将 Int64 转换为 Int32 时遇到错误。
    • SQLite 在版本 3.6.19 (2009-10-14) 中增加了对外键的支持。
    • -1 用于 varchar(36)varchar(50)int32 这似乎表明 SQLite 实际上对这些类型的意义比它更大。 SQLite 仅支持TEXTINTREALNULL 数据。其他所有内容都只是在内部翻译成其中之一。
    • @Don Dickinson,OP 似乎对 SQLite 如何处理数据类型存在误解,我认为您的代码示例强化了这种误解。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-05
    • 2014-12-24
    • 2012-10-05
    • 2013-07-12
    相关资源
    最近更新 更多