Showing posts with label basically. Show all posts
Showing posts with label basically. Show all posts

Wednesday, March 28, 2012

Poor Performance from Web Server

Hi,

I am having a problem with one of my stored procedures in SQL Server 2005. Basically the proc brings back a data set for the ASP.NET front end, but it is running very slowly from .NET.

I have run SQL profiler on the procedure and its taking around 20 seconds to bring back the data for the .NET, where as if I copy and paste the executed SP from profiler into the management studio and run it in a query window, it runs in around 1 second, even if I run DBCC DROPCLEANBUFFERS before I run it. More worryingly, the CPU usage is 40 times higher and the number of reads is 50% higher from .NET.

We have the .NET front end spread over 3 clustered web servers with load balancers and the SQL db is on a dedicated rig. I am having the same problem on my locally published version of the site as well, so I don't think it's an issue with the web site.

If anyone has got any ideas on this then please let me know as I am completely stuck. I should mention that the issue has only recently started occuring and it used to be fine and the rest of the site is fine...

Thanks in advance

Tom



maybe put some trace statements to echo out the time it execute a line of code. This way you can maybe find the bottleneck in your DAL. Are you using the Data Access Application Blocks. I have found those to be very valuable to manage my connections. I never see issues like you are describing anymore. Back in the day, like 4 years ago maybe when I was doing things on my own. Are you trying to fill a custom list or collection with a large set of records? I found that takes way too long and just op for datasets, readers or change my procedure to return a fixed set of rows.

But try the tracing thing to see what line(s) take the longest to execute and I think you will find your issue.

Friday, March 23, 2012

Pointing my new .ADP file to my new SQL Server DB

I hope this question belongs in this forum.

I have a .ADP application (access 2000 front end, SQL Server 2000 back end)
I basically want to create a new .ADP file and point it to a different SQL Server 2000 Database.

I've copied the current SQL Server DB and recreated it. Same for the .ADP file, but it is currently pointing to the old Db, where do I go to have it point to the new SQL Server DB?

Thanksi figured this out thanks.|||You know, you don't need to create a copy of the ADP file. You can easily change the datasource as long as the schemas in both databases are the same.

Wednesday, March 21, 2012

Point in Time query >:[

Hey guys and gals,

I'm having a real problem with this query at the moment...
Basically I have to produce a query which will tell me the total number of people employed by the company at any given date and the total salary for all these people.

We have a people table and a career table.
People(unique_identifier, known_as_and_surname, start_date, termination_date ...)
Career(unique_identifier, parent_identifier, career_date, basic_pay ...)
Relationship people.unique_identifier = career.parent_identifier

Employees can be identified like so

SELECT *
FROM people
WHERE start_date <= DateSelected
AND (termination_date > DateSelected
OR termination_date IS NULL)

Passing the selected date to the query is no trouble at all I am just having problems with the point in time side of this.

All and any help is greatly appreciated :)
~George

P.S. SQL Server 2000 ;)...I am just having problems with the point in time side of this.could you elaborate on this a bit please?

because your query looks fine, all you need is an INNER JOIN as well as a GROUP BY and some aggregate expressions|||george ... is People to Career a 1:1 or 1:many relationship? What if a personn's salary changes during the date range in question?

If 1:1, then a count of unique identifiers and sum of the salary from the Career table using a join on a filter from the People table using the date criteria would do the job.

If however, you can have a salary change during the data range, and you have two rows in the Career table, you will need someone to define the business rules for that situation.|||could you elaborate on this a bit please?

I need to find out if they were an employee at any given date...
There is no career_date_from or to fields, just a single career_date - which is part of the problem!

Tom, One person can have many career history lines. and the problem is - how do I make this a range?

Here's some samlpe data that may help

unique_id name start_date termination_date
00001 George V 01/11/2006 NULL
00002 Tom 53 01/06/2004 01/06/2007
00003 Rudy 937 07/07/2007 NULL

unique_id parent_id career_date basic_pay
1 00001 01/11/2006 150
2 00001 01/12/2006 165
3 00002 01/06/2004 155
4 00003 07/07/2007 160
5 00003 09/07/2007 170

If I entered 02/11/2006 as my criteria I'd want to return the sum of the following lines

unique_id parent_id career_date basic_pay
1 00001 01/11/2006 150
3 00002 01/06/2004 155

Which gives us
2 employees : £305|||Do you just want the "last" (by career_date) record in Career where the career_date is less than or equal to the DateSelected?|||I think that's it!
I believe that makes it look something like this:

