2016-03-12 3 views
0

Этот вопрос связан с этим thread, не уверен, что я должен опубликовать этот новый вопрос в этом сообщении или создать новое сообщение, но был обеспокоен тем, что он не может рассматриваться как следующий вопрос в старом столбце ...Генерировать уникальные случайные идентификаторы, циклические по таблице SQL

  • Мне нужно заменить кучу идентификаторов случайными, но уникальными новыми в таблице SQL.
  • Я использую код t-clausen.dk из этого thread, чтобы сгенерировать новые идентификаторы.
  • Я использую временную таблицу для повторения старых идентификаторов, создания нового идентификатора, а затем обновления таблицы с новым идентификатором. (эта часть решения в этом thread)
  • Моя проблема в том, что все новые идентификаторы в конечном итоге совпадают. Как я могу получить @r для очистки, чтобы он мог генерировать новый номер?
  • Или есть лучший способ решить эту проблему в целом? Скажите, не зацикливая ...?

    SELECT * INTO #ControlTable FROM tempmaster 
    DECLARE @ei varchar(max) 
    DECLARE @r varchar(8) 
    
    WHILE EXISTS (SELECT * FROM #ControlTable) 
    BEGIN 
        SELECT @ei = (SELECT TOP 1 externalid FROM #ControlTable ORDER BY externalid ASC) 
    
        -- CREATE UNIQUE RANDOM ID 
        SELECT @r = coalesce(@r, '') + n 
        FROM (SELECT top 8 
        CHAR(number) n FROM 
        master..spt_values 
        WHERE type = 'P' AND 
        (number between ascii(0) and ascii(9) 
        or number between ascii('A') and ascii('Z') 
        or number between ascii('a') and ascii('z')) 
        ORDER BY newid()) a 
    
        -- REPLACE OLD ID 
        UPDATE tempmaster SET externalid = @r WHERE externalid = @ei 
    
        DELETE #ControlTable WHERE externalid = @ei 
    
        /*TESTING*/ 
        --SELECT @ei AS EI, @r AS [newID] 
        --SELECT * FROM #ControlTable 
        --SELECT * FROM tempmaster WHERE externalid = @ei OR externalid = @r 
    END 
    
    drop table #ControlTable 
    

ЗДЕСЬ Очерк Попытки подстроено ПОДХОДОМ

DECLARE @r varchar(8); 
    SELECT oid, startdate, enddate, 
     coalesce(@r, '') + n 
     FROM (SELECT TOP 8 
     CHAR(number) n FROM 
     master..spt_values 
     WHERE type = 'P' AND 
     (number between ascii(0) and ascii(9) 
     or number between ascii('A') and ascii('Z') 
     or number between ascii('a') and ascii('z')) 
     ORDER BY newid()) 
    as externalid 
    FROM MasterTable 
+0

Является ли ваш оригинальный внешний вид уже уникальным? – trincot

+0

да оригинальный идентификатор является уникальным varchar – dharol

ответ

1

Я не тестировал это, но вы могли бы заменить цикл на этот UPDATE. Это требует текущих enternalid значения должны быть уникальными:

WITH cte AS (
    SELECT 
     externalid, 
     concat(
      substring(chars, num % 62, 1), 
      substring(chars, (num/62) % 62, 1), 
      substring(chars, (num/3844) % 62, 1), 
      substring(chars, (num/238328) % 62, 1), 
      substring(chars, (num/14776336) % 62, 1), 
      substring(chars, (num/916132832) % 62, 1), 
      substring(chars, (num/56800235584) % 62, 1), 
      substring(chars, (num/3521614606208) % 62, 1) 
     ) AS unique_string8 
    FROM (
     SELECT 
      externalid, 
      (rn * 34524689549219 + seed) % 199689672115897 AS num, 
      'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' AS chars 
     FROM (
      SELECT externalid, 
        ROW_NUMBER() OVER (ORDER BY externalid) AS rn, 
        0 AS seed 
      FROM tempmaster 
     ) AS subq1 
    ) AS subq2 
) 
UPDATE  t 
SET  externalid = cte.unique_string8 
FROM  tempmaster t 
INNER JOIN cte 
     ON cte.externalid = t.externalid; 

Идея заключается в том, что КТР запрос отображает существующую ExternalId с новым ключом 8 символов, а затем выполняет обновление с помощью этого отображения ,

Символы взяты из буквенной строки с 62 возможными символами. Значение num является кратным пробелу плюс некоторое семя (в данном случае 0) и удерживается в пределах, беря по модулю простое число, которое близко к числу возможных строк с 8 символами.

Это итоговое число затем преобразуется в строку с 8 символами, как если бы число было представлено на 62-основе. Знаменатели в формуле имеют степень 62.

Таким образом, гарантируется, что вы никогда не получите дубликат (если у вас нет больше записей, чем возможные 8-буквенные комбинации).

Не существует случайной части, поэтому она будет производить всегда одну и ту же серию, но вы можете изменить значение seed для любого целого числа, чтобы изменить серию, которая будет создана.

+0

это сработало - спасибо! – dharol

2

Хотя ваш цикл не так, как я бы подойти к решению проблемы (подход на основе набора значительно лучше), ваша проблема в том, что вы не перезапускаете @r внутри цикла.

Итак, добавьте:

set @r = NULL; 

к началу цикла.

+0

doh, спасибо. как будет работать подход на основе набора? опубликует редактирование в оригинальном посте, показывая, что я пробовал – dharol

+0

@dharol. , , Можете ли вы задать другой вопрос? Ответ совсем не похож на этот вопрос. –

+0

Вы хотите сказать, что я должен задать вопрос в новой теме? – dharol

Смежные вопросы