Need to skip Dense Rank in SQL Server - sql-server

I want to generate Dense_Rank on a particular column but I want to provide default Rank on few value but the sequence should not break any suggestion.

What you want is:
select *,
dense_rank() over (order by case when id <> 3 then id end)-1 as Ranking
from test
order by id;
DBFiddle demo
Probably this was what you meant in your comment:
IF OBJECT_ID('tempdb..#test') IS NOT NULL
DROP TABLE #test
create table #test (id int);
insert into #test (id) values (1),(2),(3),(4),(4),(5),(6),(7);
with mx(id) as
(select max(id) from #test),
data(id, idrev) as (select t.id, mx.id - t.id + 1 from #test t, mx)
select id,
dense_rank() over (order by case when id <> 3 then idrev end)-1 as Ranking
from data order by id;
DBFiddle demo

Related

row number without using the ROW_NUMBER window function

Suppose you have a table with non-unique values such as this:
CREATE TABLE accounts ( fname VARCHAR(20), lname VARCHAR(20))
GO
INSERT accounts VALUES ('Fred', 'Flintstone')
INSERT accounts VALUES ('Fred', 'Flintstone')
INSERT accounts VALUES ('Fred', 'Flintstone')
SELECT * FROM accounts
GO
Now using a ROW_NUMBER function, you can get a unique incrementing row number.
select *, ROW_NUMBER() over(order by (select null)) as rn
from accounts
But how do we this without using a ROW_NUMBER function. I tried giving each row a unique ID using NEWID() and then counting the rows as given below but it did not work as it gives me a non-unique number which does not start with 1.
Note that I do not want to alter the table to add a new column.
;with cte as
(select *
from accounts as e
cross apply (select newid()) as a(id)
)
select *, (select count(*)+1 from cte as c1 where c.id > c1.id) as rn
from cte as c
order by rn
SQL Fiddle for toying around is http://sqlfiddle.com/#!18/c270f/3/0
The following demonstrates why your code fails, but does not provide an alternative to Row_Number().
A column, TopId, is added to the final select that should get the minimum value generated by NewId() and report it in every row. Instead, a new value is generated for each row.
-- Sample data.
declare #Samples as Table ( FName VarChar(20), LName VarChar(20) );
insert into #Samples ( FName, LName ) values
( 'Fred', 'Flintstone' ), ( 'Fred', 'Flintstone' ), ( 'Fred', 'Flintstone' );
select * from #Samples;
-- Cross apply NewId() in a CTE.
;with cte as
( select *
from #Samples as S
cross apply ( select NewId() ) as Ph( Id ) )
select *, ( select count(*) from cte as c1 where c1.Id >= c.Id ) as RN,
-- The following column should output the minimum Id value from the table for every row.
-- Instead, it generates a new unique identifier for each row.
( select top 1 id from cte order by id ) as TopId
from cte as c
order by RN;
The execution plan shows that the CTE is treated as a view that is being evaluated repeatedly, thus generating conflicting Id values.
How about this:
SELECT
src.*,
SUM(DummyVal) OVER(ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS RowId
FROM (
SELECT a.*, 1 AS DummyVal
FROM MyTable a
) src
It's still a window function, though, not sure if that matters.
Fiddle me this
You can create an function yourself to compute the row_number,
In this example, I had to calculate an index for a lesson within a course.
Window Function version:
SELECT *, ROW_NUMBER() OVER(PARTITION BY courseId) AS row_num FROM lessons;
I created helper-function, to compute the row_number without window function:
DELIMITER $$
CREATE FUNCTION getRowNumber (lessonId int, courseId int)
RETURNS int
DETERMINISTIC
BEGIN
DECLARE count int;
select count(l2.id) into count from lessons l2 where l2.courseId=courseId
and l2.id<=lessonId;
RETURN count;
END$$
DELIMITER ;
so, the final query is:
SELECT l.*, getRowNumber(l.id,l.courseId) as row_num FROM lessons l;
got the same result as the first query!
MySQL:
SELECT #rownum := #rownum + 1 AS rank, a.*
FROM accounts a,(SELECT #rownum := 0) r;
In ORACLE it would simply be
SELECT ROWNUM, a.*
FROM accounts a;
Both without window

Select record from SQL Server like data below

I have record like below in SQL Server.
Id RefId FromRefId
1 RH01 RH00
2 RH02 RH01
3 RH03 RH01
4 RH04 RH03
5 RH05 RH02
6 RH06 RH03
7 RH07 RH04
8 RH08 RH02
9 RH09 RH05
And I want get result like below using Id in where condition
Where Id=1
RH02
RH03
RH04
RH05
RH06
RH07
RH08
RH09
Where Id=2
RH05
RH08
RH09
Where Id=3
RH04
RH06
RH07
Where Id=4
RH07
Where Id=5
RH09
Thanks, please guide me how can I achieve this?
Since you want to obtain all the references following the chain of FromRefId you need to use a recursive query, which can be achieved in SQL Server using a recursive common table expression:
with Recursive_IDs (Id, RefId, FromRefId) as (
-- anchor query
select Id, RefId, FromRefId
from IDs
union all
-- recursive query
select IDs.Id, IDs.RefID, Recursive_IDs.FromRefId
from IDs
inner join Recursive_IDs on Recursive_IDs.RefId=IDs.FromRefId
)
select Recursive_IDs.RefId
from Recursive_IDs
join IDs on Recursive_IDs.FromRefID=IDs.RefID
where IDs.id = [the id you want]
SQL fiddle
Note that if instead of searching by Id you search by RefId you can simplify the query a bit:
with Recursive_IDs (Id, RefId, FromRefId) as (
-- anchor query
select Id, RefId, FromRefId
from IDs
union all
-- recursive query
select IDs.Id, IDs.RefID, Recursive_IDs.FromRefId
from IDs
inner join Recursive_IDs on Recursive_IDs.RefId=IDs.FromRefId
)
select Recursive_IDs.RefId
from Recursive_IDs
where FromRefId = [the RefId you want]
You can use the below approach. I have written a Table-valued function, "GetChild". It iterates through the records recursively to get all dependencies, and finally get the RefId for all those dependencies.
Create table hierarchy (Id int, RefId varchar(10), FromRefId varchar(10))
GO
insert into hierarchy
select 1,'RH01','RH00' union all
select 2,'RH02','RH01' union all
select 3,'RH03','RH01' union all
select 4,'RH04','RH03' union all
select 5,'RH05','RH02' union all
select 6,'RH06','RH03' union all
select 7,'RH07','RH04' union all
select 8,'RH08','RH02' union all
select 9,'RH09','RH05'
GO
-- Table valued Function
GO
create function GetChild (#Id INT)
RETURNS #temp TABLE (RefId varchar(10))
AS
BEGIN
declare #tempDependencies table (Id int)
insert into #tempDependencies SELECT #Id
WHILE ((Select COUNT(Id) from hierarchy where FromRefId in (select RefId from hierarchy where id in (select Id from #tempDependencies) ) and id not in (select Id from #tempDependencies)) > 0)
BEGIN
insert into #tempDependencies
Select Id from hierarchy where FromRefId in (select RefId from hierarchy where id in (select Id from #tempDependencies) ) and id not in (select Id from #tempDependencies)
END
insert into #temp
Select RefId from hierarchy where FromRefId in (select RefId from hierarchy where id in (SELECT Id from #tempDependencies))
return
END
GO
-- You may call the functions like this:
select * from GetChild(1)
select * from GetChild(2)
select * from GetChild(3)
SQL Fiddle Code
Should be a simple query
SELECT * FROM your_table_name WHERE Id = your_desired_id
Why the downgrade? Isn’t that what you were looking for? I don’t think your question is clear. Which Id is being referred here?!

How to find the maximum value in join without using if in sql stored procedure

I have a two tables like below
A
Id Name
1 a
2 b
B
Id Name
1 t
6 s
My requirement is to find the maximum id from table and display the name and id for that maximum without using case and if.
i findout the maximum by using below query
SELECT MAX(id)
FROM (SELECT id,name FROM A
UNION
SELECT id,name FROM B) as c
I findout the maximum 6 using the above query.but i can't able to find the name.I tried the below query but it's not working
SELECT MAX(id)
FROM (SELECT id,name FROM A
UNION
SELECT id,name FROM B) as c
How to find the name?
Any help will be greatly appreciated!!!
First combine the tables, since you need to search both. Next, determine the id you need. JOIN the id back with the temporarily created table to retreive the name that belongs to that id:
WITH tmpTable AS (
SELECT id,name FROM A
UNION
SELECT id,name FROM B
)
, max AS (
SELECT MAX(id) id
FROM tmpTable
)
SELECT t.id, t.name
FROM max m
JOIN tmpTable t ON m.id = t.id
You could use ROW_NUMBER(). You have to UNION ALL TableA and TableB first.
WITH TableA(Id, Name) AS(
SELECT 1, 'a' UNION ALL
SELECT 2, 'b'
)
,TableB(Id, Name) AS(
SELECT 1, 't' UNION ALL
SELECT 6, 's'
)
,Combined(Id, Name) AS(
SELECT * FROM TableA UNION ALL
SELECT * FROM TableB
)
,CTE AS(
SELECT *, RN = ROW_NUMBER() OVER(ORDER BY ID DESC) FROM Combined
)
SELECT Id, Name
FROM CTE
WHERE RN = 1
Just order by over the union and take first row:
SELECT TOP 1 * FROM (SELECT * FROM A UNION SELECT * FROM B) x
ORDER BY ID DESC
This won't show ties though.
For you stated that you used SQL Server 2008. Therefore,I used FULL JOIN and NESTED SELECT to get what your looking for. See below:
SELECT
(SELECT
1,
ISNULL(A.Id,B.Id)Id
FROM A FULL JOIN B ON A.Id=B.Id) AS Id,
(SELECT
1,
ISNULL(A.Name,B.Name)Name
FROM A FULL JOIN B ON A.Id=B.Id) AS Name
It's possible to use ROW_NUMBER() or DENSE_RANK() functions to get new numiration by Id, and then select value with newly created orderId equal to 1
Use:
ROW_NUMBER() to get only one value (even if there are some repetitions of max id)
DENSE_RANK() to get all equal max id values
Here is an example:
DECLARE #tb1 AS TABLE
(
Id INT
,[Name] NVARCHAR(255)
)
DECLARE #tb2 AS TABLE
(
Id INT
,[Name] NVARCHAR(255)
)
INSERT INTO #tb1 VALUES (1, 'A');
INSERT INTO #tb1 VALUES (7, 'B');
INSERT INTO #tb2 VALUES (4, 'C');
INSERT INTO #tb1 VALUES (7, 'D');
SELECT * FROM
(SELECT Id, Name, ROW_NUMBER() OVER (ORDER BY Id DESC) AS [orderId]
FROM
(SELECT Id, Name FROM #tb1
UNION
SELECT Id, Name FROM #tb2) as tb3) AS TB
WHERE [orderId] = 1
SELECT * FROM
(SELECT Id, Name, DENSE_RANK() OVER (ORDER BY Id DESC) AS [orderId]
FROM
(SELECT Id, Name FROM #tb1
UNION
SELECT Id, Name FROM #tb2) as tb3) AS TB
WHERE [orderId] = 1
Results are:

Updating Sql Server Row with increasing ID

How do I update sql server with increasing ID according to another column?
I have a table with following structure:
sn name val
test 0
test 0.5
test 2
test1 0
test1 0.5
test1 2
How do i update it so that is will be:
sn name val
1 test 0
2 test 0.5
3 test 2
1 test1 0
2 test1 0.5
3 test1 2
fiddle
Use cte and row_number
Here is an example :
create table #mytable (sn int, name varchar(20), val money)
insert into #mytable values (null, 'test', 0.5)
insert into #mytable values (null, 'test', 1)
insert into #mytable values (null, 'test1', 0.5)
insert into #mytable values (null, 'test1', 1)
;with cte as (select row_number() over (order by name, val) as rn, * from #mytable)
update cte set sn = rn
select * from #mytable
This can easily be done using Row_Number() and the OVER ... PARTITION BY clause, if you have a key column in the table. I added a column: Id int identity primary key and here's the update:
;with RowNumberedData as (
select
id,
row_number() over (
partition by name
order by id
) as rowno
from sql_test
)
update s
set sn = r.rowno
from sql_test s
join RowNumberedData r
on s.id = r.id;
SQLFiddle: http://sqlfiddle.com/#!3/43fa8/4
You should use ROW_NUMBER() function. Also as soon as you have to start new counter for each NAME value you should use PARTITON by NAME in this statement.
WITH T AS
(select sql_test.*,
ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Val) as RowNumber
from sql_test)
UPDATE T SET SN=RowNumber;
SQLFiddle demo

How to use row_number() in SQL Server

I want to update row data where the row_number of the column (p_id) is 1.. but this syntax is providing error:
update app1
set p_id = 1
where Row_Number() = 1 over(p_id)
You can't use ROW_NUMBER() directly - you need to e.g. use a CTE (Common Table Expression) for that:
;WITH DataToUpdate AS
(
SELECT
SomeID,
p_id,
ROW_NUMBER() OVER(ORDER BY .......) AS 'RowNum'
FROM
dbo.app1
)
UPDATE DataToUpdate
SET p_id = 1
WHERE
RowNum = 1
In order to use the ROW_NUMBER function, you also need at least an ORDER BY clause to define an order by which the rows are ordered.
From your question, it's not very clear what criteria (column) you want to order by to determine your ROW_NUMBER(), and it's also not clear what kind of column there is to uniquely identify a row (so that the UPDATE can be applied)
This will update only the first employee of that age. May be used as a lottery type logic
create table emp(name varchar(3),Age int, Salary int, IncentiveFlag bit)
insert into emp values('aaa',23,90000,0);
insert into emp values('bbb',22,50000,0);
insert into emp values('ccc',63,60000,0);
insert into emp values('ddd',53,50000,0);
insert into emp values('eee',23,80000,0);
insert into emp values('fff',53,50000,0);
insert into emp values('ggg',53,50000,0);
update A
set IncentiveFlag=1
from
(
Select row_number() over (partition by Age order by age ) AS SrNo,* from emp
)A
where A.SrNo=1
TO Delete duplicates ;WITH CTE(Name,Address1,Phone,RN)
AS
(
SELECT Name,Address1,Phone,
ROW_NUMBER() OVER(PARTITION BY Name ORDER BY Name) AS RN
)
DELETE FROM CTE WHERE RN > 1

Resources