SQLite 生成隨機(jī)數(shù)字、字符串、日期、驗(yàn)證碼以及 UUID

作者: 不剪發(fā)的Tony老師
畢業(yè)于北京航空航天大學(xué),十多年數(shù)據(jù)庫(kù)管理與開(kāi)發(fā)經(jīng)驗(yàn),目前在一家全球性的金融公司從事數(shù)據(jù)庫(kù)架構(gòu)設(shè)計(jì)。CSDN學(xué)院簽約講師以及GitChat專(zhuān)欄作者。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ī)字符串
            生成固定長(zhǎng)度的隨機(jī)字符串
            生成可變長(zhǎng)度的隨機(jī)字符串
        生成隨機(jī)日期和時(shí)間
        獲取表中的隨機(jī)記錄
        生成 UUID
        總結(jié)

今天我們介紹一下如何在 SQLite 中生成隨機(jī)數(shù)據(jù),包括隨機(jī)數(shù)字、驗(yàn)證碼、隨機(jī)字符串以及隨機(jī)日期和時(shí)間等。


    ??計(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ù)類(lèi)型為 INTEGER,每次調(diào)用都會(huì)返回不同的結(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á)式將會(huì)返回一個(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|



該語(yǔ)句返回了一個(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 中沒(méi)有提供生成遵循正態(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;

    1

以上查詢(xún)利用 Box-Muller 變換算法通過(guò)兩個(gè)平均分布的隨機(jī)數(shù)生成正態(tài)分布的隨機(jī)數(shù),@stdev 是標(biāo)準(zhǔn)差,@mean 是均值。例如,以下查詢(xún)生成了一個(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|

 

通過(guò)運(yùn)行 1000000 次計(jì)算,這些數(shù)據(jù)的平均值和標(biāo)準(zhǔn)差非常接近 0 和 1。
生成隨機(jī)字符串
生成固定長(zhǎng)度的隨機(jī)字符串

除了隨機(jī)數(shù)字之外,有時(shí)候我們也需要生成一些隨機(jī)的字符串。SQLite 沒(méi)有提供專(zhuān)門(mén)生成隨機(jī)字符串的函數(shù),但是可以通過(guò)其他函數(shù)進(jìn)行模擬。例如:

SELECT CHAR(FLOOR((RANDOM()+9223372036854775808)/2.0/9223372036854775808 * 26) + 65) AS ch;
ch|
--|
K |


以上查詢(xún)返回了一個(gè)隨機(jī)的大寫(xiě)字母,char 函數(shù)用于將 ASCII 碼轉(zhuǎn)換為對(duì)應(yīng)的字符。

我們也可以通用表表達(dá)式返回一個(gè)固定長(zhǎng)度的隨機(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|

   

以上查詢(xún)返回了一個(gè)由指定字符(所有數(shù)字、大小寫(xiě)字母)組成、長(zhǎng)度為 10 的隨機(jī)字符串。以下語(yǔ)句也可以用于返回一個(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|

 
生成可變長(zhǎng)度的隨機(jī)字符串

那么,怎么返回一個(gè)長(zhǎng)度可變的隨機(jī)字符串呢?很簡(jiǎn)單,在上面的示例中指定一個(gè)隨機(jī)的長(zhǎng)度參數(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è)長(zhǎng)度大于等于 10 且小于 20 的隨機(jī)字符串。
生成隨機(jī)日期和時(shí)間

通過(guò) 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ī)日期。以下語(yǔ)句通過(guò) 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ī)記錄

對(duì)于返回多行數(shù)據(jù)的查詢(xún)語(yǔ)句,RANDOM 函數(shù)每次都會(huì)返回不同的隨機(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|簡(jiǎn)雍    |
     3|張飛    |
     7|孫尚香  |
    19|龐統(tǒng)    |

 

以上示例從 employee 表中返回了 5 行隨機(jī)記錄。該方法需要為表中的每行數(shù)據(jù)都生成一個(gè)隨機(jī)數(shù),然后進(jìn)行排序;所以會(huì)隨著表中的數(shù)據(jù)量增加而逐漸變慢。
生成 UUID

UUID(Universal Unique Identifier)或者 GUID(Globally Unique Identifier)是一個(gè) 128 比特的數(shù)字,可以用于唯一標(biāo)識(shí)每個(gè)網(wǎng)絡(luò)對(duì)象或資源。由于它的生成機(jī)制,一個(gè) UUID 可以保證幾乎不會(huì)與其他 UUID 重復(fù),因此常常用于生成數(shù)據(jù)庫(kù)中的主鍵值。

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。