Outer Query OrderBy does not depends on Inner Query's Resultset - sql

I am not having deep knowledge of SQL execution order.
When I Execute a Query
select top 2 * from Configuration
It Gives me
ABC1,100,Data001
ABC2,200,Data002
When I Execute a Query
select top 2 * from Configuration order by 1 desc
It Gives me
XYZ1,400,Data100
XYZ2,300,Data099
When I Execute a Query
select * from (select top 2 * from Configuration) as a order by 1 desc
It gives me
XYZ1,400,Data100
XYZ2,300,Data099
My problem is why i am getting
XYZ1,400,Data100
XYZ2,300,Data099
as output instead
ABC1,100,Data001
ABC2,200,Data002
As per my knowledge Inner Query Will Return two rows to Outer Query.
Outer Query Will process those two rows with
From->Where->group by->having->Select->Order by
order of Execution and Will give output as two rows which I mentioned as expected. But Outer Query's order by is affecting on whole table of Inner Query.
Please comment where I am making mistake.

SQL Server has no any sense to populate by default order by.
In your inner query you have not specified order by so it returned wrong result.
Now use below code for SQL Server 2008 R2
SELECT * FROM (SELECT TOP 2 * FROM Configuration ORDER BY 1) AS a ORDER BY 1 DESC
One other alternative is : Comman Table Expression , Like below,
;WITH cteTest AS
(
SELECT TOP 2 *
FROM Configuration ORDER BY 1
)
SELECT * FROM cteTest ORDER BY 1 DESC

Related

Is there an efficiency problem with my query to select middle rows?

I am trying to select rows 3 - 5 of:
SELECT *
FROM Finance_User
ORDER BY email DESC
I originally had just:
SELECT
ROW_NUMBER() OVER (ORDER BY email DESC) AS RowNum, *
FROM
Finance_User
WHERE
RowNum BETWEEN 3 AND 5
But this did not work as RowNum was an invalid column.
Instead I did the below:
WITH OrderedUsers AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY email DESC) AS RowNum, *
FROM
Finance_User
)
SELECT *
FROM OrderedUsers
WHERE RowNum BETWEEN 3 AND 5
This works perfectly fine. However, I am concerned that there might be performance issues with this as it seems to be selecting from the table twice?
ROW_NUMBER() with a CTE (or a subquery) won't scan the table twice. However using the window function might incur additional processing for the RDBMS.
You could achieve the same results with ORDER BY ... OFFSET ... FETCH ..., available starting SQL-Server 2012, that are provided specifically for the purpose of paging a resultset:
SELECT *
FROM Finance_User
ORDER BY email DESC
OFFSET 2 ROWS FETCH NEXT 3 ROWS ONLY
From the documentation:
We recommend that you use the OFFSET and FETCH clauses instead of the TOP clause to implement a query paging solution and limit the number of rows sent to a client application.
Your query is fine.
WITH AS clause is a Common Table Expression which means that this query may be reused later and should be cached if needed and possible. So there should not be any problem with "selecting from the table twice".
The same result you can get with this query:
SELECT * from
(SELECT ROW_NUMBER() OVER (ORDER BY email DESC) AS RowNum, * FROM Finance_User)
where RowNum between 3 and 5
And finally, you can always check execution plan and make sure of it as well.

Insert duplicate row in SQL Server view

I was wondering if it was possible in SQL Server 2008 R2 to create a view with only the last column (DateTime DESC), but this last row should be copied in the view again.
So the end result would be a View with two rows with the same data.
The query to select one row is easy:
SELECT TOP 1 *
FROM Reporting
ORDER BY DateTime DESC
or
SELECT TOP 1 *
FROM Reporting
WHERE DateTime IN (SELECT MAX(DateTime)
FROM Reporting)
This returns only one row, but I want to duplicate this row in the view again.
Thanks
The syntax in the above answer is invalid. You are not allowed to have ORDER BY in each data source in the UNION ALL. You can have only one at the final statement. So, this is wrong:
SELECT TOP 1 * FROM Reporting ORDER BY DateTime DESC
UNION ALL
SELECT TOP 1 * FROM Reporting ORDER BY DateTime DESC
And should be done like this:
SELECT * FROM (SELECT TOP 1 * FROM Reporting ORDER BY DateTime DESC)
UNION ALL
SELECT * FROM (SELECT TOP 1 * FROM Reporting ORDER BY DateTime DESC);
I will advice using a different approach. Use fake data source and then cross apply.
SELECT SI.*
FROM
(
SELECT 1
UNION ALL
SELECT 2
) DS ([col])
CROSS APPLY
(
SELECT TOP 1 * FROM Reporting ORDER BY DateTime DESC
) SI;
You can test easily that the execution plan of this statement is better causing only one ordering and index scan:
Try Union all:
SELECT TOP 1 * FROM Reporting ORDER BY DateTime DESC
UNION ALL
SELECT TOP 1 * FROM Reporting ORDER BY DateTime DESC

