87

I'm working with SQL Server 2005.

My query is:

SELECT (
  SELECT COUNT(1) FROM Seanslar WHERE MONTH(tarihi) = 4
  GROUP BY refKlinik_id
  ORDER BY refKlinik_id
) as dorduncuay

And the error:

The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.

How can I use ORDER BY in a sub query?

Steven
  • 1,996
  • 3
  • 22
  • 33
cagin
  • 5,772
  • 14
  • 74
  • 130

15 Answers15

123

This is the error you get (emphasis mine):

The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.

So, how can you avoid the error? By specifying TOP, would be one possibility, I guess.

SELECT (
  SELECT TOP 100 PERCENT
  COUNT(1) FROM Seanslar WHERE MONTH(tarihi) = 4
  GROUP BY refKlinik_id
  ORDER BY refKlinik_id
) as dorduncuay
Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • 6
    this does not order by, if you specify top 99.99999 Percent it works as expected – foz1284 Jul 03 '13 at 09:41
  • @foz1284 Can you point to some documentation or reference that confirms this statement? – Tomalak Jul 03 '13 at 10:54
  • 15
    http://blogs.msdn.com/b/queryoptteam/archive/2006/03/24/560396.aspx as explained here with TOP 100 Percent there is no order as it is guaranteed to be returning all rows hovever when SQL Server is evaluating top 99 it needs to perform order to make sure it returns the correct rows. – foz1284 Jul 05 '13 at 06:24
  • 1
    As far as I understand, this peculiarity only affects tables without a clustered index, so it is not a general issue you will encounter when using `TOP 100 PERCENT`. But thanks for the hint, I did not know that. – Tomalak Jul 05 '13 at 06:28
  • 1
    i've just had a quick re-read and I see what you are referencing, It was an issue for me the other day as I was ordering a subquery which was unioning 3 tables together(I'm no SQL expert but I guess the result would have no clustered index!) – foz1284 Jul 05 '13 at 06:32
  • @foz1284 Hi, the link can't found. Could you update a new link? Thanks. – Jun Yu Mar 23 '21 at 06:03
44

If you're working with SQL Server 2012 or later, this is now easy to fix. Add an offset 0 rows:

SELECT (
  SELECT
  COUNT(1) FROM Seanslar WHERE MONTH(tarihi) = 4
  GROUP BY refKlinik_id
  ORDER BY refKlinik_id OFFSET 0 ROWS
) as dorduncuay
Jez
  • 27,951
  • 32
  • 136
  • 233
  • 2
    Out of all the answers that I've been looking in the past 20 minutes, this was the only one that solved my problem. – iminiki Jul 21 '19 at 04:34
  • I was avoiding this answer because it seems so redundant and pointless, surely there would be a better way to make it work!....not. So this is it, this is the answer y'all. What a strange feature. – Jose V Feb 14 '20 at 19:41
  • I added an example using ORDER BY on a SQL Server's CTE (temporary named result set) in an answer to another question [here](https://stackoverflow.com/a/60232533/2446144) – Jose V Feb 15 '20 at 00:24
  • what action does offset 0 rows? – vll1990 Nov 15 '21 at 11:15
  • @vll1990 OFFSET 0 Rows means that o rows will get skipped . In the above query bit generally do the order by and while doing that it will take all records without skipping any rows. Below points can suffice your understanding. 1.) OFFSET is part of the ORDER BY clause. It cannot be used on its own. 2.) OFFSET values must be zero or greater. A negative number results in an error. 3.) When OFFSET is 0, then no rows are skipped. 4.) If OFFSET is greater than the number of rows in the ordered results, then no rows are returned. – Prashant.jha Nov 30 '22 at 07:07
  • 2
    Why adding `offset 0 rows` magically makes `order by` work? Any difference this statement brings to query planner? – zh chen Dec 02 '22 at 04:42
37

Besides the fact that order by doesn't seem to make sense in your query.... To use order by in a sub select you will need to use TOP 2147483647.

