2017-01-07 2 views
2

Я пытаюсь загрузить огромное количество в Field1 INT, который может содержать только max=2,147,483,647, в соответствии с ним я не могу изменить DDL, поэтому попытался найти решение adhoc для вырезания одиночного цифры от середины этого номера, а затем добавить проверку на уникальность.
Эти цифры относятся к следующему: 290000, поэтому я хочу сохранить этот формат с нулями в середине, чтобы легко распознать. Я не хочу вводить какие-либо новые столбцы/таблицы в эту задачу, поскольку это ограничено свободой там, это сторонняя схема.TSQL remap большое число, чтобы уменьшить, но сохранить идентификатор

Может ли кто-нибудь предложить лучшее решение, как переназначить/сохранить все номера под этим лимитом; это мой проект:

DECLARE @fl FLOAT = 290000
DECLARE @I INT 

SELECT @i = (SUBSTRING(CAST(CAST(@fl AS BIGINT) AS VARCHAR(18)),1,4) + 
      SUBSTRING(CAST(CAST(@fl AS BIGINT) AS VARCHAR(18)),7,LEN(CAST(CAST(@fl AS BIGINT) AS VARCHAR(18)))) ) 
select @i; 

ответ

0

Похоже, странная ситуация, не знаю, почему вы должны пойти на все проблемы преобразования большого числа в строку, а затем случайным образом удалить цифру. Более подробная информация о том, почему и в чем заключается реальная цель, будет полезной.

Было сказано, может быть, было бы проще просто вычесть постоянную сумму из этих значений? например .:

DECLARE @fl FLOAT = 290000
DECLARE @I INT 
DECLARE @OFFSET BIGINT = 29000000000 
SET @I = CAST(@fl AS BIGINT)[email protected] 
SELECT @I 

Что дает Вам INT из 1234 как результат, используя ваш пример.

+0

Tx все, Alexei решение лучше для меня, вот что у меня есть: 1. У меня есть как 10K + строк, 2. Это поле должно быть уникальным, 3.Это поле должно соответствовать INT (менее 2147483647). 4. У меня нет никакого контроля, чтобы изменить какой-либо DDL в пункте назначения 6. В идеале я хотел бы сохранить шаблон этих идентификаторов для отслеживания/исследования –

+0

Tx Rocky, он тоже работает, мне просто нужно сохранить этот шаблон, т.е. и последние 3-4 цифры. –

1

Но если вы действительно хотите, чтобы удалить средние цифры, вот другой подход:

DECLARE @fl FLOAT = 290000
DECLARE @I INT 

DECLARE @StringFloat as varchar(80) 
SET @StringFloat = CONVERT(varchar(80), CAST(@fl AS bigint)) 
SET @I = CAST(CONCAT(LEFT(@StringFloat, 4), RIGHT(@StringFloat, 5)) as int) 

SELECT @i; 
0

Следующая создание капель все более широкие блоки цифр от исходного значения третьей стороны и возвращает результаты, которые соответствуют в a INT. Результаты могут быть связаны с существующими данными, чтобы найти подходящее новое значение.

declare @ThirdPartyValue as BigInt = 290000; 
declare @MaxInt as BigInt = 2147483647; 

declare @TPV as VarChar(19) = Cast(@ThirdPartyValue as VarChar(19)); 
declare @TPVLen as Int = Len(@TPV); 

with 
    -- 0 through 9. 
    Digits as (
    select Digit from (values (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) as Digits(Digit)), 
    -- 0 through @TPVLen . 
    Positions as (
    select Ten_1.Digit * 10 + Ten_0.Digit as Number 
     from Digits as Ten_0 cross join Digits as Ten_1 
     where Ten_1.Digit * 10 + Ten_0.Digit <= @TPVLen), 
    -- 1 through @TPVLen - 1 . 
    Widths as (
    select Number 
     from Positions 
     where 0 < Number and Number < @TPVLen), 
    -- Try dropping Width digits at Position from @TPV . 
    AlteredTPVs as (
    select P.Number as Position, W.Number as Width, 
     Stuff(@TPV, P.Number, W.Number, '') as AlteredTPV 
     from Positions as P cross join Widths as W 
     where P.Number + W.Number <= @TPVLen) 
    -- See which results fit in an Int . 
    select Position, Width, AlteredTPV, Cast(AlteredTPV as BigInt) as AlteredTPVBigInt 
    from AlteredTPVs 
    where Cast(AlteredTPV as BigInt) <= @MaxInt -- Comment out this line to see all results. 
    order by Width, Position 

Это может быть более умно для возвращения только новых значений.

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

1

Я думаю, что арифметические операции должны быть дешевле, чем строковые операции, так что вы должны использовать их вместо того, чтобы:

DECLARE @fl FLOAT = 290000
DECLARE @flBig BIGINT = @fl 
DECLARE @i INT 

SET @i = (@flBig/1000000000) * 10000000 + (@flBig % 100000000) 
select @i; --> 2900

При условии примера предполагается, что первая часть числа будет иметь максимум двух цифр (т.е. 29 в ваш случай) и что вы хотите разрешить большее число в левой части (до 999999).

ПРИМЕЧАНИЕ: скобки в являются избыточными, поскольку деление и умножение имеют одинаковый приоритет, а оператор modulo имеет более высокий приоритет перед добавлением. Я использовал их только для выделения частей вычисления.

1

Вы не можете сделать это без какого-либо арифметического переполнения или без потери исходных данных.
Если у вас есть ограничение в столбцах вашей целевой таблицы или запроса, используйте несколько строк:

declare @c bigint = 290000; 
declare @s bigint = 1000000000; -- Separator value 

;with cte(partNo, partValue) as (
    select 1, @c % @s 
    union all 
    select partNo + 1, (@c/power(@s, partNo)) % @s 
    from cte 
    where (@c/power(@s, partNo)) > 0 
) 
select partValue 
from cte; 
Смежные вопросы