看到園子里一位朋友用newid()寫的,(這里是原文):
insert into T select top 10000 replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(lower(left(replace(newid(), '-', ''), 20)), '0', 'a'), 1, 'b'), 2, 'c'), 3, 'd'), 4, 'e'), 5, 'f'), 6, 'g'), 7, 'h'), 8, 'i'), 9, 'j') as col from sys.all_columns , sys.all_objects
這里newid()產生一個GUID, 形如"F6BCE480-834B-4FB9-B905-B568B9F9C7A3", (32個字母和數字加4條橫線), 理論上是沒有重復的. 問題在於, 當把其中的數字轉換成字母之后, 產生的字母序列中一個字母可能對應GUID的一個字母, 也可能對應的是一個數字. 換句話說, 當把這個字母序列"翻譯"回GUID的時候, 它最多可以對應到2的32次方個不同的GUID, (拿計算器算了下: 4,294,967,296個). 這樣先不說出現重復的概率大不大, 至少理論上不能保證說不出現重復的.
其實, 0到10000, 這數字本身就是不重復的, 干脆把他們轉換成字母就好了. 這是方法一:
declare @n int set @n = 0; while @n<10000 begin print replace(replace(convert(varchar(5), @n), '0', 'a'), '1', 'b') ---replace('2', 'c').... set @n = @n+1 end
上面看到的是a, b, c...h, i, j十個字母的組合, 是不是可以用26個字母? 當然是可以的. 不妨把十進制轉換成"二十六進制": a = 0, b = 1 .... z = 25. 那么, ba = 26. 好, 沒問題, 可以這樣:
declare @one int, @n int, @res varchar(5) set @n = 20 -- test if (@n = 0) set @res = 'a'; else set @res = '' while @n > 0 begin set @one = @n%26 set @res = CHAR(@one+97) + @res set @n = @n/26 end print @res
上面解決了"二十六進制"的問題. 我們還知道while循環是可以嵌套的, 於是, 可以用"二十六進制"來表示10000個編號. 方法二:
declare @n int set @n = 0 while @n < 10000 begin declare @one int, @num int, @res varchar(5) set @num = @n if (@num = 0) set @res = 'a' else set @res = '' while @num>0 begin set @one=@num%26 set @res = CHAR(@one+97) + @res set @num = @num/26 end print @res set @n = @n+1 end
另外, SQL SERVER 2008開始提供表值函數:
select ch from ( values ('a'), ('b'), ('c'), ('d'), ('e'), ('f'), ('g'), ('h'), ('i'), ('j'), ('k'), ('l'), ('m'), ('n'), ('o'), ('p'), ('q'), ('r'), ('s'), ('t'), ('u'), ('v'), ('w'), ('x'), ('y'), ('z') ) as char_table(ch)
不妨考慮用26個字母作個交叉連接, 26*26*26 = 17576, 三張表足夠了. 方法三:
with chars as ( select ch from ( values ('a'), ('b'), ('c'), ('d'), ('e'), ('f'), ('g'), ('h'), ('i'), ('j'), ('k'), ('l'), ('m'), ('n'), ('o'), ('p'), ('q'), ('r'), ('s'), ('t'), ('u'), ('v'), ('w'), ('x'), ('y'), ('z') ) as char_table(ch) ) select a.ch, b.ch, c.ch, (a.ch+b.ch+c.ch) as rn from chars as a cross join chars as b cross join chars as c -- results ch ch ch rn ---- ---- ---- ---- a a a aaa a b a aba a c a aca a d a ada ....
可以看到它從第二列開始遞增, 我們想讓它從第三列開始:
with chars as ( select ch from ( values ('a'), ('b'), ('c'), ('d'), ('e'), ('f'), ('g'), ('h'), ('i'), ('j'), ('k'), ('l'), ('m'), ('n'), ('o'), ('p'), ('q'), ('r'), ('s'), ('t'), ('u'), ('v'), ('w'), ('x'), ('y'), ('z') ) as char_table(ch) ), bc as (select c1.ch as chb, c2.ch as chc from chars as c1 cross join chars as c2), abc as (select ch as cha, chb, chc from chars cross join bc) select top 10000 cha, chb, chc, (cha+chb+chc) as rn from abc -- results cha chb chc rn ---- ---- ---- ---- a a a aaa a a b aab a a c aac a a d aad ....
好了, 吃飯去啦!