DECLARE @.SelectedDate datetime
SET @.SelectedDate = '2006-11-02'

SELECT Count(*)
,Sum(c.basic_pay)
FROM people e
LEFT JOIN career c
ON c.parent_identifier = e.unique_identifier
AND c.career_date = (
SELECT Max(career_date)
FROM career
WHERE parent_identifier = c.parent_identifier
AND career_date <= @.SelectedDate
)

That's what I couldn't get my head around :)|||george ... reference uniqueid '00002' ... you can't fire me ... I QUIT ;)|||george, your sample data was the key to understanding the data relationship (which was not at all apparent from post #1)

just another example of why we ask posters to show sample data :cool:

p.s. those unique_ids are awful!|||They are aweful, but you know what...
It allowed the original developers to make an inbuilt query designers that fools can use - which helps me a little. The only other benefit is that you know the relationships between almsot everything simply by logic.

But yes, it was like this when I got it :p

Can one of you kindly check the following code over once? It's my "final" result

DECLARE @.SelectedDate datetime
SET @.SelectedDate = '2005-11-01'

SELECT Count(*)
,Sum(c.basic_pay)
FROM people e
LEFT JOIN career c
ON c.parent_identifier = e.unique_identifier
AND c.career_date = (
SELECT Max(career_date)
FROM career
WHERE parent_identifier = c.parent_identifier
AND career_date <= @.SelectedDate
)
WHERE (e.termination_date > @.SelectedDate
OR e.termination_date IS NULL)
AND e.start_date <= @.SelectedDate

Oh and Tom, you were never fired... You just didn't turn up ;)

And Rudy; yes it occured to me that I never mentioned that it was 1:M...
It's Monday, I'm frazzled already!
I came in this morning and my monitor was covered in sticky notes because of missed calls etc. So lame.
Not a good start to the week.

Finally - thank you all :)|||Once again Poots' incisive logic cuts to the very core of the problem :cool:

Ok - this:
SET @.SelectedDate = '2005-11-01'
is not guarenteed to work in all system set ups. Better is:
SET @.SelectedDate = '20051101'
Also - is there a unique constriant on the composite key parent_identifier, career_date (assuming a person cannot have two career records in a day)? If not there could be two records for a person on a given day -> errors in the count and sum.|||SET @.SelectedDate = '2005-11-01'

This query will be translated into a 3rd party program that will only run on SS 2000 with it's own run time expression builder - so this was purely for testing purposes ;)
You can have two career records on one day... which is something I had not thought about. Would an order by clause sort this out (if say, I ordered it by date_entered)?|||Damnit - the dupes are causing me a problem.
There are around 10 people who are being counted twice!

How can I eliminate these?|||Extend the same logic again. You wanted the max(career_date). You now want the max(date_entered) for the max(career_date)...|||Yeah... Having trouble with that.

AND c.career_date =
(
SELECT Max(x.career_date)
FROM career x
WHERE x.parent_identifier = c.parent_identifier
AND x.career_date <= @.SelectedDate
AND x.created_by_user =
(
SELECT Max(created_by_user)
FROM career
WHERE parent_identifier = c.parent_identifier
AND career_date <= @.SelectedDate
)

Is not what I want... I'm sorry; lack of sleep + stress =
...can't even think of a word suitable to complete that sentence :( *sigh*|||Untested but worrabout:
... AND c.career_date = (
SELECT TOP 1 career_date
FROM MySchema.career
WHERE parent_identifier = c.parent_identifier
AND career_date <= @.SelectedDate
ORDER BY career_date DESC, created_by_user DESC
)|||SQL Server 2000 - no TOP *sigh*|||SQL Server 2000 - no TOP *sigh*Yeah - you mentioned that before. It is in SQL 2k.

What error do you get again?|||You now want the max(date_entered) for the max(career_date)...hmmm, sounds mysteriously like minimum price on earliest date (http://www.dbforums.com/showthread.php?t=1618384)

:cool:|||Sounds like it - but I can't use local views - courtesy of SS2K :o

However, I think I may have cracked it!
It's not pretty, but (I'm fairly sure :p) it works!

SELECT Count(*)
,Sum(c.basic_pay)
FROM people e
LEFT JOIN career c
ON c.parent_identifier = e.unique_identifier
AND c.career_date = (
SELECT max(c2.career_date)
FROM career c2
WHERE c2.parent_identifier = c.parent_identifier
AND c2.career_date <= @.SelectedDate
)
AND c.datetime_created =(
SELECT max(c3.datetime_created)
FROM career c3
WHERE c3.parent_identifier = c.parent_identifier
AND c3.career_date = c.career_date
)
AND (e.termination_date > @.SelectedDate
OR e.termination_date IS NULL)
AND e.start_date <= @.SelectedDate

What you think? :)|||Looks fine. Shame it takes three scans of the careers table :confused:

