select top 1 * returns diffrent recordset each time - sql

In my application I use SELECT TOP 12 * clause to select top 12 records from database and show it to user. In another case I have to show the same result one by one. So I use SELECT TOP 1 * clause,rest of the query is same. I used Sql row_number() function to select items one by on serially.
The problem is SELECT TOP 1 * doesn't return me same row as I get in SELECT TOP 12 *. Also the result set of SELECT TOP 12 * get changed each time I execute the query.
Can anybody explain me why the result is not get same in SELECT TOP 12 * and SELECT TOP 1 *.
FYI: here is my sql
select distinct top 1 * from(
select row_number() over ( ORDER BY Ratings desc ) as Row, * from(
SELECT vw.IsHide, vw.UpdateDate, vw.UserID, vw.UploadPath, vw.MediaUploadID, vw.Ratings, vw.Caption, vw.UserName, vw.BirthYear, vw.BirthDay, vw.BirthMonth, vw.Gender, vw.CityProvince, vw.Approved
FROM VW_Media as vw ,Users as u WITH(NOLOCk)
WHERE vw.IsHide='false' and
GenderNVID=5 and
vw.UserID=u.UserID and
vw.UserID not in(205092) and
vw.UploadTypeNVID=1106 and
vw.IsDeleted='false' and
vw.Approved = 1 and
u.HideProfile=0 and
u.StatusNVID=126 and
vw.UserID not in(Select BlockedToUserID from BlockList WITH(NOLOCk) where UserID=205092) a) totalres where row >0
Thanks in Advance
Sachin

When you use SELECT TOP, you must use also the ORDER BY clause to avoid different results every time.

For performance resons, the database is free to return the records in any order it likes if you don't specify any ordering.
So, you always have to specify in which order you want the records, if you want them in any specific order.
Up to some version of SQL Server (7 IIRC) the natural order of the table was preserved in the result if you didn't specify any ordering, but this feature was removed in later versions.

Related

Top 10 Subquery in Access SQL

SELECT TOP 10 [FINAL_FOR_DB].[Indemnity_Paid]/[FINAL_FOR_DB].[Claim_Count] AS Indemnity_Cost,
final_for_db.Claimant_Name,
final_for_db.Account_Name,
final_for_db.Claim_ID,
final_for_db.File_Date,
final_for_db.Resolution_Date,
final_for_db.Claim_Status,
final_for_db.State_Filed, final_for_db.Expense_Amount,
final_for_db.Claim_Count,
final_for_db.Indemnity_Paid AS [Total Indemnity]
FROM final_for_db
WHERE (((final_for_db.Account_Name)="Exxon"))
ORDER BY [FINAL_FOR_DB].[Indemnity_Paid]/[FINAL_FOR_DB].[Claim_Count] DESC;
This would only give me top 10 entries for Exxon but I am wondering if there is a way to get top 10 entries for each account name from the biggest indemnity cost to the lowest. I believe there is a need for subquery. I would appreciate any help on this. Thanks
Other RDBMS's support the RANK() and ROW_NUMBER() functions. Unfortunately, Access does not (to my knowledge). This should get you close to what you want. It does not handle duplicates well (two customers with the same indemnity cost would get the same rank, possibly leaving you with the top 11 or so).
Select * From
(
Select *
, (
Select count(*)
From final_for_db as tbl2
where (tbl1.Indemnity_Paid/tbl1.Claim_Count) < (tbl2.Indemnity_Paid/tbl2.Claim_Count)
and tbl1.Account_Name= tbl2.Account_Name
) + 1 as rank from final_for_db tbl1
) x where x.Rank < 10

How do I get the top 10 results of a query?

I have a postgresql query like this:
with r as (
select
1 as reason_type_id,
rarreason as reason_id,
count(*) over() count_all
from
workorderlines
where
rarreason != 0
and finalinsdate >= '2012-12-01'
)
select
r.reason_id,
rt.desc,
count(r.reason_id) as num,
round((count(r.reason_id)::float / (select count(*) as total from r) * 100.0)::numeric, 2) as pct
from r
left outer join
rtreasons as rt
on
r.reason_id = rt.rtreason
and r.reason_type_id = rt.rtreasontype
group by
r.reason_id,
rt.desc
order by r.reason_id asc
This returns a table of results with 4 columns: the reason id, the description associated with that reason id, the number of entries having that reason id, and the percent of the total that number represents.
This table looks like this:
What I would like to do is only display the top 10 results based off the total number of entries having a reason id. However, whatever is leftover, I would like to compile into another row with a description called "Other". How would I do this?
with r2 as (
...everything before the select list...
dense_rank() over(order by pct) cause_rank
...the rest of your query...
)
select * from r2 where cause_rank < 11
union
select
NULL as reason_id,
'Other' as desc,
sum(r2.num) over() as num,
sum(r2.pct) over() as pct,
11 as cause_rank
from r2
where cause_rank >= 11
As said above Limit and for the skipping and getting the rest use offset... Try This Site
Not sure about Postgre but SELECT TOP 10... should do the trick if you sort correctly
However about the second part: You might use a Right Join for this. Join the TOP 10 Result with the whole table data and use only the records not appearing on the left side. If you calculate the sum of those you should get your "Sum of the rest" result.
I assume that vw_my_top_10 is the view showing you the top 10 records. vw_all_records shows all records (including the top 10).
Like this:
SELECT SUM(a_field)
FROM vw_my_top_10
RIGHT JOIN vw_all_records
ON (vw_my_top_10.Key = vw_all_records.Key)
WHERE vw_my_top_10.Key IS NULL

How do I SELECT TOP X where it INCLUDES records based on a criteria?

I have a table, with multiple columns, including a column named "PolicyNumber"
Here's a sample:
PolicyNumber
NYH1111
NYD2222
SCH3333
SCS4444
LUH5555
LUS6666
ALH7777
ALW8888
VAH9999
AKH0000
...
NYH1010
NYD2318
There are 1,000+ records in this table and records contain several of each policy number types. For example, multiple policies starting with "NYH" or multiple policies starting with "VAH."
The possible policy types are here:
NYH
NYD
SCH
SCS
LUH
LUS
ALH
ALW
VAH
AKH
How do I do a SELECT TOP 300 where it'll INCLUDE at least one of each Policy Type? Remember, a policy type is the first 3 letters of a policy number.
Is this even possible? The purpose of this is that I have to grab 300 records from production to dump into a test environment and I need to include at least 1 of each policy. After I have at least one of each, it can be completely randomized.
You can try this:
In this solution first there is the newid() with you can generate random order by each running.
To achive the "at least one from each policy" goal, I made the AtLeastOne column. This selects the first from the randomized CTE table for each unique three letters at the start. If the current Policy equals with this first selected value, then it gets 1 else 0. So with this logic, you can select a randomized first one from each unique three letters.
Note: You can put this logic directly into the Order By part too if you need the Policy field only. (I made the example on this way to make the logic behind it visible)
In the last step you just have to order by the AtLeastOne Desc and then by the random ID.
WITH CTE_Policy
AS
(
SELECT newid() as ID, Policy
FROM Code
)
SELECT TOP 300
Policy,
CASE WHEN Policy = (SELECT TOP 1 Policy FROM cte_Policy c
WHERE SUBSTRING(c.Policy,1,3) =
SUBSTRING(CTE_Policy.Policy,1,3))
THEN 1 ELSE 0 END AS AtLeastOne
FROM CTE_Policy
ORDER BY AtLeastOne DESC, ID
Here is an SQLFiddle demo.
Off the top of my head, you could do:
SELECT TOP 30 Column1, Column2, Column3, PolicyNumber
FROM YourTable
WHERE PolicyNumber LIKE 'NYH%'
UNION
SELECT TOP 30 Column1, Column2, Column3, PolicyNumber
FROM YourTable
WHERE PolicyNumber LIKE 'NYD%'
UNION
/* ... remaining eight policy types go here */
ORDER BY PolicyNumber /* Or whatever sort order you want */
It will give you 30 of each type every time, instead of X of one type, and Y of another, however.
one quick way that comes to my mind.. below query will grab just 1 record per policy type
SELECT TOP 300 *
FROM ( SELECT *,rank1= ROW_NUMBER () OVER (PARTITION BY LEFT (PolicyNo,3) ORDER BY GETDATE ()) FROM MyTable
) AS t1
WHERE t1.rank1 = 1
Try this for SQL Server 2005+:
;WITH CTE AS
(
SELECT LEFT(PolicyNumber) PolicyType, PolicyNumber,
ROW_NUMBER() OVER(PARTITION BY LEFT(PolicyNumber) ORDER BY NEWID()) RN
FROM YourTable
)
SELECT TOP 300 PolicyNumber
FROM CTE
ORDER BY RN, NEWID()
Borrowed from ClearLogic +1 Please give the check to ClearLogic if this works
Problem with WHERE t1.rank1 = 1 is that it will stop short of 300 if less then 300 unique
SELECT TOP 300 t1.PolicyNo
FROM ( SELECT PolicyNo, rank1= ROW_NUMBER ()
OVER (PARTITION BY LEFT (PolicyNo,3) ORDER BY NEWID())
FROM MyTable
) AS t1
order by t1.rank, t1.PolicyNo

SQL First Match or just First

Because this is part of a larger SQL SELECT statement, I want a wholly SQL query that selects the first item matching a criteria or, if no items match the criteria, just the first item.
I.e. using Linq I want:
Dim t1 = From t In Tt
Dim t2 = From t In t1 Where Criteria(t)
Dim firstIfAny = From t In If(t2.Any, t2, t1) Take 1 Select t
Because If is not part of Linq, LinqPad doesn't show a single SQL statement, but two, the second depending upon whether the Criteria matches any of the Tt values.
I know it will be SELECT TOP 1 etc. and I can add ORDER BY clauses to get the specific first one I want, but I'm having trouble thinking of the most straightforward way to get the first of two criteria. (It was at exactly this point when I was able to solve this myself.)
Seeing as I don't see an existing question for this, I will let it stand. I'm sure someone else will see the answer quickly.
select top 1 *
from (
select top 1 *, 1 as Rank from MyTable where SomeColumn = MyCriteria
union all
select top 1 *, 2 as Rank from MyTable order by MyOrderColumn
) a
order by Rank
I've gone with this:
SELECT TOP 1 *
FROM MyTable
WHERE SomeColumn = MyCriteria
OR NOT (EXISTS (SELECT NULL FROM MyTable WHERE SomeColumn = MyCriteria))
ORDER BY MyOrdering
My actual SomeColumn = MyCriteria is rather more complex of course, as well as other unrelated where clauses.

SQL query to get the top "n" scores out of a list

I'd like to find the different ways to solve a real life problem I had: imagine to have a contest, or a game, during which the users collect points. You have to build a query to show the list of users with the best "n" scores.
I'm making an example to clarify. Let's say that this is the Users table, with the points earned:
UserId - Points
1 - 100
2 - 75
3 - 50
4 - 50
5 - 50
6 - 25
If I want the top 3 scores, the result will be:
UserId - Points
1 - 100
2 - 75
3 - 50
4 - 50
5 - 50
This can be realized in a view or a stored procedure, as you want. My target db is Sql Server. Actually I solved this, but I think there are different way to obtain the result... faster or more efficent than mine.
Untested, but should work:
select * from users where points in
(select distinct top 3 points from users order by points desc)
Here's one that works - I don't know if it's more efficient, and it's SQL Server 2005+
with scores as (
select 1 userid, 100 points
union select 2, 75
union select 3, 50
union select 4, 50
union select 5, 50
union select 6, 25
),
results as (
select userid, points, RANK() over (order by points desc) as ranking
from scores
)
select userid, points, ranking
from results
where ranking <= 3
Obviously the first "with" is to set up the values, so you can test the second with, and final select work - you could start at "with results as..." if you were querying against an existing table.
How about:
select top 3 with ties points
from scores
order by points desc
Not sure if "with ties" works on anything other the SQL Server.
On SQL Server 2005 and up, you can pass the "top" number as an int parameter:
select top (#n) with ties points
from scores
order by points desc
Actually a modification to the WHERE IN, utilizing an INNER JOIN will be much faster.
SELECT
userid, points
FROM users u
INNER JOIN
(
SELECT DISTINCT TOP N
points
FROM users
ORDER BY points DESC
) AS p ON p.points = u.points
#bosnic, I don't think that will work as requested, I'm not that familiar with MS SQL but I would expect it to return only 3 rows, and ignore the fact that 3 users are tied for 3rd place.
Something like this should work:
select userid, points
from scores
where points in (select top 3 points
from scores
order by points desc)
order by points desc
#Rob#37760:
select top N points from users order by points desc
This query will only select 3 rows if N is 3, see the question. "Top 3" should return 5 rows.
#Espo thanks for the reality check - added the sub-select to correct for that.
I think the easiest response is to:
select userid, points from users
where points in (select distinct top N points from users order by points desc)
If you want to put that in a stored proc which takes N as a parameter, then you'll either have to do read the SQL into a variable then execute it, or do the row count trick:
declare #SQL nvarchar(2000)
set #SQL = "select userID, points from users "
set #SQL = #SQL + " where points in (select distinct top " + #N
set #SQL = #SQL + " points from users order by points desc)"
execute #SQL
or
SELECT UserID, Points
FROM (SELECT ROW_NUMBER() OVER (ORDER BY points DESC)
AS Row, UserID, Points FROM Users)
AS usersWithPoints
WHERE Row between 0 and #N
Both examples assume SQL Server and haven't been tested.
#Matt Hamilton
Your answer works with the example above but would not work if the data set was 100, 75, 75, 50, 50 (where it would return only 3 rows). TOP WITH TIES only includes the ties of the last row returned...
Crucible got it (assuming SQL 2005 is an option).
Hey I found all the other answers bit long and inefficient
My answer would be:
select * from users order by points desc limit 0,5
this will render top 5 points
Try this
select top N points from users order by points desc