在SQLite中使用UUIDs

111

在SQLite中是否可以使用UUID作为主键?有关该主题的信息非常有限,因此我不确定SQLite是否支持UUID数据类型。我应该将UUID存储为字符串吗?

5个回答

70
CL的答案是正确的,但有点绕过了问题的核心。如前所述,任何类型的列(或多个列)都可以用作主键。因此,您可以将UUID存储为格式化的、可读的字符串,并将其作为表的键。而且,由于UUID只是一个128位整数,您还可以将整数的字节存储为BLOB,这样可以节省空间并且可能会稍微快一些。

但是为了更直接回答我认为是问题的核心,不,SQLite没有任何直接支持UUID的功能。当SQLite创建一个表时,它使用列声明的类型来确定使用五种底层存储类(整数、实数、文本、二进制大对象或空)中的哪一种。表创建后,列的类型不再使用,列的行为完全由其存储类确定。没有特定于UUID的列类型或存储类。也似乎没有可用于转换为和从格式化的UUID字符串的函数。要获取UUID的字节,您需要查看应用程序所使用语言提供的方法。例如,Java的UUID类,Apple的NSUUID,或Swift的UUID


63

SQLite允许将任何数据类型用作主键。

UUID可以存储为字符串(可读性强)或16字节的BLOB(如果记录小到足以影响速度,则该方法可能更快)。


这两种数据类型中,哪一种更适合存储UUID以提高效率? - Mike Baxter
5
其他读者请注意:这个36位十六进制字符串的人类可读形式如下:988097c8-3f9c-4ecf-9d1d-64701bb9764c - Basil Bourque
8
UUID作为BLOB类型和TEXT类型的区别在于它们所占用的文件大小,但是它们在插入和查询速度方面几乎相同。详见https://dev59.com/HGgu5IYBdhLWcg3wbGel#11337522 - xmedeko

23

1
你如何添加一个扩展? - amadesclaire
4
有些繁琐...详细信息请参见此处 https://www.sqlite.org/loadext.html#:~:text=An%20SQLite%20extension%20is%20a,using%20the%20sqlite3_load_extension()%20API. - DrGo
1
下载文件后,运行gcc -g -fPIC -dynamiclib uuid.c -o uuid.c.dylib。然后在sqlite3中执行SELECT load_extension('uuid.c'); - zvxr

9

我需要在sqlite中实现UUID,但这不是它的本地功能,所以我在互联网上找到了一个技巧。

SQLite不支持UUID,因此想法是创建一个函数,使用randomblob()函数生成UUID。

select lower(hex( randomblob(4)) || '-' || hex( randomblob(2))
         || '-' || '4' || substr( hex( randomblob(2)), 2) || '-'
         || substr('AB89', 1 + (abs(random()) % 4) , 1)  ||
         substr(hex(randomblob(2)), 2) || '-' || hex(randomblob(6))) 

这将确保您拥有一个可以存储在表中的UUID,其类型为varchar,现在开始实施。SQLite不存储函数,因此您可以使用触发器,在您的表中插入新记录时调用它。

CREATE TABLE UUID_TABLE(
   id varchar(500),
   name varchar(500) NOT NULL,
   CONSTRAINT name_unique UNIQUE (name),
   CONSTRAINT rid_pkey PRIMARY KEY (id)
);

并且触发器

CREATE TRIGGER AutoGenerateGUID_RELATION_3
AFTER INSERT ON UUID_TABLE
FOR EACH ROW
WHEN (NEW.relation_id IS NULL)
BEGIN
   UPDATE UUID_TABLE SET relation_id = (select lower(hex( randomblob(4)) || '-' ||      hex( randomblob(2))
             || '-' || '4' || substr( hex( randomblob(2)), 2) || '-'
             || substr('AB89', 1 + (abs(random()) % 4) , 1)  ||
             substr(hex(randomblob(2)), 2) || '-' || hex(randomblob(6))) ) WHERE rowid = NEW.rowid;
END;

每当插入一行新数据时,默认情况下会将 NULL 值赋给 id,然后触发器会将其修改为作为 varchar 存储的新 UUID 值。灵感来源于:解决方案源

5
我的意思是在 SQLite 中没有定义 UUID 作为数据类型,可以查看 https://www.sqlite.org/datatype3.html。 被接受的答案建议将 UUID 存储为字符串类型在 SQLite 中。 与支持 UUID 作为数据类型的 PostgreSQL 不同,这一点可以帮助您自动生成 UUID。 - Idhem
1
@NicoHaase,那个被接受的答案字面上说:UUID可以存储为字符串或二进制大对象。也就是说:在sqlite中没有对UUID的一流支持。有很多方法可以解释kaygi22所说的话,但你可以合理地将其解释为明智的。 - hraban
对于大量小记录,将UUID作为字符串存储将占用不成比例的存储空间 - 这对索引来说可能也不是最优的。我认为,通过存储128位(16字节)的二进制数据块,并使用类似的技术,但使用位运算符创建有效的UUID v4位 - 然后在客户端层中转换为/从格式化字符串,您可以做得更好。 - mindplay.dk

3

不确定是否将其用作默认字段,但如果有人需要在sqlite查询中生成唯一值,则可以使用此处建议的方法:

randomblob(N)函数返回一个包含伪随机字节的N字节Blob。 如果N小于1,则返回1字节的随机Blob。 提示:应用程序可以使用此函数与hex()和/或lower()一起生成全局唯一标识符,如下所示:

hex(randomblob(16)) 

或者

lower(hex(randomblob(16))) 

15
UUID不是“randomblob(16)”,请参考https://dev59.com/D2kw5IYBdhLWcg3wJXMh#22725697。如果您不需要精确的UUID,则“randomblob”就足够了。 - xmedeko
13
伪随机字节与 UUID 不同。 - Bill

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接