I'm writing a SQL stored procedure that for each AliasName it will retrieve me MasterNames it's associated with in the NameAssociations table, which contains AliasNameId, MasterNameId, and MatchRank, and StatusCode columns. I'll be using the stored procedure for server-side paging the data in C#, so I'd like the startRow endRow part to stay the same.
CREATE PROCEDURE [dbo].[NameAssociationsGetNameAssociations]
#StartRow INT = 1,
#EndRow INT = 1
AS
WITH result_set AS (
SELECT DENSE_RANK() OVER (ORDER BY an.Id) AS rowNum,
an.Id as AliasId, an.AliasName,
mn.Id as MasterId, mn.MasterName, mn.CodeId, mn.RowUpdateVersion AS ConcurrencyToken, na.MatchRank
FROM
NameAssociations na
INNER JOIN AliasNames an
ON na.AliasNameId = an.Id
INNER JOIN MasterNames mn
ON na.MasterNameId = mn.Id
WHERE
na.StatusCode = 0
)
SELECT
rowNum,
AliasId as Id, AliasName,
MasterId as Id, MasterName, CodeId, ConcurrencyToken, MatchRank
FROM
result_set
WHERE
rowNum BETWEEN #StartRow AND #EndRow
This procedure works and retrieves rows numbered correctly:
rowNum
Id
AliasName
Id
MasterName
CodeId
ConcurrencyToken
MatchRank
1
5
BName
34
SomeName1
2
0x0000021
1
2
6
DName
21
SomeName2
3
0x0000003
2
2
6
DName
2
SomeName3
1
0x00000A2
1
2
6
DName
40
SomeName4
1
0x00000B4
3
3
7
AName
11
SomeName5
1
0x000005B
1
So basically, I get a list of MasterNames for every AliasName.
But the rows are not ordered in the way I would like them to be, which is by AliasName ASC, Id (of alias) ASC, and MatchRank ASC, which would look like this:
rowNum
Id
AliasName
Id
MasterName
CodeId
ConcurrencyToken
MatchRank
1
7
AName
11
SomeName5
1
0x000005B
1
2
5
BName
34
SomeName1
2
0x0000021
1
3
6
DName
2
SomeName3
1
0x00000A2
1
3
6
DName
21
SomeName2
3
0x0000003
2
3
6
DName
40
SomeName4
1
0x00000B4
3
You can see the names of aliases are ordered alphabetically, and then the associated masters were reordered so the MatchRank is in ASC order. All of this while the rowNum is correct, which is what I've been having trouble with attaining.
I've tried doing PARTITION BY an.Id ORDER BY an.AliasName ASC, an.Id ASC, na.MatchRank ASC, but I must be misunderstanding what ORDER BY does in this case because the results come out wrong. The results look like it ordered the records only by MatchRank ASC and partitioned by it. I'm expecting it to order the data by those three columns, and then partition it by the an.Id.
How can I write the query so that the output result looks like the second example of table? I hope this was all clear.
Ignoring what looks like a transcription/obfuscation error in your script that actually renders your SQL as invalid (dense_rank must have an order by), I think your solution is actually pretty simple.
The dense_rank function uses the values in the order by to determine which records get the same ranking value, so if you want to sort the output by the AliasName, but also want to make sure records with the same AliasName but different id values (not sure why this would be possible, but defensive coding is generally a good practice), you just need to include both values in your order by, in the order that you want to apply sorting. In your case this looks like the following minimal solution:
Query
declare #t table(id int, AliasName varchar(10), val int);
insert into #t values (1,'b',1),(2,'c',2),(2,'c',3),(2,'cc',4),(22,'c',5),(3,'a',6);
select *
,dense_rank() over (order by id) as rid
,dense_rank() over (order by AliasName, id) as rAliasName
from #t;
Output
id
AliasName
val
rid
rAliasName
3
a
6
3
1
1
b
1
1
2
2
c
2
2
3
2
c
3
2
3
22
c
5
4
4
2
cc
4
2
5
Let's say I have a table
CREATE TABLE names (
id SERIAL PRIMARY KEY,
name CHARACTER VARYING
);
with data
id name
-------------
1 John
2 John
3 John
4 Jane
5 Jane
6 Jane
I need to select all duplicate rows by name except the original one. So in this case I need the result to be this:
id name
-------------
2 John
3 John
5 Jane
6 Jane
How do I do that in Postgresql?
You can use ROW_NUMBER() to identify the 'original' records and filter them out. Here is a method using a cte:
with Nums AS (SELECT id,
name,
ROW_NUMBER() over (PARTITION BY name ORDER BY ID ASC) RN
FROM names)
SELECT *
FROM Nums
WHERE RN <> 1 --Filter out rows numbered 1, 'originals'
select * from names where not id in (select min(id) from names
group by name)
Consider the following table:
ID GroupId Rank
1 1 1
2 1 2
3 1 1
4 2 10
5 2 1
6 3 1
7 4 5
I need an sql (for MS-SQL) select query selecting a single Id for each group with the lowest rank. Each group needs to only return a single ID, even if there are two with the same rank (as 1 and 2 do in the above table). I've tried to select the min value, but the requirement that only one be returned, and the value to be returned is the ID column, is throwing me.
Does anyone know how to do this?
Use row_number():
select t.*
from (select t.*,
row_number() over (partition by groupid order by rank) as seqnum
from t
) t
where seqnum = 1;
I have a single table, where I want to return a list of the MAX(id) GROUPed by another identifier. However I have a third column that, when it meets a certain criteria, "trumps" rows that don't meet that criteria.
Probably easier to explain with an example. Sample table has:
UniqueId (int)
GroupId (int)
IsPriority (bit)
Raw data:
UniqueId GroupId IsPriority
-----------------------------------
1 1 F
2 1 F
3 1 F
4 1 F
5 1 F
6 2 T
7 2 T
8 2 F
9 2 F
10 2 F
So, because no row in groupId 1 has IsPriority set, we return the highest UniqueId (5). Since groupId 2 has rows with IsPriority set, we return the highest UniqueId with that value (7).
So output would be:
5
7
I can think of ways to brute force this, but I am looking to see if I can do this in a single query.
SQL Fiddle Demo
WITH T
AS (SELECT *,
ROW_NUMBER() OVER (PARTITION BY GroupId
ORDER BY IsPriority DESC, UniqueId DESC ) AS RN
FROM YourTable)
SELECT UniqueId,
GroupId,
IsPriority
FROM T
WHERE RN = 1
I have a table with following columns
1. ID
2. UserID
3. ImageUrl
I want retrieve a random ImageUrl for each UserID. For example, there 4 rows in the table
1 12251 Winter.jpg
2 12251 Summer.jpg
3 33333 Fall.jpg
4 33333 Spring.jpg
and the query retrieve the following rows
1 12251 Winter.jpg
4 33333 Spring.jpg
select userid,picture from
(
select userid, picture, ROW_NUMBER() over (partition by userid order by newid()) rn
from yourtable
) v
where rn =1
order by xtype