2012-06-24 4 views
4

Я извлекаю подписанный int из базы данных SQL Server и должен преобразовать его в «обычную» строку с точками для отображения пользователям.Преобразование подписанного int для строкового ip-адреса в SQL Server

Googling, я нашел этот код:

SELECT 
    dbo.IPADDRESS.IPADDRESS, 
    CAST(ROUND((cast(dbo.IPADDRESS.IPADDRESS as bigint)/16777216), 0, 1) AS varchar(4)) + '.' + 
    CAST((ROUND((cast(dbo.IPADDRESS.IPADDRESS as bigint)/65536), 0, 1) % 256) AS varchar(4)) + '.' + 
    CAST((ROUND((cast(dbo.IPADDRESS.IPADDRESS as bigint)/256), 0, 1) % 256) AS varchar(4)) + '.' + 
    CAST((cast(dbo.IPADDRESS.IPADDRESS as bigint) % 256) AS varchar(4)) as IPDottedNotation 
FROM 
    dbo.IPADDRESS 

который работает некоторое время, но производит дурацкие выходные другие времена. Например, преобразование этого -1951276725 дает результат -116.-78.-30.-181.

Любые предложения? Благодарю.

ответ

8
DECLARE @IPADDRESS TABLE (
    IPADDRESS INT); 

INSERT INTO @IPADDRESS 
VALUES  (-1139627840), 
      (1); 

SELECT 
     LTRIM(CAST(SUBSTRING(IP,4,1) AS TINYINT)) + '.' + 
     LTRIM(CAST(SUBSTRING(IP,3,1) AS TINYINT)) + '.' + 
     LTRIM(CAST(SUBSTRING(IP,2,1) AS TINYINT)) + '.' + 
     LTRIM(CAST(SUBSTRING(IP,1,1) AS TINYINT)) 
FROM @IPADDRESS 
CROSS APPLY (SELECT CAST(IPADDRESS AS BINARY(4))) C(IP) 

enter image description here

+1

+1 намного более аккуратный, чем код OP –

+0

Я новичок MSSQL, и я изо всех сил пытаюсь понять, что здесь происходит. Кто-нибудь хочет «рассказать» меня. – jalperin

+2

@jalperin 'CROSS APPLY' отличает 4 байтовое целое к 4-байтовому двоичному. Результат этого выражения затем сглаживается как «IP». Это просто, чтобы не потребоваться повторить бросок на двоичные четыре отдельных раза. 'SUBSTRING (IP, 1,1)' извлекает первый байт из этого, 'SUBSTRING (IP, 2,1)' второй и так далее. Это будет в диапазоне от 0x00 до '0xFF', приведение к' tinyint' преобразует в десятичную форму. «LTRIM» используется для перевода результата в строку, чтобы он мог быть объединен в пунктирную форму. Более кратким, чем 'CAST (CAST (SUBSTRING (IP, 1,1) AS TINYINT) AS VARCHAR (3))' –

3

Код, который у вас есть, будет работать, если IPADDRESS был bigint (эффективно сохраняя неподписанное представление int в базе данных - то есть все значения> 0). У вас есть возможность изменить тип данных в таблице?

Чтобы получить то, что вам нужно для работы, вам необходимо преобразовать подписанный int в эквивалентный unsigned int перед преобразованием в bigint. Я не уверен, что самый эффективный способ сделать это в TSQL есть, но это может быть, чтобы бросить его в двоичную:

SELECT dbo.IPADDRESS.IPADDRESS, 
CAST(ROUND((cast(cast(dbo.IPADDRESS.IPADDRESS as binary(4)) as bigint)/16777216), 0, 1) AS varchar(4)) + '.' + 
CAST((ROUND((cast(cast(dbo.IPADDRESS.IPADDRESS as binary(4)) as bigint)/65536), 0, 1) % 256) AS varchar(4)) + '.' + 
CAST((ROUND((cast(cast(dbo.IPADDRESS.IPADDRESS as binary(4)) as bigint)/256), 0, 1) % 256) AS varchar(4)) + '.' + 
CAST((cast(cast(dbo.IPADDRESS.IPADDRESS as binary(4)) as bigint) % 256) AS varchar(4)) as IPDottedNotation 
+0

Это, кажется, работает; благодаря! – jalperin

+0

IP-байты почему-то перевернуты в моем случае, но проблем нет. Отлично работает – Ondra

0

Как @Ed Харпер заявил, что выбранный решение не работает для подписанного int. Ниже мое решение, которое требует немного меньше кастинга и не инвертируется. Проверьте приведенный ниже сценарий тестирования, где преобразованная строка/varchar IP должна быть 192.168.18.188:

CREATE TABLE #data 
    (
    ip  NVARCHAR(45), 
    before NVARCHAR(45) 
) 

INSERT INTO #data 
VALUES  ('converted-ip','-1139627840') 

    update #data 
    set ip = cast((cast(before as int) & 255) as nvarchar) + '.' + 
     cast((cast(floor(convert(decimal, before)/256) as int) & 255) as nvarchar) + '.' + 
     cast((cast(floor(convert(decimal, before)/65536) as int) & 255) as nvarchar) + '.' + 
     cast((cast(floor(convert(decimal, before)/16777216) as int) & 255) as nvarchar) 

select * from #data 
Смежные вопросы