Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2000 Forums
 Transact-SQL (2000)
 aggregates, grouping, and sort order

Author  Topic 

jshepler
Yak Posting Veteran

60 Posts

Posted - 2003-09-20 : 13:45:19
[code]
CREATE TABLE #T(IP NVARCHAR(15), Usage NVARCHAR(20))

INSERT INTO #T
SELECT '192.168.2.0', 'Network Address' UNION ALL
SELECT '192.168.2.1', 'Unallocated' UNION ALL
SELECT '192.168.2.2', 'Unallocated' UNION ALL
SELECT '192.168.2.3', 'Unallocated' UNION ALL
SELECT '192.168.2.4', 'Unallocated' UNION ALL
SELECT '192.168.2.5', 'Web Site' UNION ALL
SELECT '192.168.2.6', 'Web Site' UNION ALL
SELECT '192.168.2.7', 'Web Site' UNION ALL
SELECT '192.168.2.8', 'Web Site' UNION ALL
SELECT '192.168.2.9', 'Web Site' UNION ALL
SELECT '192.168.2.10', 'Unallocated' UNION ALL
SELECT '192.168.2.11', 'Unallocated' UNION ALL
SELECT '192.168.2.12', 'Unallocated' UNION ALL
SELECT '192.168.2.13', 'Server' UNION ALL
SELECT '192.168.2.14', 'Server' UNION ALL
SELECT '192.168.2.15', 'Broadcast Address'
[/code]

I need the results to look like:

[code]
BegIP EndIP Usage
-------------------------------------------------
192.168.2.0 192.168.2.0 Network Address
192.168.2.1 192.168.2.4 Unallocated
192.168.2.5 192.168.2.10 Web Site
192.168.2.11 192.168.2.12 Unallocated
192.168.2.13 192.168.2.14 Server
192.168.2.15 192.168.2.15 Broadcast Address
[/code]

I cannot figure out how to get this result and would appreciate any help.

Also, MAX() says that the text "***.***.***.9" is greater than "***.***.***.10". I understand why that is, but how can I have it sort by number. To make it a little bit harder, the range of IP address can be more than 256 address and needs to take that into account. For example, the range could be 192.168.8.3 - 192.168.12.32 and it needs to show that 192.168.9.* is less than 192.168.10.*.

I did try it by having a seperate field for each octet, but when I tried to use the MIN() function to get the low end of a range, it would return (using the last example) 192.168.8.0. This was using something like SELECT MIN(Oct3) + '.' + MIN(Oct4) grouped by usage. Well, MIN(Oct3) returned the 8 like it was supposed to, but since 192.168.9.0 is within the range of address, MIN(Oct4) returned 0.

So, I used MIN((Oct3 * 256) + Oct4) and I got the correct value, but I couldn't figure out how to return the IP instead of the calculated number.

Any help would be greatly appreciated.

jsmith8858
Dr. Cross Join

7423 Posts

Posted - 2003-09-20 : 16:55:01
clue 1: break each field into an octet as you mentioned, make sure they are numeric datatypes.

clue 2:then, check out my article here at SQLTeam on runs and streaks. The answer is really easy if you apply the technique from the article. Here's the article: http://www.sqlteam.com/item.asp?ItemID=12654

clue 3: You had a good idea: Calculate oct3 * 256 + oct4 and deal with that value during the process taking of the MIN() and the MAX() of a range of values. To transalte that value BACK: Oct3 = convert(int, value / 256) and Oct4 = value % 256.

if no one can figure it out from the above 3 clues, let me know ! it's not easy, but the basic info should be there !

- Jeff
Go to Top of Page

Stoad
Freaky Yak Linguist

1983 Posts

Posted - 2003-09-21 : 06:35:45
create table h (n varchar(8), m int)
insert into h
select 'a', 1 union all
select 'a', 3 union all
select 'a', 4 union all
select 'a', 4 union all
select 'a', 5 union all
select 'a', 6 union all
select 'a', 6 union all
select 'a', 6 union all
select 'a', 8 union all
select 'a', 9 union all
select 'a', 12 union all
select 'b', 1 union all
select 'b', 1 union all
select 'b', 2 union all
select 'b', 2 union all
select 'b', 5