I think you should post the lack of TOP as a thread - it ain't right I tell ya it ain't right. Check it out in BoL - should be there.|||Yep - it's not exactly the fastest query in the west, but on this occasion I'm going to let it slide - because I actually can't come up with a better solution!

Why should the lack of TOP be a thread?
I suppose it is odd that it recognises TOP as a keyword (highlights it blue)

SELECT TOP 1 FROM people ORDER BY birth_date DESC
-----
Server: Msg 156, Level 15, State 1, Line 1
Incorrect syntax near the keyword 'FROM'.|||Why should the lack of TOP be a thread?
I suppose it is odd that it recognises TOP as a keyword (highlights it blue)

SELECT TOP 1 FROM people ORDER BY birth_date DESC
-----
Server: Msg 156, Level 15, State 1, Line 1
Incorrect syntax near the keyword 'FROM'.
Duhhhhhh! SELECT TOP 1... what?

SELECT TOP 1 *, myfield, 'George is a plonker' AS plonky_george
FROM people
ORDER BY birth_date DESC
-----
Server: Msg 156, Level 15, State 1, Line 1
Incorrect syntax near the keyword 'FROM'.|||More interestingly

AND c.datetime_created =(
SELECT max(c3.datetime_created)
FROM career c3
WHERE c3.parent_identifier = c.parent_identifier
AND c3.career_date = c.career_date
ORDER BY c3.career_date DESC
)

Gives me

Server: Msg 1033, Level 15, State 1, Line 21
The ORDER BY clause is invalid in views, inline functions, derived tables, and subqueries, unless TOP is also specified.

It's just toying with me!|||That is invalid and also the order by is superfluous there anyhoo.|||Apologies

SELECT TOP 1 birth_date FROM people ORDER BY birth_date
----
Server: Msg 170, Level 15, State 1, Line 1
Line 1: Incorrect syntax near '1'.

EDIT: How many times will I make the same mistake?|||Apologies

SELECT TOP birth_date FROM people ORDER BY birth_date
----
Server: Msg 207, Level 16, State 3, Line 1
Invalid column name 'TOP'.
Duhhhhhhhhhhh! ;)
SELECT TOP how many?|||this time you forgot the top how many

come on, george, slow down and do some desk checking (an age-old debugging technique where you actually read what you just wrote to see if it makes sense)

:)|||See above (edit) :D

My edit beat your posts ;)