SELECT (
  SELECT TOP 2147483647
  COUNT(1) FROM Seanslar WHERE MONTH(tarihi) = 4
  GROUP BY refKlinik_id
  ORDER BY refKlinik_id
) as dorduncuay

My understanding is that "TOP 100 PERCENT" doesn't gurantee ordering anymore starting with SQL 2005:

In SQL Server 2005, the ORDER BY clause in a view definition is used only to determine the rows that are returned by the TOP clause. The ORDER BY clause does not guarantee ordered results when the view is queried, unless ORDER BY is also specified in the query itself.

See SQL Server 2005 breaking changes

Hope this helps, Patrick

Quuxplusone
  • 23,928
  • 8
  • 94
  • 159
Patrick Wolf
  • 2,530
  • 2
  • 28
  • 27
8

If building a temp table, move the ORDER BY clause from inside the temp table code block to the outside.

Not allowed:

SELECT * FROM (
SELECT A FROM Y
ORDER BY Y.A
) X;

Allowed:

SELECT * FROM (
SELECT A FROM Y
) X
ORDER BY X.A;
JustBeingHelpful
  • 18,332
  • 38
  • 160
  • 245
5

You don't need order by in your sub query. Move it out into the main query, and include the column you want to order by in the subquery.

however, your query is just returning a count, so I don't see the point of the order by.

cjk
  • 45,739
  • 9
  • 81
  • 112
3

maybe this trick will help somebody

SELECT
    [id],
    [code],
    [created_at]                          
FROM
    ( SELECT
        [id],
        [code],
        [created_at],
        (ROW_NUMBER() OVER (
    ORDER BY
        created_at DESC)) AS Row                                 
    FROM
        [Code_tbl]                                 
    WHERE
        [created_at] BETWEEN '2009-11-17 00:00:01' AND '2010-11-17 23:59:59'                                  
        )  Rows                          
WHERE
    Row BETWEEN 10 AND    20;

here inner subquery ordered by field created_at (could be any from your table)

Community
  • 1
  • 1
Vlad
  • 31
  • 1
3

A subquery (nested view) as you have it returns a dataset that you can then order in your calling query. Ordering the subquery itself will make no (reliable) difference to the order of the results in your calling query.

As for your SQL itself: a) I seen no reason for an order by as you are returning a single value. b) I see no reason for the sub query anyway as you are only returning a single value.

I'm guessing there is a lot more information here that you might want to tell us in order to fix the problem you have.

Robin Day
  • 100,552
  • 23
  • 116
  • 167
3

Add the Top command to your sub query...

SELECT 
(
SELECT TOP 100 PERCENT 
    COUNT(1) 
FROM 
    Seanslar 
WHERE 
    MONTH(tarihi) = 4
GROUP BY 
    refKlinik_id
ORDER BY 
    refKlinik_id
) as dorduncuay

:)

2

Try moving the order by clause outside sub select and add the order by field in sub select



SELECT * FROM 

(SELECT COUNT(1) ,refKlinik_id FROM Seanslar WHERE MONTH(tarihi) = 4 GROUP BY refKlinik_id)
as dorduncuay 

ORDER BY refKlinik_id 

indrap
  • 760
  • 2
  • 10
  • 18
2

In this example ordering adds no information - the COUNT of a set is the same whatever order it is in!

If you were selecting something that did depend on order, you would need to do one of the things the error message tells you - use TOP or FOR XML

AakashM
  • 62,551
  • 17
  • 151
  • 186
1

For me this solution works fine as well:

SELECT tbl.a, tbl.b
FROM (SELECT TOP (select count(1) FROM yourtable) a,b FROM yourtable order by a) tbl
Qohelet
  • 1,459
  • 4
  • 24
  • 41
1

Good day

for some guys the order by in the sub-query is questionable. the order by in sub-query is a must to use if you need to delete some records based on some sorting. like

