views:

2120

answers:

14

What should be the most recommended datatype for storing an IPv4 address in SQL server?

Or maybe someone has already created a user SQL data-type (.Net assembly) for it?

I don't need sorting.

A: 

Store IP addresses in a CHAR(15) column. Depending on how much data you're storing, this can be quite wasteful (why do we need to store the dots?). I

joe
"this can be quite wasteful" Unless you are storing all the IPs in the world, I think it better to store it with the dots. "Premature optimization is the root of all evil"
tekBlues
You need to store the dots because otherwise you wouldn't be able to tell the difference between 127.1.1.10 and 127.1.11.0 both would be stored as 1271110. I suppose you could store it as 4 separate byte fields, but unless you are really concerned about space saving for lots of data I don't think it's worth the extra effort (and processing to put it back together).
Simon P Stevens
"12121212" is this 12.12.12.12 or 12.121.2.12 or maybe 12.121.21.2 or ....
Kyle Sonaty
you could ignore the dots if you were padding the value, ie 127.1.1.10 would become 127001001010
phsr
@tekBlues: "Premature optimization" is good database design.
gbn
+3  A: 

I'd probably go with a varchar or char.

And set the size to 15.

Simon P Stevens
+12  A: 

I normally just use varchar(15) for IPv4 addresses - but sorting them is a pain unless you pad zeros.

I've also stored them as an INT in the past. System.Net.IPAddress has a GetAddressBytes method that will return the IP address as an array of the 4 bytes that represent the IP address. You can use the following C# code to convert an IPAddress to an int...

var ipAsInt = BitConverter.ToInt32(ip.GetAddressBytes(), 0);

I had used that because I had to do a lot of searching for dupe addresses, and wanted the indexes to be as small & quick as possible. Then to pull the address back out of the int and into an IPAddress object in .net, use the GetBytes method on BitConverter to get the int as a byte array. Pass that byte array to the constructor for IPAddress that takes a byte array, and you end back up with the IPAddress that you started with.

var myIp = new IPAddress(BitConverter.GetBytes(ipAsInt));
Scott Ivey
If you're padding the ip, it would make more sense to use CHAR(15)
phsr
i don't pad the zeros, just threw that in there as a suggestion.
Scott Ivey
Just throwing in a suggestion also :-)
phsr
y not use varchar and forget about the zeros?
Shimmy
Padding the IP address with zeros could make it a different IP address. 010.001.001.100 isn't the same thing as 10.1.1.100. Preceeding the value in an octet with a zero indicates that that octet is being written in octal. The Right Way(tm) to store IP addresses is to parse their various possible representations and store them as binary values (either 32 or 128 bit, depending on whether they're IPv4 or IPv6 addresses).
Evan Anderson
FYI, IPAddress.Parse could be very useful when using on a string.Also note, that in .NET 4.0, Microsoft added a new function, GetAddressBytes, which you then don't need to convert to byte array, and for creating simple use one of the constructors which supports it.
Shimmy
RE: Sorting IP addresses. In SQL Server 2008 you can use `hierarchyid` to help with this http://stackoverflow.com/questions/1038950/what-is-be-the-most-appropriate-data-type-for-storing-an-ip-address-in-sql-server/3441685#3441685
Martin Smith
Also the IPAddress contructor accepts a long value (odd, it should have been uint) as an initialization argument, see my answer: http://stackoverflow.com/questions/1038950/3445015#3445015
Shimmy
+1  A: 

IPV4? int? or tinyint x 4?

It really depends on whether it's just storage and retrieval or if it's going to be a ranged search criteria.

Cade Roux
+22  A: 

Storing an IPv4 address as a binary(4) is truest to what it represents, and allows for easy subnet mask-style querying. However, it requires conversion in and out if you are actually after a text representation. In that case, you may prefer a string format.

A little-used SQL Server function that might help if you are storing as a string is PARSENAME, by the way. Not designed for IP addresses but perfectly suited to them. The call below will return '14':

SELECT PARSENAME('123.234.23.14', 1)

(numbering is right to left).