And yes, sorry :(

And another smiley for luck :cool:

It's been a long hectic day :o|||Ok - so can we confirm that the below query and error go together?

SELECT TOP 1 birth_date FROM people ORDER BY birth_date
----
Server: Msg 170, Level 15, State 1, Line 1
Line 1: Incorrect syntax near '1'.

If so George - start a thread. This is some sort of error.|||Yes, that is correct.
Damnit.
*goes off to start a new thread* :rolleyes:

Thank you for your patience - and I'm glad you had fun when I misposted ;)

SELECT TOP 1 *, myfield, 'George is a plonker' AS plonky_george
FROM people
ORDER BY birth_date DESC|||I'm glad you had fun when I misposted ;)When you are as easily amused as me every day is a riot ;)

Tuesday, March 20, 2012

PLSQL triggers

I am having some problems with my trigger..
Basically the trigger is there to inform the user that they are entering an item that already exists on the database.

The problem however is that the Trigger wont function, it will not allow any item to be entered into the database (even if this is the first item)
It does retrun a message if the same item exists on the database, but it still returns errors.
And even if I dont have the same thing on the database, the system returns a unique Constraint violation.
I am using a procedure to addnew items. But when I remove the trigger it functions perfectly so the error must be here.

I would really be gratefull to anyone who can help me understand this problem. To me the code is logical, obviously not to the system.

Heres the code:
-----
CREATE OR REPLACE TRIGGER UPDATEITEM
AFTER INSERT OR UPDATE OF title ON ITEM
DECLARE

CURSOR ist_item IS
select title from item where itemno = (select max(itemno) from item);

----Selects newest Item (the one that has been inserted

CURSOR sst_item IS
select itemno from item where itemno = (select max(itemno) from item);

v_count number;
old_count number;
num number;
new_title varchar(20);
old_title varchar(20);
errors_main EXCEPTION;
BEGIN
OPEN ist_item;
OPEN sst_item;
FETCH sst_item INTO num;

if num> 0 then ----checks if anything is in the record yet.

FETCH ist_item INTO new_title;

select title into old_title from item where title= new_title and itemno<> num; --looks at another item in the database with the same title -- --- but not the same number

if old_title=new_title THEN
RAISE_APPLICATION_ERROR (-20000, 'ITEM ALREADY EXISTS IN DATABASE');

END IF;
END IF;
END;
/
SHOW ERROR
-------Not sure what you are trying to accomplish.

1. Your trigger is fired after each STATEMENT, not after each ROW. You can insert/update millions rows into the ITEM table with a single statement. Wouldn't you like to check each insert/update ?

2. You are opening cursors, but not closing them.

3. As for as I can understand, you are assuming that the row with the highest ITEMNO is the one that you have been inserting/updating. Does that assumption really hold ?

To my point of view, forget about the trigger and just add a unique constraint on column TITLE in table ITEM. That is exactly what they are built for.

Good luck.|||What I am trying to achive is:
- Making sure that each item is unique, if someone is trying to put in another item of the same title, this trigger should find the existing item and update the quantity.
(At the moment there is an error message in place of the 'update table' statement) - I am trying to get the basics working.

So the trigger will look for items with the same name, then fire when it has found an existing item.

Thats what this statement does:
select title into old_title from item where title= new_title and itemno<> num;
Looks for a title that is the same as the new title that has been entered but is not the same record number.

The MAX(itemno) is to show the newest record. (The item is stored in a sequential fashion, thus the highest in the database will also be the newest entry and the one that needs to be compared with the rest of the database)

I know the Trigger looks a little sketchy, its just because I have been playing round with it so much, that some of the Close Cursor statement have been deleted, but even with them it doesnt work.

Big thanks for looking at this post, have you any further ideas...|||The MAX(itemno) is to show the newest record. (The item is stored in a sequential fashion, thus the highest in the database will also be the newest entry and the one that needs to be compared with the rest of the database)

This is a very tricky assumption you make. Did you think about updates ? Suppose your table contains two rows :
ItemNo Title
1 First_title
2 Second_title

Now suppose somebody updates row identified by ItemNo 1, and sets the title colum to "Second_Title". Does your trigger still do the job ? What about bulk inserts ? Did you notice that your trigger only fires after each statement. I can do a million inserts in your table and only have the trigger fired once...

You also probably will run into the notorious "ORA-04091 table is mutating".

The only proper way to enforce uniqueness is to use a constraint. But, if you still want to use a trigger, you might want to try (you need Oracle version 8.1.5 or higher):

create or replace trigger UPDATEITEM
AFTER INSERT OR UPDATE OF title ON ITEM
for each row -- verifies all inserted or updated rows !!
declare
pragma autonomous_transaction; -- circumvent ORA-04091
v_count number;
begin
select count(*) into v_count from item where title = :new_title;
if v_count > 0 then raise_application_error(-20000,'ITEM ALREADY EXISTS IN DATABASE'); end if;
end;|||Thats a really good point. (and I didnt consider the fact that it only fires once)

However: I think I can get away with it, in any case, because the entire concept of adding an item is done via procedures (it has to be, its part of the assignment) Therefore the issue of bulk loading never applies (as far as this scenario goes)
Although at a later stage I do want to make some compensations for bulk loading, but it is not really the highest priority.

The reason why this entire trigger looks show slip-shot is because the strength of the scenario that we are doing, realistically the system cannot be implemented in a real organisation, however it has to be implemented with the scenario in mind, and we cant make our own assumptions.

Thanks again for the reply, I am begining to understand how this is supposed to work.

Monday, March 12, 2012

Pls Help With JOIN query...

I'm trying to write a stored proc...

Basically, I have a tblItems table which contains a list of every item
available. One of the columns in this table is the brand... for test
purposes, I hardcoded the BrandID=1...

tblItems also contains a category column (int) which contains a categoryID
of 0..3...

I then have a category table which has CategoryID, Name, and DisplayOrder...

So basically what I'm trying to do is return a list of Category NAMES that
have items in them for a specifc brand... but I want to sort the returned
categories by the DisplayOrder column...

this is what I have now:

select DISTINCT tblCategories.Name, tblCategories.DisplayOrder from
tblCategories
INNER JOIN tblItems
on tblCategories.CategoryID = tblItems.CategoryID
where BrandID=1 order by tblCategories.DisplayOrder

this does what I want it to do, but its returning TWO columns... Name AND
DisplayOrder... I only want to return Name, but if I take the DisplayOrder
out of the select portion, it errors out because it can't order by that...

Any ideas? Obviously I need the DISTINCT keyword so I dont get 10 copies of
the same category name.Just remove the order by ie:

select DISTINCT tblCategories.Name, tblCategories.DisplayOrder
from tblCategories
INNER JOIN tblItems
on tblCategories.CategoryID = tblItems.CategoryID
where BrandID=1
/* order by tblCategories.DisplayOrder */

Nobody wrote:

Quote:

Originally Posted by

I'm trying to write a stored proc...
>
Basically, I have a tblItems table which contains a list of every item
available. One of the columns in this table is the brand... for test
purposes, I hardcoded the BrandID=1...
>
tblItems also contains a category column (int) which contains a categoryID
of 0..3...
>
I then have a category table which has CategoryID, Name, and DisplayOrder...
>
So basically what I'm trying to do is return a list of Category NAMES that
have items in them for a specifc brand... but I want to sort the returned
categories by the DisplayOrder column...
>
this is what I have now:
>
>
select DISTINCT tblCategories.Name, tblCategories.DisplayOrder from
tblCategories
INNER JOIN tblItems
on tblCategories.CategoryID = tblItems.CategoryID
where BrandID=1 order by tblCategories.DisplayOrder
>
this does what I want it to do, but its returning TWO columns... Name AND
DisplayOrder... I only want to return Name, but if I take the DisplayOrder
out of the select portion, it errors out because it can't order by that...
>
Any ideas? Obviously I need the DISTINCT keyword so I dont get 10 copies of
the same category name.

|||Okay my mistake. This will do the job:

select a.tblCategories.Name
from (select DISTINCT top 100 percent tblCategories.Name,
tblCategories.DisplayOrder
from tblCategories
INNER JOIN tblItems
on tblCategories.CategoryID = tblItems.CategoryID
where BrandID=1 order by
tblCategories.Name,tblCategories.DisplayOrder) a

Unlike other databases, SQL Server does not allow 'order by' within
derived tables, so had to use top etc...

othellomy@.yahoo.com wrote:

Quote:

Originally Posted by

Just remove the order by ie:
>
select DISTINCT tblCategories.Name, tblCategories.DisplayOrder
from tblCategories
INNER JOIN tblItems
on tblCategories.CategoryID = tblItems.CategoryID
where BrandID=1
/* order by tblCategories.DisplayOrder */
>
Nobody wrote:

Quote:

Originally Posted by

I'm trying to write a stored proc...

Basically, I have a tblItems table which contains a list of every item
available. One of the columns in this table is the brand... for test
purposes, I hardcoded the BrandID=1...

tblItems also contains a category column (int) which contains a categoryID
of 0..3...

I then have a category table which has CategoryID, Name, and DisplayOrder...

So basically what I'm trying to do is return a list of Category NAMES that
have items in them for a specifc brand... but I want to sort the returned
categories by the DisplayOrder column...

this is what I have now:

select DISTINCT tblCategories.Name, tblCategories.DisplayOrder from
tblCategories
INNER JOIN tblItems
on tblCategories.CategoryID = tblItems.CategoryID
where BrandID=1 order by tblCategories.DisplayOrder

this does what I want it to do, but its returning TWO columns... Name AND
DisplayOrder... I only want to return Name, but if I take the DisplayOrder
out of the select portion, it errors out because it can't order by that...

Any ideas? Obviously I need the DISTINCT keyword so I dont get 10 copies of
the same category name.

|||Nobody (nobody@.cox.net) writes:

Quote:

Originally Posted by

I'm trying to write a stored proc...
>
Basically, I have a tblItems table which contains a list of every item
available. One of the columns in this table is the brand... for test
purposes, I hardcoded the BrandID=1...
>
tblItems also contains a category column (int) which contains a categoryID
of 0..3...
>
I then have a category table which has CategoryID, Name, and
DisplayOrder...
>
So basically what I'm trying to do is return a list of Category NAMES that
have items in them for a specifc brand... but I want to sort the returned
categories by the DisplayOrder column...
>
this is what I have now:
>
>
select DISTINCT tblCategories.Name, tblCategories.DisplayOrder from
tblCategories
INNER JOIN tblItems
on tblCategories.CategoryID = tblItems.CategoryID
where BrandID=1 order by tblCategories.DisplayOrder
>
this does what I want it to do, but its returning TWO columns... Name AND
DisplayOrder... I only want to return Name, but if I take the DisplayOrder
out of the select portion, it errors out because it can't order by that...
>
Any ideas? Obviously I need the DISTINCT keyword so I dont get 10 copies
of the same category name.


No, you don't need DISTINCT. You need to learn to use EXISTS:

SELECT C.Name
FROM tblCategories C
WHERE EXISTS (SELECT *
FROM tblItems I
WHERE I.CategoryID = C.CategoryID
AND I.BrandID = @.brandid)
ORDER BY C.DisplayOrder

--
Erland Sommarskog, SQL Server MVP, esquel@.sommarskog.se
Books Online for SQL Server 2005 at
http://www.microsoft.com/technet/pr...oads/books.mspx
Books Online for SQL Server 2000 at
http://www.microsoft.com/sql/prodin...ions/books.mspx|||On Wed, 22 Nov 2006 16:59:17 -0800, Nobody wrote:

Quote:

Originally Posted by

>I'm trying to write a stored proc...
>
>Basically, I have a tblItems table which contains a list of every item
>available. One of the columns in this table is the brand... for test
>purposes, I hardcoded the BrandID=1...
>
>tblItems also contains a category column (int) which contains a categoryID
>of 0..3...
>
>I then have a category table which has CategoryID, Name, and DisplayOrder...
>
>So basically what I'm trying to do is return a list of Category NAMES that
>have items in them for a specifc brand... but I want to sort the returned
>categories by the DisplayOrder column...
>
>this is what I have now:
>
>
>select DISTINCT tblCategories.Name, tblCategories.DisplayOrder from
>tblCategories
>INNER JOIN tblItems
>on tblCategories.CategoryID = tblItems.CategoryID
>where BrandID=1 order by tblCategories.DisplayOrder
>
>this does what I want it to do, but its returning TWO columns... Name AND
>DisplayOrder... I only want to return Name, but if I take the DisplayOrder
>out of the select portion, it errors out because it can't order by that...
>
>Any ideas? Obviously I need the DISTINCT keyword so I dont get 10 copies of
>the same category name.
>


Hi Nobody,

Since you don't display any columns from tblItems, the only reason to
use it in this query is obviously to check for existance of at least one
row with BrandID equal to 1. That means that you can rewrite your query
as

SELECT c.Name --, c.DisplayOrder
FROM Categories AS c
WHERE EXISTS
(SELECT *
FROM Items AS i
WHERE i.CategoryID = c.CategoryID
AND i.BrandID = 1)
ORDER BY c.DisplayOrder;

You'll probably see a performance increase as well.

--
Hugo Kornelis, SQL Server MVP|||On 23 Nov 2006 01:48:32 -0800, othellomy@.yahoo.com wrote:

Quote:

Originally Posted by

>Okay my mistake. This will do the job:
>
>select a.tblCategories.Name
>from (select DISTINCT top 100 percent tblCategories.Name,
>tblCategories.DisplayOrder
from tblCategories
INNER JOIN tblItems
on tblCategories.CategoryID = tblItems.CategoryID
where BrandID=1 order by
>tblCategories.Name,tblCategories.DisplayOrder) a
>
>Unlike other databases, SQL Server does not allow 'order by' within
>derived tables, so had to use top etc...


Hi othellomy,

Though you can use ORDER BY in a subquery if you also use TOP, the ORDER
BY will only be used to determins which rows meat the TOP criterium;
there is no guarantee that the actual order of the query will be the
same. In fact, SQL Server 2005 will ignore both TOP 100 PERCENT and the
accomanying ORDER BY, since it is essentially a no-op to restrict the
output to 100 percent of the regular output.

If you really want to move the DISTINCT to a subquery (which in this
case is NOT needed - see my reply to Nobody), you could use

SELECT a.Name
FROM (SELECT DISTINCT c.Name, c.DisplayOrder
FROM Categories AS c
INNER JOIN Items AS i
ON i.CategoriID = c.CategoryID
WHERE i.BrandID = 1) AS a
ORDER BY a.DisplayOrder;

(untested)

--
Hugo Kornelis, SQL Server MVP