SQL Server: selecting distinct values per one column - sql-server

I was wandering if it's possible to filter select results removing values that partially overlap
For example below, i have thousands of records, but i need the 'week date' value to be unqiue, and in case of duplicates the one with the highest value should remain.
emplo project_id Value week_Date week_ActualStart week_ActualEnd
A0001 project001 100 2015-12-28 2015-12-28 2016-01-03
A0001 project001 60 2015-12-28 2016-01-01 2016-01-03
So only the first row should remain.
I could really use someone's advice

Try something like the following:
;WITH WeekDateCte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY emplno, week_Date ORDER BY Value DESC) RowNo
FROM employee
)
SELECT *
FROM WeekDateCte
WHERE RowNo = 1
For more information about ROW_NUMBER function, check here.
NOTE: ROW_NUMBER() returns BIGINT.

You can use ROW_NUMBER for this:
SELECT emplno, project_id, Value, week_Date,
week_ActualStart, week_ActualEnd
FROM (
SELECT emplno, project_id, Value, week_Date,
week_ActualStart, week_ActualEnd,
ROW_NUMBER() OVER (PARTITION BY emplno, week_Date
ORDER BY Value DESC) AS rn
FROM mytable) AS t
WHERE t.rn = 1
The query picks the row having the greatest Value per emplno, week_Date slice.

Related

Case when first instance of unique ID

I'm in Snowflake and am trying to mark the first occurrence of a unique ID in a column. I've been playing around with first_value but am not really getting anywhere.
So my data looks something like this:
ID Date
123 1/2019
123 2/2019
123 3/2019
234 2/2019
234 3/2019
And ideally I want something like this:
ID Date First?
123 1/2019 1
123 2/2019 0
123 3/2019 0
234 2/2019 1
234 3/2019 0
How do I accomplish this?
You want ROW_NUMBER:
SELECT
ID,
Date,
IFF(ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Date) = 1, 1, 0) AS First
FROM
schema.table
ORDER BY ID, Date
;
This checks whether the current row is the first date for the ID, and if it is, assigns a value of 1 (otherwise 0).
LAG can also be used to solve this..
SELECT id
,date
,lag(id) over (partition by id order by date) is null as first
FROM table_name;
Which can be also done with FIRST_VALUE like
SELECT id
,date
,first_value(id) over (partition by id order by date) = date as first
FROM table_name;
If your intention is to retrieve the first occurrence of a unique ID in a column then the row_number() or the dense_rank() function can help.
with cte as
(
select ID, Date,
row_number() over (partition by ID order by date) as row_number
from table1
)
select * from cte where row_number = 1;
with cte as
(
select ID, Date,
dense_rank() over (partition by ID order by date) as rank
from stack1
)
select * from cte where rank = 1;

SQL Server query should return max value records

I have table like this:
id_Seq_No emp_name Current_Property_value
-----------------------------------------------
1 John 100
2 Peter 200
3 Pollard 50
4 John 500
I want the max record value of particular employee.
For example, John has 2 records seq_no 1, 4. I want 4th seq_no Current_Property_Value in single query.
Select
max(id_Seq_No)
from
t1
where
emp_name = 'John'
To get the Current_Property_value, just order the results by id_Seq_No and get the first one:
SELECT
TOP 1 Current_Property_value
FROM
table
WHERE
emp_name = 'John'
ORDER BY
id_Seq_No DESC
this will give highest for all tied employees
select top 1 with ties
id_Seq_No,emp_name,Current_Property_value
from
table
order by
row_number() over (partition by emp_name order by Current_Property_value desc)
You can use ROW_NUMBER with CTE.
Query
;WITH CTE AS(
SELECT rn = ROW_NUMBER() OVER(
PARTITION BY emp_name
ORDER BY id_Seq_No DESC
), *
FROM your_table_name
WHERE emp_name = 'John'
)
SELECT * FROM CTE
WHERE rn = 1;

How to give numbers to the result after executing the query in sql server?

