T-SQL SELECT DISTINCT & ROW_NUMBER() OVER Ordering Problem - sql-server

I'm trying to select DISTINCT rows from a view using ROW_NUMBER() OVER for paging. When I switched the ORDER BY field from a SMALLDATETIME to INT I started getting weird results:
SELECT RowId, Title, HitCount FROM
( SELECT DISTINCT Title, HitCount, ROW_NUMBER() OVER(ORDER BY HitCount DESC) AS RowId FROM ou_v_Articles T ) AS Temp
WHERE RowId BETWEEN 1 AND 5
This query returns:
RowId | Title | HitCount
=======================
4 --- 9
1 --- 43
3 --- 11
2 --- 13
5 --- 0
The results are obviously not in the correct order. I'm not sure what the problem is here, but when I removed DISTINCT it orders them correctly.
Thanks.

Applying DISTINCT to a column list containing ROW_NUMBER() will always result in every row being distinct, as there is one ROW_NUMBER per row.

Is the RowId value you're getting correct? Perhaps you just need an ORDER BY RowId clause on the outer query?

Have you tried just using an order by on the outer select and removing the OVER clause?

Related

Max Value with unique values in more than one column

I feel like I'm missing something really obvious here.
Using T-SQL/SQL-Server:
I have unique values in more than one column but want to select the max version based on one particular column.
Dataset:
Example
ID | Name| Version | Code
------------------------
1 | Car | 3 | NULL
1 | Car | 2 | 1000
1 | Car | 1 | 2000
Target status: I want my query to only select the row with the highest version value. Running a MAX on the version column pulls all three because of the distinct values in the 'Code' column:
SELECT ID
,Name
,MAX(Version)
,Code
FROM Table
GROUP BY ID, Name, Code
The net result is that I get all three entries as per the data set due to the unique values in the Code column, but I only want the top row (Version 3).
Any help would be appreciated.
You need to identify the row with the highest version as 1 query and use another outer query to pull out all the fields for that row. Like so:
SELECT t.ID, t.Name, GRP.Version, t.Code
FROM (
SELECT ID
,Name
,MAX(Version) as Version
FROM Table
GROUP BY ID, Name
) GRP
INNER JOIN Table t on GRP.ID = t.ID and GRP.Name = t.Name and GRP.Version = t.Version
You can also use row_number() to do this kind of logic, for example like this:
select ID, Name, Version, Code
from (
select *, row_number() over (order by Version desc) as RN
from Table1
) X where RN = 1
Example in SQL Fiddle
add the top statment to force the return of a single row. Also add the order by notation
SELECT top 1 ID
,Name
,MAX(Version)
,Code
FROM Table
GROUP BY ID, Name, Code
order by max(version) desc

select statement with "Group by" on specific columns but displaying other columns along with group by columns