Different result when selecting different columns ms sql server

I am querying multiple databases with heidiSQL and I am obtaining a different result when i adjust the SELECT clause.
When I execute the following query, the db returns 501 records:
select *
from klantcontact
inner join (
select top 448 ks.FIRNR,ROW_NUMBER() OVER(ORDER BY FIRNR DESC) as rownum
from klant ks) res
on klantcontact.KLANR = res.FIRNR
I actully only need two columns. But i get 526 records as result when I run the following query (only the select clause is changed):
select klantcontact.NAAM
from klantcontact
inner join (
select top 448 ks.FIRNR,ROW_NUMBER() OVER(ORDER BY FIRNR DESC) as rownum
from klant ks) res
on klantcontact.KLANR = res.FIRNR
I think it has something to do with the 'OVER'?
In the subquery, you have specified top 448 but you have not specified any order by clause at the end. So every time you run a query there is a chance that the 448 rows which are returned are different giving a different number of rows every time.
Change your query to either the following:
select klantcontact.NAAM
from klantcontact
inner join (
select top 448 ks.FIRNR,ROW_NUMBER() OVER(ORDER BY FIRNR DESC) as rownum
from klant ks order by ks.FIRNR) res
on klantcontact.KLANR = res.FIRNR
OR remove the top 448 clause.

optimizing row number query

I am using sql server 2008 r2 and had below query
select * from
(
select d.ID as ID,
....
....
ROW_NUMBER() OVER
(
ORDER BY #some field
) AS RowNum
from
/*some table*/
LEFT join
(select Device_ID,
Level,
ROW_NUMBER() over (partition by Device_ID order by id desc) as rn
from #sometable as de WITH (NOLOCK)
where #some condition
) t
where t.rn = 1)tmp on ID=tmp.Device_ID **/* sort operation 1*/**
/*some more joins */
WHERE /*some condition*/
) as DbD
where RowNum BETWEEN #SkipRowsLocal and (#SkipRowsLocal + #TakeRowsLocal - 1)
order by RowNum
I am trying to implement pagination kind of query from sample
http://blog.sqlauthority.com/2013/04/14/sql-server-tricks-for-row-offset-and-paging-in-various-versions-of-sql-server/
but looks like it's executing very slow, when I looked into query plan sort operation is consuming almost 50% of query time and i guess its the 1st sort operation which I marked as 1, basically in temp table t I want to retrieve latest value and in outer row number I wanted to fetch say only 40 records.
It's basically like sorting 10K rows and then taking 40 out of it, is there is any way we can improve this query?
instead of a left join, try an OUTER APPLY, to get the TOP 1 of the device you are interested in - think of it as 'I get a record from the first table, then for that record, I go and get the TOP 1 for that device ID in the other table, but remembering that in the second table, you need to search by the data from the first table, rather than a join
select * from
(
select d.ID as ID,
....
....
ROW_NUMBER() OVER
(
ORDER BY #some field
) AS RowNum
from
/*some table*/
OUTER APPLY
(select TOP 1 Device_ID,
Level
from #sometable as de WITH (NOLOCK)
where #some condition and Device_ID = [/*some table*/].id ORDER BY id DESC
) t
)tmp
/*some more joins */
WHERE /*some condition*/
) as DbD
where RowNum BETWEEN #SkipRowsLocal and (#SkipRowsLocal + #TakeRowsLocal - 1)
order by RowNum
something on those lines, you might want to build just the relevant parts of the query and compare them, it would seem to avoid sorting and with an index might well be quick

MS Access limit syntax

I have a very basic Access DB table called SCHEDULE. When I make the following SQL Query entry, things work perfectly.
SELECT *
FROM schedule
ORDER BY start;
Now what I want is to skip the first 3 records and view the remaining 10 like so:
SELECT *
FROM schedule
ORDER BY start
LIMIT 3,7;
But I receive a "SYNTAX ERROR (MISSING OPERATOR) IN QUERY EXPRESSION 'START LIMIT 3'
So as a test I tried the following:
SELECT *
FROM schedule
ORDER BY start
LIMIT 0,3;
Same error.
What is the correct syntax?
You can do this with subqueries is MS Access:
select top 7 *
from (select top 10 *
from schedule
order by start
) as s
order by start desc;
If you want the final results in ascending order rather than descending order, use this as a subquery and add order by start.
EDIT:
If you just want to avoid the first three:
select *
from schedule
where start not in (select top 3 start from schedule order by start);
There is no LIMIT operator in MS Access, that's why you are getting the syntax error, but you can get this result using TOP and a subquery, like the following:
SELECT *
FROM schedule
WHERE schedule.ID IN
(
SELECT TOP 7 SUB.ID
FROM [
SELECT TOP 10 schedule.start, schedule.ID
FROM schedule
ORDER BY schedule.start, schedule.ID
]. AS SUB
ORDER BY SUB.start DESC, SUB.ID DESC
)
ORDER BY schedule.start, schedule.ID