David M
And if needed, you can also create UDFs to work with these data with dotted-decimal notation... Maybe both for entry and retrieval.
Arjan Einbu
Yes. Or if working with an ORM this conversion could be easily wrapped up - for example, a UserType in (N)Hibernate.
David M
+1 By far the best answer
gbn
@David, how do I make the select so it should return a single int? also what cost more space, a single sql int, or binary(4)? So I can use IPAddress' constructor (that takes a *long* as an argument)? view @ my answer: http://stackoverflow.com/questions/1038950/3445015#3445015
Shimmy
A: 

Since an IP address has 32 bits in it, can you just use a LONG to store the numerical value? It wouldn't be as space-wasteful as using VARCHAR, but then you'd have to decode it back to an IP before you use it, every time, and the delay and overhead that costs might not be worth it.

rwmnau
A: 

I've had some success with making four smallint (or whatever smallish integer datatype you prefer) columns -- one for each octet. Then, you can make a view which smashes them together as a char string (for display) or then you can write simple operators to determine who all is in what subnet etc.

It is quite fast (provided you do proper indexing) and also allows for really easy querying (no string manipulation!).

Matt Rogish
+1  A: 

Don't forget about IPv6 - you need a lot more room if you need to store them - 128bits compares to IPv4's 32.

I'd go for bigint, though you will need some helper code to translate to human friendly versions.

Lee Atkinson
A: 

For space efficient storage and when the values are to be processed (matched or compared to a range), I use an int. The IP address really is just a 32 bit value.

For a simple solution where you just want to store the value to view it, I use a varchar(15) to store the string representation of the IP adress.

Guffa
+2  A: 

One of my favorite articles talks about why you shouldn't use regular expressions to parse IP addresses. Most of what they're talking about is really explaining why you should be very careful with textual representations of IP addresses. I suggest you read it before deciding what datatype to use in your database, and probably also for whatever handling your app will be doing (even though the article is written about Perl, it's useful for any language).

I think in the end a 32 bit datatype (or four 8-bit datatypes) would be the best choice.

rmeador
That is a good article. I haven't been to perl-monks in a loooong time now.
Yoopergeek
A little out of context don't you think? He's serializing them to the database - he's going to control that conversion no matter what database datatype or format he chooses. This article is just being pedantic - I don't see any real-world application of what it's talking about.
Frank Krueger
+1  A: 

If using PHP, then PHP5 has 2 built-in functions for conversion:

ip2long and long2ip (http://uk.php.net/manual/en/function.ip2long.php or .long2ip.php) which returns/converts a signed integer

How does this help storing the value in SQL Server?
gbn
+1  A: 

Regarding this comment in the accepted answer

sorting them is a pain unless you pad zeros.

Here's a trick for SQL Server 2008 (From Itzik Ben-Gan in this book)

with ip_addresses as
(
SELECT '131.33.2.201' AS ip_address UNION ALL
SELECT '2.12.4.4' AS ip_address UNION ALL
SELECT '131.33.2.202' AS ip_address UNION ALL
SELECT '2.12.4.169' AS ip_address UNION ALL
SELECT '131.107.2.201' AS ip_address 
)
select ip_address
from ip_addresses
ORDER  BY CAST('/' + ip_address + '/' AS hierarchyid)

Returns

ip_address
-------------
2.12.4.4
2.12.4.169
131.33.2.201
131.33.2.202
131.107.2.201
Martin Smith
Oh. It's not the accepted answer any more. But still a useful technique for people likely to look at this question.
Martin Smith
+2  A: 

Best way (when no need sorting and other control on the IPs) is store it as int, storing it as varchar etc. would cost way more performance than just a simple innocent int.

There is a property IPAddress.Address but it's obsolete, I don't know why, since if you don't need sorting or control over the IP classes, the best way is to store it as unsigned integer (that has a max value of 0xffffffff which equals to 255.255.255.255 in decimal representation.

Also the IPAddress class has a constructor that accepts a long argument.

And according to VS debugger visualizer, that IPAddress class itself stores its internal variable as one number (not byte array).

Read more on workarounds storing a unit in MS SQL Server:

Shimmy
+1  A: 

I'm reading a lot of similar questions on here, and none of the replies in this one mention the number one answer in others: "For IPv4 addresses, you may want to store them as an int unsigned and use the INET_ATON() and INET_NTOA() functions to return the IP address from its numeric value, and vice versa." I think this is what I'm going to go with in my db, unless I decide to use the php functions mentioned above.

Bobby