I have a table with some 100 records and Total is the one of the colum in the table.I am arranging the rows in the table in the DESC order with the following query.
Select Name,Total from tbl_one group by Toal DESC
Now my requirment is after getting this result I need to give number to each record starting from first. like
John 500 1
Sam 490 2
David 480 3 and till 100
Please suggest me the best way of doing this. I am using SQL Server 2008 R2.
Your query will not work. But this is the method used to select an enumerating column:
SELECT Name, Total, ROW_NUMBER() OVER(ORDER BY Total DESC) AS RN
FROM tbl_one
ORDER BY RN ASC
You can do this with ROW_NUMBER window function:
select Name, Total, Row_Number() Over(Order By Total DESC) as RowIndex
from tbl_one
order by RowIndex
PS: in Sql Server you call it ROW not RECORD.
You could use the row_number window function:
SELECT Name, Total, ROW_NUMBNER() OVER (ORDER BY Total)
FROM tbl_one
ORDER BY Toal DESC
SELECT
Name,
Total,
Index = ROW_NUMBER() OVER(PARTITION BY [Total] ORDER BY [Total])
FROM tbl_one
To retain the grouping
DECLARE #startnum INT=400
DECLARE #endnum INT=1400
;
WITH gen AS (
SELECT #startnum AS num
UNION ALL
SELECT num+10 FROM gen WHERE num + 1<=#endnum
)
SELECT 'Some name',num,ROW_NUMBER()OVER( ORDER BY num DESC) FROM gen order by num desc
option (maxrecursion 10000)

In SQL Server how can I fetch all rows with a date greater than some set date or at least 20 rows