select n, min(m) m1, max(m) m2 from
(select n, m,
m-(select count(distinct m) from h hh where hh.n=h.n and hh.m<h.m) kk
from h) r
group by n, kk

produces:

n m1 m2
-------- ----------- -----------
a 1 1
a 3 6
a 8 9
a 12 12
b 1 2
b 5 5

Jeff, don't you mind to post here how it appears in your approach?
Go to Top of Page

jsmith8858
Dr. Cross Join

7423 Posts

Posted - 2003-09-22 : 09:05:48
OK, here you go:


CREATE TABLE #T(Oct3 int, Oct4 int, Usage NVARCHAR(20))
GO
INSERT INTO #T (oct3, oct4, Usage)
SELECT 2,0, 'Network Address' UNION ALL
SELECT 2,1, 'Unallocated' UNION ALL
SELECT 2,2, 'Unallocated' UNION ALL
SELECT 2,3, 'Unallocated' UNION ALL
SELECT 2,4, 'Unallocated' UNION ALL
SELECT 2,5, 'Web Site' UNION ALL
SELECT 2,6, 'Web Site' UNION ALL
SELECT 2,7, 'Web Site' UNION ALL
SELECT 2,8, 'Web Site' UNION ALL
SELECT 2,9, 'Web Site' UNION ALL
SELECT 2,10, 'Unallocated' UNION ALL
SELECT 2,11, 'Unallocated' UNION ALL
SELECT 2,12, 'Unallocated' UNION ALL
SELECT 2,13, 'Server' UNION ALL
SELECT 2,14, 'Server' UNION ALL
SELECT 2,15, 'Broadcast Address' UNION ALL
SELECT 2,16, 'Another' UNION ALL
SELECT 3,1,'Another' UNION ALL
SELECT 3,2,'Another' UNION ALL
SELECT 3,6,'One More' UNION ALL
SELECT 3,10,'One More'
GO

select Usage,
'192.168.' + convert(varchar, min(tmp) / 256) + '.' +
convert(varchar, min(tmp) % 256) as FromIP,
'192.168.' + convert(varchar,max(tmp) / 256) + '.' +
convert(varchar, max(tmp) % 256) as ToIP,
count(*) as [# of Addresses]
from
(
select a.*,
(select count(*)
from #t b
where
((b.Oct3 < a.Oct3) or
(b.Oct3 = A.Oct3 and b.Oct4 <= a.oct4))
and a.Usage<> B.Usage) as RunGroup
from
(select #t.*, oct3 * 256 + oct4 as tmp from #t) a
) a
group by
usage, runGroup

GO
DROP TABLE #t


I admit this isn't easy stuff, but hopefully it makes SOME sense. let me know if anyone needs it dissected, but the 3 clues in my first post should explain most of it.

also, note I added some more sample data, and normalized it a little (as discussed in the previous posts) ....


- Jeff
Go to Top of Page

X002548
Not Just a Number

15586 Posts

Posted - 2003-09-22 : 09:43:59
quote:
Originally posted by jshepler

BegIP EndIP Usage
-------------------------------------------------
192.168.2.0 192.168.2.0 Network Address
192.168.2.1 192.168.2.4 Unallocated
192.168.2.5 192.168.2.10 Web Site
192.168.2.11 192.168.2.12 Unallocated
192.168.2.13 192.168.2.14 Server
192.168.2.15 192.168.2.15 Broadcast Address




Shouldn't Web site be 5-9? Unallocated be 10-12?

If not, I'm missing something....



Brett

8-)

SELECT @@POST=NewId()

That's correct! It's an AlphaNumeric!
Go to Top of Page

Stoad
Freaky Yak Linguist

1983 Posts

Posted - 2003-09-22 : 09:59:41
Jeff:

Great!
But I meant to see your approah
on my intentionally simplified data.
Go to Top of Page

X002548
Not Just a Number

15586 Posts

Posted - 2003-09-22 : 10:07:13
Jeff,

That's my point...his result set is different...unless s/he made a mistake in the result set to be returned...

Great stuff though...another one for the SQL tool box...




Brett

8-)

SELECT @@POST=NewId()

That's correct! It's an AlphaNumeric!
Go to Top of Page

jsmith8858
Dr. Cross Join

7423 Posts