I want to get all data based on group by of only encounter,medicationname
column data..
select encounter,medicationname,count(*) as freq,labdate,result
from Medications where (labdate between #admitdate and DATEDIFF(dd,24,#admitdate))
group by encounter,medicationname having count(*)>2
I have records like
encounter medicationname freq
8604261 ACC 3
Now based on this data ,I want to get
This is my desired output
encounter medicationname labtime result
8604261 ACC 2015-05-22 18
8604261 ACC 2015-07-23 23
8604261 ACC 2015-09-09 27
You can use COUNT() as a window function, something like this:
;With Counted as (
SELECT encounter,medicationname,labdate,result,
COUNT(*) OVER (PARTITION BY encounter,medicationname) as cnt
from Medications
where (labdate between #admitdate
and DATEDIFF(dd,24,#admitdate))
)
select encounter,medicationname,labdate,result
from Counted
where cnt > 2
I would note that I think DATEDIFF1 is probably wrong also but since I don't have your data, inputs and an actual spec, I've left it as is for now.
1DATEDIFF returns an int, but you're using it in a comparison against a column which is apparently a date. DATEADD would be the more probably desired function here, but as I say, I don't have full information to go on.
If I understand you question correctly what you need is this
;WITH CTE AS
(
select encounter,medicationname,count(*) as freq,labdate,result
from Medications where (labdate between #admitdate and DATEDIFF(dd,24,#admitdate))
group by encounter,medicationname having count(*) > 2
)
select encounter,medicationname,labdate,result
from Medications M
INNER JOIN CTE C
ON M.encounter = C.encounter
AND M.medicationname = C.medicationname
where (labdate between #admitdate and DATEDIFF(dd,24,#admitdate))
or better yet using COUNT()OVER()
;WITH CTE AS
(
SELECT encounter,medicationname,COUNT(*) OVER(PARTITION BY encounter,medicationname)as freq,labdate,result
FROM Medications
WHERE (labdate between #admitdate and DATEDIFF(dd,24,#admitdate))
)
SELECT * FROM CTE
WHERE freq > 2
select encounter,medicationname,count(*) as freq,labdate,result
from Medications
where (labdate between #admitdate and DATEDIFF(dd,24,#admitdate))
group by encounter,medicationname having count(*) > 2

SQL Update sequence data based upon date field

I am attempting to update a table that contains deed information. Specifically property ID, sale sequence, and deed date. The program generates the sale sequence data sequentially regardless of the deed date or prior deed information for the property in question.
[property_ID] [sale_number] [sale_deed_date]
1 1 01/15/1990
1 2 06/25/1970
1 3 08/12/1930
What I would like to accomplish is re-sequence sale_number data so they are in chronological order. Similar to this:
[property_ID] [sale_number] [sale_deed_date]
1 1 08/12/1930
1 2 06/25/1970
1 3 01/15/1990
Any help with this would be greatly appreciated.
You can do this by grabbing the correct order in a cte:
;WITH cte AS (SELECT property_ID, sales_number, sales_deed_date, rn = ROW_NUMBER() OVER (PARTITION BY Property_ID ORDER BY sales_deed_date) FROM tablename)
UPDATE t
SET t.sales_number = cte.rn
FROM tablename t
INNER JOIN cte ON t.property_ID = cte.property_ID AND t.sales_deed_date = cte.sales_deed_date

T-SQL order by, based on other column value

I'm stuck with a query which should be pretty simple but, for reasons unknown, my brain is not playing ball here ...
Table:
id(int) | strategy (varchar) | value (whatever)
1 "ABC" whatevs
2 "ABC" yeah
3 "DEF" hello
4 "DEF" kitty
5 "QQQ" hurrr
The query should select ALL rows grouped on strategy but only one row per strategy - the one with the higest id.
In the case above, it should return rows with id 2, 4 and 5
SELECT id, strategy , value
FROM (
SELECT id, strategy , value
,ROW_NUMBER() OVER (PARTITION BY strategy ORDER BY ID DESC) rn
FROM Table_Name
) Sub
WHERE rn = 1
Working SQL FIDDLE
You can use window function to get the solution you want. Fiddle here
with cte as
(
select
rank()over(partition by strategy order by id desc) as rnk,
id, strategy, value from myT
)
select id, strategy, value from
cte where rnk = 1;
Try this:
SELECT T2.id,T1.strategy,T1.value
FROM TableName T1
INNER JOIN
(SELECT MAX(id) as id,strategy
FROM TableName
GROUP BY strategy) T2
ON T1.id=T2.id
Result:
ID STRATEGY VALUE
2 ABC yeah
4 DEF kitty
5 QQQ hurrr
See result in SQL Fiddle.
SELECT id, strategy , value
FROM (
SELECT id, strategy , value
,MAX(id) OVER (PARTITION BY strategy) MaxId
FROM YourTable
) Sub
WHERE id=MaxId
You may try this one as well:
SELECT id, strategy, value FROM TableName WHERE id IN (
SELECT MAX(id) FROM TableName GROUP BY strategy
)
Bit depends on your data, you might get results faster with it as it does not do sorting, but by the other hand it uses IN, which can slow you down if there is many 'strategies'

how to get certain sql results

i'm looking to get certain sql results from a query depending on where they are positioned, for example, consider this code
SELECT * FROM Product ORDER BY id asc
which could return at least 100 or so results.
the question is though, how can i get the first 1 - 10 results of that, and then in another different, separate query, how can i get the results that are 11 - 20 or even get the results that are positioned 51 - 60 of that query?
Use a CTE to get the row number and then query by the row column
with your_query as(
SELECT ROW_NUMBER() OVER(ORDER BY ID ASC) AS Row, *
FROM Product
)
select * from your_query
where Row >=5 and Row<=10
There are a number of ways, here's one approach using ROW_NUMBER:
DECLARE #StartRow INTEGER = 11
DECLARE #EndRow INTEGER = 20
;WITH Data AS
(
SELECT TOP(#EndRow) ROW_NUMBER() OVER (ORDER BY id) AS RowNo, *
FROM Product
)
SELECT *
FROM Data
WHERE RowNo BETWEEN #StartRow AND #EndRow
ORDER BY Id

Resources