SQLite 生成隨機(jī)數(shù)字、字符串、日期、驗(yàn)證碼以及 UUID
作者: 不剪發(fā)的Tony老師
畢業(yè)于北京航空航天大學(xué),十多年數(shù)據(jù)庫管理與開發(fā)經(jīng)驗(yàn),目前在一家全球性的金融公司從事數(shù)據(jù)庫架構(gòu)設(shè)計(jì)。CSDN學(xué)院簽約講師以及GitChat專欄作者。csdn上的博客收藏于以下地址:https://tonydong.blog.csdn.net
文章目錄
生成隨機(jī)數(shù)字
生成 0 到 1 之間的隨機(jī)數(shù)
生成指定范圍內(nèi)的隨機(jī)數(shù)
生成 6 位數(shù)字手機(jī)驗(yàn)證碼
生成遵循正態(tài)分布的隨機(jī)數(shù)
生成隨機(jī)字符串
生成固定長度的隨機(jī)字符串
生成可變長度的隨機(jī)字符串
生成隨機(jī)日期和時(shí)間
獲取表中的隨機(jī)記錄
生成 UUID
總結(jié)
大家好,我是只談技術(shù)不剪發(fā)的 Tony 老師。
今天我們介紹一下如何在 SQLite 中生成隨機(jī)數(shù)據(jù),包括隨機(jī)數(shù)字、驗(yàn)證碼、隨機(jī)字符串以及隨機(jī)日期和時(shí)間等。
如果覺得文章有用,歡迎評論??、點(diǎn)贊??、推薦??
??計(jì)算機(jī)生成的都是偽隨機(jī)數(shù),并不是真正的物理隨機(jī)數(shù)。
生成隨機(jī)數(shù)字
生成 0 到 1 之間的隨機(jī)數(shù)
SQLite 中的RANDOM()函數(shù)可以用于生成一個(gè)大于等于 -9223372036854775808 小于 9223372036854775807 的隨機(jī)整數(shù)。例如:
SELECT RANDOM();
RANDOM() |
--------------------|
-4966318396207630447|
RANDOM() |
-------------------|
2995047221162090652|
該函數(shù)返回的數(shù)據(jù)類型為 INTEGER,每次調(diào)用都會返回不同的結(jié)果。我們可以利用一個(gè)表達(dá)式返回大于等于 0 小于 1 的隨機(jī)浮點(diǎn)數(shù)。例如:
SELECT (RANDOM()+9223372036854775808)/2.0/9223372036854775808 AS rd;
rd |
------------------|
0.9012224701108758|
SELECT (RANDOM()+9223372036854775808)/2.0/9223372036854775808 AS rd;
rd |
------------------|
0.4753244900925889|
生成指定范圍內(nèi)的隨機(jī)數(shù)
基于 RANDOM() 函數(shù)和一些運(yùn)算,就可以返回任意兩個(gè)數(shù)字之間的隨機(jī)數(shù):
low + (RANDOM()+9223372036854775808)/2.0/9223372036854775808 * (high - low)
以上表達(dá)式將會返回一個(gè)大于等于 low,小于 high 的隨機(jī)數(shù)。例如:
SELECT 10 + (RANDOM()+9223372036854775808)/2.0/9223372036854775808 * 10 AS rd;
rd |
------------------|
17.757509471861432|
以上示例返回了一個(gè)大于等于 10 且小于 20 的隨機(jī)數(shù)字。
如果想要生成某個(gè)范圍內(nèi)的隨機(jī)整數(shù),可以加上 FLOOR 函數(shù)。例如:
SELECT FLOOR(10 + (RANDOM()+9223372036854775808)/2.0/9223372036854775808 * 10) AS rd;
rd|
--|
14|
該語句返回了一個(gè)大于等于 10 并且小于 20 的隨機(jī)整數(shù)。
生成 6 位數(shù)字手機(jī)驗(yàn)證碼
我們已經(jīng)知道了如何獲取指定范圍內(nèi)的隨機(jī)數(shù),再加上 printf 格式化函數(shù)就可以生成由 6 位數(shù)字字符組成的手機(jī)驗(yàn)證碼。例如:
SELECT printf('%06d',FLOOR((RANDOM()+9223372036854775808)/2.0/9223372036854775808 * 1000000)) AS captcha;
captcha|
-------|
073998 |
printf 函數(shù)中的格式化參數(shù)可以確保數(shù)據(jù)不夠 6 位時(shí)在前面補(bǔ)足 0。
生成遵循正態(tài)分布的隨機(jī)數(shù)
RANDOM 函數(shù)生成的是一個(gè)遵循均勻分布的隨機(jī)數(shù),SQLite 中沒有提供生成遵循正態(tài)分布(normal distribution)的隨機(jī)數(shù)。我們可以模擬生成遵循正態(tài)分布的隨機(jī)數(shù):
SELECT (sqrt(-2 * log((RANDOM()+9223372036854775808)/2.0/9223372036854775808)) * cos(2 * pi() * (RANDOM()+9223372036854775808)/2.0/9223372036854775808)) * @stdev + @mean;
以上查詢利用 Box-Muller 變換算法通過兩個(gè)平均分布的隨機(jī)數(shù)生成正態(tài)分布的隨機(jī)數(shù),@stdev 是標(biāo)準(zhǔn)差,@mean 是均值。例如,以下查詢生成了一個(gè)均值為 0,標(biāo)準(zhǔn)差為 1 的正態(tài)分布隨機(jī)數(shù):
SELECT (sqrt(-2 * log((RANDOM()+9223372036854775808)/2.0/9223372036854775808)) * cos(2 * pi() * (RANDOM()+9223372036854775808)/2.0/9223372036854775808)) * 1 + 0 AS rd;
rd |
------------------|
0.3057646802078435|
我們可以驗(yàn)證一下這種方式生成的隨機(jī)數(shù)是否遵循正態(tài)分布,例如:
WITH RECURSIVE t(val) AS (
SELECT (sqrt(-2 * log((RANDOM()+9223372036854775808)/2.0/9223372036854775808)) * cos(2 * pi() * (RANDOM()+9223372036854775808)/2.0/9223372036854775808)) * 1 + 0
UNION ALL
SELECT (sqrt(-2 * log((RANDOM()+9223372036854775808)/2.0/9223372036854775808)) * cos(2 * pi() * (RANDOM()+9223372036854775808)/2.0/9223372036854775808)) * 1 + 0
FROM t
LIMIT 1000000
)
SELECT avg(val), stdev(val)
FROM t;
avg(val) |stdev(val) |
------------------|------------------|
0.0001525693454789|1.0004047990494294|
通過運(yùn)行 1000000 次計(jì)算,這些數(shù)據(jù)的平均值和標(biāo)準(zhǔn)差非常接近 0 和 1。
生成隨機(jī)字符串
生成固定長度的隨機(jī)字符串
除了隨機(jī)數(shù)字之外,有時(shí)候我們也需要生成一些隨機(jī)的字符串。SQLite 沒有提供專門生成隨機(jī)字符串的函數(shù),但是可以通過其他函數(shù)進(jìn)行模擬。例如:
SELECT CHAR(FLOOR((RANDOM()+9223372036854775808)/2.0/9223372036854775808 * 26) + 65) AS ch;
ch|
--|
K |
以上查詢返回了一個(gè)隨機(jī)的大寫字母,char 函數(shù)用于將 ASCII 碼轉(zhuǎn)換為對應(yīng)的字符。
我們也可以通用表表達(dá)式返回一個(gè)固定長度的隨機(jī)字符串:
WITH rand_string(n, v, chars) AS (
SELECT 1, '', '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
UNION ALL
SELECT n+1, v||SUBSTR(chars, FLOOR((RANDOM()+9223372036854775808)/2.0/9223372036854775808 * LENGTH(chars)) + 1, 1), chars
FROM rand_string
WHERE n <= 10
)
SELECT v
FROM rand_string
WHERE n = (SELECT MAX(n) FROM rand_string);
v |
----------|
Xx0Bd0A7Vq|
以上查詢返回了一個(gè)由指定字符(所有數(shù)字、大小寫字母)組成、長度為 10 的隨機(jī)字符串。以下語句也可以用于返回一個(gè) 6 位隨機(jī)數(shù)字組成的手機(jī)驗(yàn)證碼:
WITH rand_string(n, v, chars) AS (
SELECT 1, '', '0123456789'
UNION ALL
SELECT n+1, v||SUBSTR(chars, FLOOR((RANDOM()+9223372036854775808)/2.0/9223372036854775808 * LENGTH(chars)) + 1, 1), chars
FROM rand_string
WHERE n <= 6
)
SELECT v
FROM rand_string
WHERE n = (SELECT MAX(n) FROM rand_string);
v |
------|
026723|
生成可變長度的隨機(jī)字符串
那么,怎么返回一個(gè)長度可變的隨機(jī)字符串呢?很簡單,在上面的示例中指定一個(gè)隨機(jī)的長度參數(shù)即可。例如:
WITH rand_string(n, v, chars) AS (
SELECT FLOOR(10 + (RANDOM()+9223372036854775808)/2.0/9223372036854775808 * 10), '', '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
UNION ALL
SELECT n-1, v||SUBSTR(chars, FLOOR((RANDOM()+9223372036854775808)/2.0/9223372036854775808 * LENGTH(chars)) + 1, 1), chars
FROM rand_string
WHERE n > 0
)
SELECT v
FROM rand_string
WHERE n = 0;
v |
-------------|
GDRv44ohcnYxB|
以上示例返回了一個(gè)長度大于等于 10 且小于 20 的隨機(jī)字符串。
生成隨機(jī)日期和時(shí)間
通過 date 函數(shù)將指定日期增加一個(gè)隨機(jī)的天數(shù),就可以得到隨機(jī)的日期。例如:
SELECT date(current_date,'+'||FLOOR((RANDOM()+9223372036854775808)/2.0/9223372036854775808 * 15)||' day') AS rand_date;
rand_date |
----------|
2020-11-04|
以上示例返回了當(dāng)前日期 14 天之內(nèi)的某個(gè)隨機(jī)日期。以下語句通過 time 函數(shù)返回了一天中的某個(gè)隨機(jī)時(shí)間:
SELECT time('00:00:00','+'||FLOOR((RANDOM()+9223372036854775808)/2.0/9223372036854775808 * 86400)||' second') AS rand_time;
rand_time|
---------|
02:42:09 |
獲取表中的隨機(jī)記錄
對于返回多行數(shù)據(jù)的查詢語句,RANDOM 函數(shù)每次都會返回不同的隨機(jī)值。例如:
SELECT random() FROM employee;
random() |
--------------------|
940003262281969703|
-5987940189147449949|
5587923950423690762|
...
利用這個(gè)特性,我們可以從表中返回隨機(jī)的數(shù)據(jù)行。例如:
SELECT emp_id, emp_name
FROM employee
ORDER BY random()
LIMIT 5;
emp_id|emp_name|
------|--------|
17|馬岱 |
24|簡雍 |
3|張飛 |
7|孫尚香 |
19|龐統(tǒng) |
以上示例從 employee 表中返回了 5 行隨機(jī)記錄。該方法需要為表中的每行數(shù)據(jù)都生成一個(gè)隨機(jī)數(shù),然后進(jìn)行排序;所以會隨著表中的數(shù)據(jù)量增加而逐漸變慢。
生成 UUID
UUID(Universal Unique Identifier)或者 GUID(Globally Unique Identifier)是一個(gè) 128 比特的數(shù)字,可以用于唯一標(biāo)識每個(gè)網(wǎng)絡(luò)對象或資源。由于它的生成機(jī)制,一個(gè) UUID 可以保證幾乎不會與其他 UUID 重復(fù),因此常常用于生成數(shù)據(jù)庫中的主鍵值。
SQLite 提供了一個(gè) randomblob(N) 函數(shù),可以用于返回一個(gè) N 字節(jié)的偽隨機(jī)字節(jié) BLOB。利用該函數(shù)和 hex() 函數(shù)可以返回 GUID:
SELECT hex(randomblob(16)) AS guid;
guid |
--------------------------------|
BEA6B419172B9FAECE45883D13935690|
總結(jié)
本文介紹了在 SQLite 中生成隨機(jī)數(shù)據(jù)的方法,包括隨機(jī)數(shù)字、驗(yàn)證碼、隨機(jī)字符串以及隨機(jī)日期和時(shí)間等,同時(shí)還介紹了如何從表中返回隨機(jī)記錄,以及如何生成 UUID。