delete from someTable Where ID in (select top(1) from sometable where condition order by insertionstamp desc)

so that you can delete the last insertion form table. there are three way to do this deletion actually.

however, the order by in the sub-query can be used in many cases.

for the deletion methods that uses order by in sub-query review below link

http://web.archive.org/web/20100212155407/http://blogs.msdn.com/sqlcat/archive/2009/05/21/fast-ordered-delete.aspx

i hope it helps. thanks you all

Omar Kamel
  • 155
  • 1
  • 8
0

For a simple count like the OP is showing, the Order by isn't strictly needed. If they are using the result of the subquery, it may be. I am working on a similiar issue and got the same error in the following query:

-- I want the rows from the cost table with an updateddate equal to the max updateddate:

    SELECT * FROM #Costs Cost
    INNER JOIN
    (
        SELECT Entityname, costtype, MAX(updatedtime) MaxUpdatedTime
        FROM #HoldCosts cost
        GROUP BY Entityname, costtype
        ORDER BY Entityname, costtype  -- *** This causes an error***
    ) CostsMax
        ON  Costs.Entityname = CostsMax.entityname
        AND Costs.Costtype = CostsMax.Costtype
        AND Costs.UpdatedTime = CostsMax.MaxUpdatedtime
    ORDER BY Costs.Entityname, Costs.costtype

-- *** To accomplish this, there are a few options:

-- Add an extraneous TOP clause, This seems like a bit of a hack:

    SELECT * FROM #Costs Cost
    INNER JOIN
    (
        SELECT TOP 99.999999 PERCENT Entityname, costtype, MAX(updatedtime) MaxUpdatedTime
        FROM #HoldCosts cost
        GROUP BY Entityname, costtype
        ORDER BY Entityname, costtype  
    ) CostsMax
        ON Costs.Entityname = CostsMax.entityname
        AND Costs.Costtype = CostsMax.Costtype
        AND Costs.UpdatedTime = CostsMax.MaxUpdatedtime
    ORDER BY Costs.Entityname, Costs.costtype

-- **** Create a temp table to order the maxCost

    SELECT Entityname, costtype, MAX(updatedtime) MaxUpdatedTime
    INTO #MaxCost
    FROM #HoldCosts cost
    GROUP BY Entityname, costtype
    ORDER BY Entityname, costtype  

    SELECT * FROM #Costs Cost
    INNER JOIN #MaxCost CostsMax
        ON Costs.Entityname = CostsMax.entityname
        AND Costs.Costtype = CostsMax.Costtype
        AND Costs.UpdatedTime = CostsMax.MaxUpdatedtime
    ORDER BY Costs.Entityname, costs.costtype

Other possible workarounds could be CTE's or table variables. But each situation requires you to determine what works best for you. I tend to look first towards a temp table. To me, it is clear and straightforward. YMMV.

iLWR
  • 111
  • 2
0

On possible needs to order a subquery is when you have a UNION :

You generate a call book of all teachers and students.

SELECT name, phone FROM teachers
UNION
SELECT name, phone FROM students

You want to display it with all teachers first, followed by all students, both ordered by. So you cant apply a global order by.

One solution is to include a key to force a first order by, and then order the names :

SELECT name, phone, 1 AS orderkey FROM teachers
UNION
SELECT name, phone, 2 AS orderkey FROM students
ORDER BY orderkey, name

I think its way more clear than fake offsetting subquery result.

iguypouf
  • 770
  • 4
  • 15
-1

I Use This Code To Get Top Second Salary

I am Also Get Error Like

The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.

TOP 100 I Used To Avoid The Error

select * from ( select tbl.Coloumn1 ,CONVERT(varchar, ROW_NUMBER() OVER (ORDER BY (SELECT 1))) AS Rowno from ( select top 100 * from Table1 order by Coloumn1 desc) as tbl) as tbl where tbl.Rowno=2

Community
  • 1
  • 1