Posted - 2003-09-22 : 10:10:54
Stoad -- your sample data makes no sense at all. the technique is for recognizing runs of consective values in your data, which requires a unique and orderable key in the table. Your table has no key, and I see no concept of ordering in your data.

What result should be returned with your data? what does it represent?

To recognize streaks in your data, the column you are "grouping" for the sake of the streak should NOT be involved in the PK of the table, as well, for obvious reasons.

Check out the article.

- Jeff
Go to Top of Page

X002548
Not Just a Number

15586 Posts

Posted - 2003-09-22 : 10:12:15
Jeff,

That's my point...his result set is different...unless s/he made a mistake in the result set to be returned...

Great stuff though...another one for the SQL tool box...




Brett

8-)

SELECT @@POST=NewId()

That's correct! It's an AlphaNumeric!
Go to Top of Page

Stoad
Freaky Yak Linguist

1983 Posts

Posted - 2003-09-22 : 14:05:25
>your sample data makes no sense at all. the technique is for
>recognizing runs of consective values in your data, which
>requires a unique and orderable key in the table. Your
>table has no key, and I see no concept of ordering in
>your data.

My query does exactly the same thing - recognizes runs of consective
values
in field m in each group of n field values.

select n, min(m) m1, max(m) m2 from
(select n, m,
m-(select count(distinct m) from h hh where hh.n=h.n and hh.m<h.m) kk
from h) r
group by n, kk
                       this is result
table h of above query
------------- ------------------
n m n m1 m2
-------- ---- ---- ---- ----
a 1 a 1 1
a 3 a 3 6
a 4 a 8 9
a 4 a 12 12
a 5 b 1 2
a 6 b 5 5
a 6 ------------------
a 6
a 8
a 9
a 12
b 1
b 1
b 2
b 2
b 5
------------
Go to Top of Page

jsmith8858
Dr. Cross Join

7423 Posts

Posted - 2003-09-22 : 14:16:35
Stoad -- yours is actually 100% different.

Again, I will suggest that you read the article.

Your query looks for NUMERICAL gaps in the "m" column and displays results for which there are no gaps.

Mine has nothing to do with gaps in the data. Note in the article there are NO numbers of any kind in the sample data, and it has nothing to do with whether or not the games occur on consective days or weeks apart.

It has to do with ordering rows in a table by a column (or two), and after doing that, seeing how many consective values in ANOTHER column there are -- with or without gaps.

My alogorithm answers a different question and is for a different type of data other than what you are showing.

Does this make sense?

This isn't to suggest that my technique is the ideal solution for this problem, or that your solution or techinique is a bad one, just that they are completely DIFFERENT concepts.

- Jeff
Go to Top of Page

Stoad
Freaky Yak Linguist

1983 Posts

Posted - 2003-09-22 : 15:07:58
OK, Jeff. Thank you. I've already read your article on last Sunday
but very fluently and carelessly. Seems it is deserved my re-reading.
Go to Top of Page

Stoad
Freaky Yak Linguist

1983 Posts

Posted - 2003-09-22 : 16:15:42
Now I really see the difference between two approachs.
Jeff, I changed a bit your test input data as follows

CREATE TABLE #T(Oct3 int, Oct4 int, Usage NVARCHAR(20))
GO
INSERT INTO #T (oct3, oct4, Usage)
SELECT 2,1, 'Unallocated' UNION ALL
SELECT 2,2, 'Unallocated' UNION ALL
SELECT 2,3, 'Unallocated' UNION ALL
SELECT 2,6, 'Unallocated' UNION ALL
SELECT 2,10, 'Unallocated' UNION ALL
SELECT 2,11, 'Unallocated' UNION ALL
SELECT 2,255, 'Unallocated' UNION ALL
SELECT 3,0, 'Unallocated'
GO

and your query produced this result:

Usage FromIP ToIP # of Addresses
-------------- -------------- ------------- --------------
Unallocated 192.168.2.1 192.168.3.0 8