I'm looking for a way to fetch at least 20 rows, regardless of the date or all rows with a date greater than a set date (whichever of the 2 fetches the most rows).
For example:
SELECT *
FROM table1
WHERE the_date >= '2014-11-01'
ORDER BY the_date DESC
will give me what I want, but if this returns less than 20 rows then I want to keep going before that date until I get 20 (or until there are no more rows - whichever comes first).
I could just select all and take the ones I need programatically, but I'm trying to avoid that as that would be a major change to the actual code in many places.
Can this be done?
Note: I am using SQL Server 2008.
Here's an approach:
select *
from
(
select row_number() over (order by the_date desc) num, t.*
from table1 t
) i
where i.the_date >= '2014-11-01'
or i.num < 21
Very strange requirement but something like this should work.
DECLARE #Date date = '2014-11-01';
with MyResults as
(
SELECT *, 1 as RowNum
FROM table1
WHERE (the_date >= #Date )
UNION ALL
SELECT top 10 *, ROW_NUMBER() over(order by the_date desc)
FROM table1
order by the_date desc
)
Select *
from MyResults
where RowNum <= 20
The right answer was almost there, but the user has removed it, so here it is again:
SELECT *
FROM table1
WHERE the_date >= '2014-11-01'
union
SELECT top 20 *
FROM table1
ORDER BY the_date desc
The removed answer had union all
This answer has a problem with duplicate dates , but with the data I have that is not an issue

How to use RANK() in SQL Server

I have a problem using RANK() in SQL Server.
Here’s my code:
SELECT contendernum,
totals,
RANK() OVER (PARTITION BY ContenderNum ORDER BY totals ASC) AS xRank
FROM (
SELECT ContenderNum,
SUM(Criteria1+Criteria2+Criteria3+Criteria4) AS totals
FROM Cat1GroupImpersonation
GROUP BY ContenderNum
) AS a
The results for that query are:
contendernum totals xRank
1 196 1
2 181 1
3 192 1
4 181 1
5 179 1
What my desired result is:
contendernum totals xRank
1 196 1
2 181 3
3 192 2
4 181 3
5 179 4
I want to rank the result based on totals. If there are same value like 181, then two numbers will have the same xRank.
Change:
RANK() OVER (PARTITION BY ContenderNum ORDER BY totals ASC) AS xRank
to:
RANK() OVER (ORDER BY totals DESC) AS xRank
Have a look at this example:
SQL Fiddle DEMO
You might also want to have a look at the difference between RANK (Transact-SQL) and DENSE_RANK (Transact-SQL):
RANK (Transact-SQL)
If two or more rows tie for a rank, each tied rows receives the same
rank. For example, if the two top salespeople have the same SalesYTD
value, they are both ranked one. The salesperson with the next highest
SalesYTD is ranked number three, because there are two rows that are
ranked higher. Therefore, the RANK function does not always return
consecutive integers.
DENSE_RANK (Transact-SQL)
Returns the rank of rows within the partition of a result set, without
any gaps in the ranking. The rank of a row is one plus the number of
distinct ranks that come before the row in question.
To answer your question title, "How to use Rank() in SQL Server," this is how it works:
I will use this set of data as an example:
create table #tmp
(
column1 varchar(3),
column2 varchar(5),
column3 datetime,
column4 int
)
insert into #tmp values ('AAA', 'SKA', '2013-02-01 00:00:00', 10)
insert into #tmp values ('AAA', 'SKA', '2013-01-31 00:00:00', 15)
insert into #tmp values ('AAA', 'SKB', '2013-01-31 00:00:00', 20)
insert into #tmp values ('AAA', 'SKB', '2013-01-15 00:00:00', 5)
insert into #tmp values ('AAA', 'SKC', '2013-02-01 00:00:00', 25)
You have a partition which basically specifies grouping.
In this example, if you partition by column2, the rank function will create ranks for groups of column2 values. There will be different ranks for rows where column2 = 'SKA' than rows where column2 = 'SKB' and so on.
The ranks are decided like this:
The rank for every record is one plus the number of ranks that come before it in its partition. The rank will only increment when one of the fields you selected (other than the partitioned field(s)) is different than the ones that come before it. If all of the selected fields are the same, then the ranks will tie and both will be assigned the value, one.
Knowing this, if we only wanted to select one value from each group in column two, we could use this query:
with cte as
(
select *,
rank() over (partition by column2
order by column3) rnk
from t
) select * from cte where rnk = 1 order by column3;
Result:
COLUMN1 | COLUMN2 | COLUMN3 |COLUMN4 | RNK
------------------------------------------------------------------------------
AAA | SKB | January, 15 2013 00:00:00+0000 |5 | 1
AAA | SKA | January, 31 2013 00:00:00+0000 |15 | 1
AAA | SKC | February, 01 2013 00:00:00+0000 |25 | 1
SQL DEMO
You have to use DENSE_RANK rather than RANK. The only difference is that it doesn't leave gaps. You also shouldn't partition by contender_num, otherwise you're ranking each contender in a separate group, so each is 1st-ranked in their segregated groups!
SELECT contendernum,totals, DENSE_RANK() OVER (ORDER BY totals desc) AS xRank FROM
(
SELECT ContenderNum ,SUM(Criteria1+Criteria2+Criteria3+Criteria4) AS totals
FROM dbo.Cat1GroupImpersonation
GROUP BY ContenderNum
) AS a
order by contendernum
A hint for using StackOverflow, please post DDL and sample data so people can help you using less of their own time!
create table Cat1GroupImpersonation (
contendernum int,
criteria1 int,
criteria2 int,
criteria3 int,
criteria4 int);
insert Cat1GroupImpersonation select
1,196,0,0,0 union all select
2,181,0,0,0 union all select
3,192,0,0,0 union all select
4,181,0,0,0 union all select
5,179,0,0,0;
DENSE_RANK() is a rank with no gaps, i.e. it is “dense”.
select Name,EmailId,salary,DENSE_RANK() over(order by salary asc) from [dbo].[Employees]
RANK()-It contain gap between the rank.
select Name,EmailId,salary,RANK() over(order by salary asc) from [dbo].[Employees]
You have already grouped by ContenderNum, no need to partition again by it.
Use Dense_rank()and order by totals desc.
In short,
SELECT contendernum,totals, **DENSE_RANK()**
OVER (ORDER BY totals **DESC**)
AS xRank
FROM
(
SELECT ContenderNum ,SUM(Criteria1+Criteria2+Criteria3+Criteria4) AS totals
FROM dbo.Cat1GroupImpersonation
GROUP BY ContenderNum
) AS a
SELECT contendernum,totals, RANK() OVER (ORDER BY totals ASC) AS xRank FROM
(
SELECT ContenderNum ,SUM(Criteria1+Criteria2+Criteria3+Criteria4) AS totals
FROM dbo.Cat1GroupImpersonation
GROUP BY ContenderNum
) AS a
RANK() is good, but it assigns the same rank for equal or similar values. And if you need unique rank, then ROW_NUMBER() solves this problem
ROW_NUMBER() OVER (ORDER BY totals DESC) AS xRank
Select T.Tamil, T.English, T.Maths, T.Total, Dense_Rank()Over(Order by T.Total Desc) as Std_Rank From (select Tamil,English,Maths,(Tamil+English+Maths) as Total From Student) as T
enter image description here

Resources