Different result when selecting different columns ms sql server - sql

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.

Related

How to join in SQL-SERVER

I am trying to learn SQL-SERVER and I have created the below query:
WITH T AS
(
SELECT ROW_NUMBER() OVER(ORDER BY d.DIALOG_ID) as row_num, *
FROM test.db as d
INNER JOIN test.dbs as ds
ON d.DIALOG_ID = ds.DIALOG_ID
)
SELECT *
FROM T
WHERE row_num <=10;
I found that the only way to limit is with ROW_NUMBER().
Although when I try to run the join I have this error:
org.jkiss.dbeaver.model.sql.DBSQLException: SQL Error [8156] [S0001]: The column 'DIALOG_ID' was specified multiple times for 'T'.
The problem: In the WITH, you do SELECT * which gets all columns from both tables db and dbs. Both have a column DIALOG_ID, so a column by that name ends up twice in the result set of the WITH.
Although until here that is all allowed, it is not good practice: why have the same data twice?
Things go wrong when SQL Server has to determine what SELECT * FROM T means: it expands SELECT * to the actual columns of T, but it finds a duplicate column name, and then it refuses to continue.
The fix (and also highly recommended in general): be specific about the columns that you want to output. If T has no duplicate columns, then SELECT * FROM T will succeed.
Note that the even-more-pure variant is to also be specific about what columns you select from T. By doing that it becomes clear at a glance what the SELECT produces, instead of having to guess or investigate when you look at the query later on (or when someone else does).
The updated code would look like this (fill in your column names as we don't know them):
WITH T AS
(
SELECT
ROW_NUMBER() OVER(ORDER BY d.DIALOG_ID) as row_num,
d.DIALOG_ID, d.SOME_OTHER_COL,
ds.DS_ID, ds.SOME_OTHER_COL_2
FROM test.db AS d
INNER JOIN test.dbs AS ds ON d.DIALOG_ID = ds.DIALOG_ID
)
SELECT row_num, DIALOG_ID, SOME_OTHER_COL, DS_ID, SOME_OTHER_COL_2
FROM T
WHERE row_num <= 10;
WITH T AS
(
SELECT ROW_NUMBER() OVER(ORDER BY d.DIALOG_ID) as row_num, d.*
FROM test.db as d
INNER JOIN test.dbs as ds
ON d.DIALOG_ID = ds.DIALOG_ID
)
SELECT *
FROM T
WHERE row_num <=10;

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

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

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

MSSQL 2008 SP pagination and count number of total records

In my SP I have the following:
with Paging(RowNo, ID, Name, TotalOccurrences) as
(
ROW_NUMBER() over (order by TotalOccurrences desc) as RowNo, V.ID, V.Name, R.TotalOccurrences FROM dbo.Videos V INNER JOIN ....
)
SELECT * FROM Paging WHERE RowNo BETWEEN 1 and 50
SELECT COUNT(*) FROM Paging
The result is that I get the error: invalid object name 'Paging'.
Can I query again the Paging table? I don't want to include the count for all results as a new column ... I would prefer to return as another data set. Is that possible?
Thanks, Radu
After more research I fond another way of doing this:
with Paging(RowNo, ID, Name, TotalOccurrences) AS
(
ROW_NUMBER() over (order by TotalOccurrences desc) as RowNo, V.ID, V.Name, R.TotalOccurrences FROM dbo.Videos V INNER JOIN ....
)
select RowNo, ID, Name, TotalOccurrences, (select COUNT(*) from Paging) as TotalResults from Paging where RowNo between (#PageNumber - 1 )* #PageSize + 1 and #PageNumber * #PageSize;
I think that this has better performance than calling two times the query.
You can't do that because the CTE you are defining will only be available to the FIRST query that appears after it's been defined. So when you run the COUNT(*) query, the CTE is no longer available to reference. That's just a limitation of CTEs.
So to do the COUNT as a separate step, you'd need to not use the CTE and instead use the full query to COUNT on.
Or, you could wrap the CTE up in an inline table valued function and use that instead, to save repeating the main query, something like this:
CREATE FUNCTION dbo.ufnExample()
RETURNS TABLE
AS
RETURN
(
with Paging(RowNo, ID, Name, TotalOccurrences) as
(
ROW_NUMBER() over (order by TotalOccurrences desc) as RowNo, V.ID, V.Name, R.TotalOccurrences FROM dbo.Videos V INNER JOIN ....
)
SELECT * FROM Paging
)
SELECT * FROM dbo.ufnExample() x WHERE RowNo BETWEEN 1 AND 50
SELECT COUNT(*) FROM dbo.ufnExample() x
Please be aware that Radu D's solution's query plan shows double hits to those tables. It is doing two executions under the covers. However, this still may be the best way as I haven't found a truly scalable 1-query design.
A less scalable 1-query design is to dump a completed ordered list into a #tablevariable , SELECT ##ROWCOUNT to get the full count, and select from #tablevariable where row number between X and Y. This works well for <10000 rows, but with results in the millions of rows, populating that #tablevariable gets expensive.
A hybrid approach is to populate this temp/variable up to 10000 rows. If not all 10000 rows are filled up, you're set. If 10000 rows are filled up, you'll need to rerun the search to get the full count. This works well if most of your queries return well under 10000 rows. The 10000 limit is a rough approximation, you can play around with this threshold for your case.
Write "AS" after the CTE table name Paging as below:
with Paging AS (RowNo, ID, Name, TotalOccurrences) as
(
ROW_NUMBER() over (order by TotalOccurrences desc) as RowNo, V.ID, V.Name, R.TotalOccurrences FROM dbo.Videos V INNER JOIN ....
)
SELECT * FROM Paging WHERE RowNo BETWEEN 1 and 50
SELECT COUNT(*) FROM Paging

sql select * between exact number of rows

I would like to know if I could using select statement retrieve exact position of the rows. e.g rows between 235 & 250. Is this possible?
Thanks in advance,
shashi
I don't know of a general way.. but each DB has a way. For example in oracle you can do it with a nested select
Oracle:
select * from (
select a, b, c from table_foo
where id = 124
)
WHERE rownum >= 235
and ROWNUM <= 250
MSSQL
select * from
(select Row_Number() over
(order by userID) as RowIndex, * from users) as Sub
Where Sub.RowIndex >= 235 and Sub.RowIndex <= 250
MySQL
SELECT * FROM TableName LIMIT 235, 15
We can do this by multiple way.
we can do with the help of offset-fetch clause.
select * from Table_Name order by Column_Name offset 234 rows fetch next 16 rows only
it will fetch the record between 235-250. because it will skip first 234 rows and will fetch next 16 rows.
we can use simple select statement with where clause.
Select * from Table_Name where Column_Name Between 235 and 250
it will also fetch same result.
Hope it will help.
If your using mySQL you could use the limit command for example:
SELECT * FROM TableName LIMIT 235, 15
Where the first number is the start index and the second is the number of rows to return.
No, that database is set not a sequence, this mean that You the don't have any specific order.
But when specify the order than everything is much simpler.
Oracle
SELECT * FROM ( SELECT * FROM TABLE ORDER BY COLUMN ) WHERE rownum BETWEEN 235 and 250
In this case You have to use rownum
rownum is a pseudo column. It numbers
the records in a result set. The first
record that meets the where criteria
in a select statement is given
rownum=1, and every subsequent record
meeting that same criteria increases
rownum.
MS SQL
WITH OrderedRecords AS
(
SELECT ColumnA,
ROW_NUMBER() OVER (ORDER BY ColumnA) AS 'RowNumber'
FROM Sales.SalesOrderHeader
)
SELECT * FROM OrderedRecords WHERE RowNumber BETWEEN 235 and 250
GO
For this You have to specify You own order column
For MySQL i don't know how the engine deal with this.
This can be done very easily in SQL Server 2012. By using the new feature of OFFSET and FETCH. This will help you to pull out desired rows in an already ordered/sorted result set.
Please see the below example:
SELECT
PP.FirstName + ' ' + PP.LastName AS 'Name'
,PA.City
,PA.PostalCode
FROM Person.Address PA
INNER JOIN
Person.BusinessEntityAddress PBEA
ON PA.AddressID = PBEA.AddressID
INNER JOIN
Person.Person PP
ON PBEA.BusinessEntityID = PP.BusinessEntityID
ORDER BY PP.FirstName
OFFSET 0 ROWS
FETCH NEXT 5 ROWS ONLY
Please notice the OFFSET 0 and FETCH NEXT 5 written above.
This is will display only 5 rows starting from 0 the row.
In SQL Server,
select * from tablename order by columnname offset 20 rows fetch next 40 rows only
It treats 21st row as 1st row and fetches next 40 rows from a 21st row.
If you're using Microsoft SQL (2005>) you can use the ROW_NUMBER function
USE AdventureWorks;
GO
WITH OrderedOrders AS
(
SELECT SalesOrderID, OrderDate,
ROW_NUMBER() OVER (ORDER BY OrderDate) AS 'RowNumber'
FROM Sales.SalesOrderHeader
)
SELECT *
FROM OrderedOrders
WHERE RowNumber BETWEEN 50 AND 60;
Following worked from me in oracle
select * from (select rownum serial,sp.* from sample_table st) sam
where sam.serial > 10 and sam.serial <= 20;