In fact my query in my first reply (I deleted it for the
sake of graz's DB space, counting it as inappropriate)
produced the same result.

To be honest I think it should be:


Usage FromIP ToIP
-------------- -------------- -------------
Unallocated 192.168.2.1 192.168.2.3
Unallocated 192.168.2.6 192.168.2.6
Unallocated 192.168.2.10 192.168.2.11
Unallocated 192.168.2.255 192.168.3.0
Go to Top of Page

jsmith8858
Dr. Cross Join

7423 Posts

Posted - 2003-09-22 : 17:38:40
absolutely ... depends what he needs and what his data looks like.

- Jeff
Go to Top of Page

jshepler
Yak Posting Veteran

60 Posts

Posted - 2003-09-23 : 09:16:00
quote:
Originally posted by X002548

quote:
Originally posted by jshepler

BegIP EndIP Usage
-------------------------------------------------
192.168.2.0 192.168.2.0 Network Address
192.168.2.1 192.168.2.4 Unallocated
192.168.2.5 192.168.2.10 Web Site
192.168.2.11 192.168.2.12 Unallocated
192.168.2.13 192.168.2.14 Server
192.168.2.15 192.168.2.15 Broadcast Address




Shouldn't Web site be 5-9? Unallocated be 10-12?

If not, I'm missing something....



Brett

8-)

SELECT @@POST=NewId()

That's correct! It's an AlphaNumeric!




Sorry, you are correct in regards to what I posted as the source. I mistakenly put .10 as unallocated when I wanted it as Web Site so that when testing, .10 would come after .9 (assuming still using text-based sort).

The sample data isn't really being used, just some data I made up for the post. We actually have various Class C subnets - all numbered differently (207.40.127.*, 209.115.44.*, etc.). Have to keep the 3rd octet in the mix because we do have a block of IPs that span 16 "class C subnets". So, I can't hardcode the first two octets.

Thanks for the tips Jeff, Brett, and Stoad. I appreciate the replies.
Go to Top of Page

joseph
Starting Member

10 Posts

Posted - 2003-09-23 : 12:49:50
here you go :

