我需要使用SQL Server生成看似随机的唯一的8位数字 ID(可以在前面填充零)。这是否有内置功能?我看到this Identity
属性,但它是顺序的,而不是随机的。
如果无法做到这一点,那么直接将随机生成的ID写入db然后检查异常是不错的做法? (请注意,我的应用程序是多线程的,因此在写入之前进行检查并不能保证唯一性,除非在原子操作中完成。)
谢谢!
更新:添加"数字"澄清。 编辑表明随机性不需要加密强或任何接近。看似随机就好了。奥利弗提出了一个优雅的解决方案,并且我已经使用这种方法发布了答案。谢谢,奥利弗!
答案 0 :(得分:7)
随机性与唯一性冲突,但@Oliver提出了一个优雅的解决方案,当数字只需要出现随机,而基础订单存在时。从Erics'http://ericlippert.com/2013/11/14/a-practical-use-of-multiplicative-inverses/开始,主要思想是,给定一对互质,正整数x和m,我们可以找到乘法逆 y,其中(x * y)%m = = 1.这非常有用,因为给定数据库行ID z,我们可以通过执行encoded = (z*x) % m
将z映射到另一个整数。现在给出这个encoded
,我们怎样才能得到z?简单,z = (encoded * y) % m
,因为(x*y*z) % m == z
给定z<米这种一对一的对应关系保证了“编码”的唯一性,同时提供了随机性的表现。
请注意,Eric展示了如何计算此乘法逆。但如果你很懒,那就有this。
在我的实现中,我只是按原样存储每行的顺序ID。然后,每个ID都映射到另一个数字,类似于文章中的“InvoiceNumber”。当客户退回此“InvoiceNumber”时,您可以使用乘法反转将其映射回其原始数据库ID。
以下是从0到9的编码和解码序列的C#示例。
public static void SeeminglyRandomSequence()
{ //use long to prevent overflow
long m = 10; //modulo, choose m to be much larger than number of rows
long x = 7; //anything coprime to m
long y = 3; //multiplicative inverse of x, where (y*x) % m == 1
List<long> encodedSequence = new List<long>();
List<long> decodedSequence = new List<long>();
for (long i = 0; i < m; i++)
{
long encoded = (i * x) % m;
encodedSequence.Add(encoded);
}
foreach (long encoded in encodedSequence)
{
long decoded = (encoded * y) % m;
decodedSequence.Add(decoded);
}
Debug.WriteLine("just encoded sequence from 0 to {0}. Result shown below:", (m - 1));
Debug.WriteLine("encoded sequence: " + string.Join(" ", encodedSequence));
Debug.WriteLine("decoded sequence: " + string.Join(" ", decodedSequence));
}
打印结果为:
just encoded sequence from 0 to 9. Result shown below:
encoded sequence: 0 7 4 1 8 5 2 9 6 3
decoded sequence: 0 1 2 3 4 5 6 7 8 9
如您所见,每个输入都映射到一个唯一的输出,并且很容易反转此映射。在您的应用程序中,您可能希望从1开始,因为0始终映射到自身。
为了显示较大m的“明显随机性”,下面是m = 100,000,000时的前10个映射:
just encoded sequence from 1 to 10. Result shown below:
encoded sequence: 81654327 63308654 44962981 26617308 8271635 89925962 71580289 53234616 34888943 16543270
decoded sequence: 1 2 3 4 5 6 7 8 9 10
答案 1 :(得分:0)
你可以使用NEWID()来生成每次都是随机且唯一的uniqueIdentifier数据
要获得8个字符,您可以使用子字符串,左等功能。
select substring( cast( NEWID() as varchar(100)),0,8)
或唯一性的新逻辑: - http://forums.asp.net/t/1474299.aspx?How+to+generate+unique+key+of+fixed+length+20+digit+in+sql+server+2005+
select Left(NewID(),4)+Right(NewId(),4)
您也可以使用random()功能。
检查此链接: How do I generate random number for each row in a TSQL Select?
How to get numeric random uniqueid in SQL Server
<强>更新强> 如果你想要唯一值int数据类型和8个字符长。很好地制作如下所示的标识列,这对于8个字符长度的数据意味着(10,000,000)。但在那之后它会给你例外。所以要小心你想要的逻辑。(我仍然说,这是个坏主意)。存储如上所述的随机值,具有更长的长度,因此具有唯一性。
create table temp (id numeric(8,0) IDENTITY(1,1) NOT NULL, value1 varchar ) --if you want do not stop after 8 character , give int datatype.
insert into temp values( 'a'), ('b'), ('c')
select * from temp
drop table temp
最后
它不保证唯一,但很难通过NEWID()获得重复(参见上面的链接forums.asp.net)
答案 2 :(得分:0)
使用以下查询创建8位随机唯一编号。
SELECT CAST(RAND() * 100000000 AS INT) AS [RandomNumber]
为了避免在查询下方将现有号码插入数据库时出现异常。
IF NOT EXIST(SELECT UniqueColumnID FROM TABLENAME WHERE UniqueColumnID = @RandowNumber)
BEGIN
--Insert query using @RandowNumber.
END
答案 3 :(得分:0)
创建SQL函数或过程,如下所示:
ALTER FUNCTION [dbo].[GenerateRandomNo]
(
@Lower INT = 111111111,
@Upper INT = 999999999
)
RETURNS NVARCHAR(128)
AS
BEGIN
DECLARE @TempRandom FLOAT
DECLARE @Random NVARCHAR(128);
-- Add the T-SQL statements to compute the return value here
SELECT @TempRandom = RandomNo from RandomNo
SELECT @Random = CONVERT(NVARCHAR(128),CONVERT(INT,ROUND(((@Upper - @Lower -1) * @TempRandom + @Lower), 0)))
WHILE EXISTS(SELECT * FROM Table WHERE Column = @Random)
BEGIN
SELECT @TempRandom = RandomNo from RandomNo
SELECT @Random = CONVERT(NVARCHAR(128),CONVERT(INT, ROUND(((@Upper - @Lower -1) * @TempRandom + @Lower), 0)))
END
-- Return the result of the function
RETURN @Random
END
如果要生成具有特定长度或范围的随机数,则调用该函数传递参数。
答案 4 :(得分:0)
--create
-- table Tbl( idx int)
DECLARE
@unique_id int
SET @unique_id= ( SELECT ROUND( 89999999 * RAND(
) + 10000000 , 0
)
)
IF not EXISTS( SELECT idx
FROM tbl
WHERE idx = @unique_id
)
BEGIN
INSERT INTO tbl( idx
)
VALUES( @unique_id
)
SELECT @unique_id, * FROM tbl
END;
--TRUNCATE TABLE tbl