select Usage,BegIP=replace(replace(BegIP,'.0','.'),'.0','.'),EndIP=replace(replace(EndIP,'.0','.'),'.0','.')
from(select Usage,BegIP=min(newip),EndIP=max(newip)
from (select newip=right('000'+octet1,3)+'.'+right('000'+octet2,3)+'.'+right('000'+octet3,3)+'.'+right('000'+octet4,3),Usage
from(select
octet1,octet2,octet3=substring(ip,1,charindex('.',ip)-1),octet4=substring(ip,charindex('.',ip)+1,len(ip)-charindex(ip,'.'))
,Usage
from(
select ip=substring(ip,charindex('.',ip)+1,len(ip)-charindex(ip,'.'))
,octet2=substring(ip,1,charindex('.',ip)-1),octet1,Usage
from(select ip=substring(ip,charindex('.',ip)+1,len(ip)-charindex(ip,'.'))
,octet1=substring(ip,1,charindex('.',ip)-1),Usage
from #T) firstlevel
) secndlevel
)thirdlevel
)forthlevel
group by Usage)lastlevel



ignore lastlevel if the result is acceptable for you(192.168.002.000,etc)
you can use more nested replace to get ride of extra zero.
Thanks stoad for learnig me new thing .
I also appricate Jeff because . he learned me many new idea in sql.I owe him
Go to Top of Page

jshepler
Yak Posting Veteran

60 Posts

Posted - 2003-09-23 : 13:08:04
quote:
Originally posted by jsmith8858

absolutely ... depends what he needs and what his data looks like.

- Jeff



There are no gaps in the data. There is a row for every IP in a particular network - 256 rows per network. One of the uses of this database is to be able to get the next unused IP for a particular usage. The usage interface just needs to list the current usages and accept input to change a usage for a range of IPs.

This part of the database is made up of 3 tables:

Networks (NetworkID int, Network nvarchar(11))
IPs (IPID int, NetworkID int, IP tinyint, IPUsageID tinyint, ...)
IPUsages (IPUsageID tinyint, IPUsage nvarchar(20))

I made a view to help with this part:
CREATE VIEW _IPUsage
as
SELECT Network + '.' + CAST(IP AS VARCHAR) AS 'IP', ISNULL(IPUsage, 'Unallocated') AS 'Usage', SubnetID,
CAST(RIGHT(Network, CHARINDEX('.', REVERSE(Network)) - 1) AS TinyINT) * 256 + IP AS 'Hash'
FROM IPs INNER JOIN Networks ON IPs.NetworkID = Networks.NetworkID
LEFT JOIN IPUsages ON IPs.IPUsageID = IPUsages.IPUsageID


No problem to make the 3 octets in the Networks table 3 different TinyINT columns. I'm going to read your article on my lunch and see if I can figure out how to apply your technique to my query.

Thanks

/Jeff
Go to Top of Page

jshepler
Yak Posting Veteran

60 Posts

Posted - 2003-09-23 : 13:56:43
Here's what I came up with:
select	Beg.IP as BegIP, [End].IP as EndIP, Beg.Usage
from (select min(hash) as MinHash, max(hash) as MaxHash, usage
from (select Hash, Usage,
(select count(*)
from _IPUsage IU1
where IU1.Usage <> IU2.Usage and
IU1.Hash <= IU2.Hash and
) as RunGroup
from _IPUsage IU2
) a
group by Usage, RunGroup
) IU
INNER JOIN _IPUsage Beg ON IU.MinHash = Beg.Hash
INNER JOIN _IPUsage [End] ON IU.MaxHash = [End].Hash
order by IU.MinHash


But I'm not happy with it. It takes 4 seconds to return a few rows. I'm assuming because I'm using a view and the cost is goin through the roof. However, I think I got the idea (I got the results I wanted) and I'm going to try it using numerical fields for the octets instead of a string. Then I can skip the view. Should be much faster.

/Jeff
Go to Top of Page

jsmith8858
Dr. Cross Join

7423 Posts

Posted - 2003-09-23 : 14:18:58
quote:

However, I think I got the idea (I got the results I wanted) and I'm going to try it using numerical fields for the octets instead of a string. Then I can skip the view. Should be much faster.



YES! should be much faster. good luck.

Again, if there are NO gaps in the IP addresses you are working with, you might be better off using a different algorithm similiar to Stoads.

- Jeff
Go to Top of Page

yousef
Starting Member

1 Post

Posted - 2003-09-23 : 14:31:09
jshepler
Do you try my reply?tell me does that work?

yousef
Go to Top of Page

jshepler
Yak Posting Veteran

60 Posts

Posted - 2003-09-23 : 18:05:31
yousef,
Sorry, I don't see your reply to try out.


Jeff,
I have a question about your method. In you games example, let's say that you want to track ties and the ties are represented by NULLs. How would you change your method to handle that. I ask because I think I have it working like it should, but I use NULL in the Usage column for IPs that are unallocated. For those rows that have NULLs, the "RunGroup" value comes out 0.

Here's where I'm at with this:
select	cast(oct1 as varchar) + '.' + cast(oct2 as varchar) + '.' + cast(min(hash) / 256 as varchar) + '.' + cast(min(hash) % 256 as varchar) as 'BegIP',
cast(oct1 as varchar) + '.' + cast(oct2 as varchar) + '.' + cast(max(hash) / 256 as varchar) + '.' + cast(max(hash) % 256 as varchar) as 'EndIP',
Usage
from (select Oct1, Oct2, (oct3 * 256) + IP as 'Hash', ISNULL(IPUsage, 'Unallocated') as Usage,
(select count(*)
from IPs I1 INNER JOIN Networks N1 ON I1.NetworkID = N1.NetworkID
LEFT JOIN IPUsages IPU1 ON I1.IPUsageID = IPU1.IPUsageID
where I1.IPUsageID <> I2.IPUsageID AND
(N1.Oct3 * 256) + I1.IP <= (N2.Oct3 * 256) + I2.IP and
subnetid = 204
) as RunGroup
from IPs I2 INNER JOIN Networks N2 ON I2.NetworkID = N2.NetworkID
LEFT JOIN IPUsages IPU2 ON I2.IPUsageID = IPU2.IPUsageID
where subnetid = 204
) a
Group By RunGroup, usage, Oct1, Oct2
ORDER BY min(hash)


Ignore subnetid. A value will be passed, not hardcoded. This is just testing through QA.

IPUsageID is NULL for the IPs that are unallocated. Granted, I could just make an entry in the IPUSages table for Unallocated and this query will probably work like it's supposed to, but I'm rather curious why it isn't counting the rows that have NULL in that column (I am using a LEFT JOIN, so they should all be there).

/Jeff
Go to Top of Page
    Next Page

- Advertisement -