Order by most duplicate record first - sql-server

create table tbl_dup
(
name varchar(100)
);
insert into tbl_dup values('Arsel Rous'),('Oram Rock'),('Oram Rock'),('Brown Twor'),
('John Mak'),('Mak Dee'),('Smith Will'),('Mak Dee'),
('John Mak'),('Oram Rock'),('John Mak'),('Oram Rock');
Query: I am looking for ordering the duplicate records should display at first level in the result set.
select *
from
(
select name,row_number() over(partition by name order by name) rn
from tbl_dup
) a
order by name,rn;
Getting:
name rn
--------------
Arsel Rous 1
Brown Twor 1
John Mak 1
John Mak 2
John Mak 3
Mak Dee 1
Mak Dee 2
Oram Rock 1
Oram Rock 2
Oram Rock 3
Oram Rock 4
Smith Will 1
Expected Result:
name rn
---------------
Oram Rock 1
Oram Rock 2
Oram Rock 3
Oram Rock 4
John Mak 1
John Mak 2
John Mak 3
Mak Dee 1
Mak Dee 2
Arsel Rous 1
Brown Twor 1

Try using COUNT as an analytic function in the ORDER BY clause:
SELECT name, ROW_NUMBER() OVER (PARTITION by name ORDER BY name) rn
FROM tbl_dup
ORDER BY COUNT(*) OVER (PARTITION BY name) DESC, rn;
Demo

You need to first order by the number of occurrence desc and row number by asc.
select name,rn
from
(
select name,row_number() over(partition by name order by name) rn ,
count(*) over(partition by name) ct
from tbl_dup
) a
order by ct desc, rn asc

Related

Create Hierarchy from Ordered Table

I have a table that has parent-child relationship in one column.
I can use a row number that has been added when the file was loaded to sort the table into the correct order.
I would like to get a full hierarchy from the column using the sort order
Sample Data
RowNumber Type Area Name
1 1 Europe Bob
2 2 Scotland Bill
3 3 Edinburgh Dave
4 2 England Sharron
5 3 London Tessa
6 2 Spain Steve
7 2 Portugal Carie
8 1 Asia Helen
9 2 Thailand John
1 2 Japan Frank
11 3 Tokyo Kate
12 3 Osaka Brian
13 1 North America Joe
I would like to be able to say exclude rows where level 1 = Asia.
Happy to use temporary tables or anything to get this working!
Help!
I'm going by a guess on here, but it looks like you're looking for the previous level with a value of type 1 lower. This isn't how traditional hierarchical data is stored, so we need to fix that.
First some consumable Sample Data:
CREATE TABLE dbo.SampleData (RowNumber int,
[Type] int,
Area varchar(30),
[name] varchar(30));
GO
INSERT INTO dbo.SampleData (RowNumber,
[Type],
Area,
[name])
VALUES(1,1,'Europe','Bob'),
(2,2,'Scotland','Bill'),
(3,3,'Edinburgh','Dave'),
(4,2,'England','Sharron'),
(5,3,'London','Tessa'),
(6,2,'Spain','Steve'),
(7,2,'Portugal','Carie'),
(8,1,'Asia','Helen'),
(9,2,'Thailand','John'),
(10,2,'Japan','Frank'),
(11,3,'Tokyo','Kate'),
(12,3,'Osaka','Brian'),
(13,1,'North America','Joe');
GO
Now we need to add a new column for the parent's ID (row number):
ALTER TABLE dbo.SampleData ADD ParentID int;
Then we need to populate that column:
UPDATE SD
SET ParentID = P.RowNumber
FROM dbo.SampleData SD
CROSS APPLY (SELECT TOP 1 ca.RowNumber
FROM dbo.SampleData ca
WHERE ca.[Type] = SD.[Type] - 1
AND ca.RowNumber < SD.RowNumber
ORDER BY ca.RowNumber DESC) P;
Now we can achieve what you're after, such as getting all rows that aren't related to 'Asia' by use of a rCTE (recursive Common Table Expression):
WITH rCTE AS(
SELECT RowNumber,
[Type],
Area,
[name]
FROM dbo.SampleData
WHERE [Type] = 1
AND Area != 'Asia'
UNION ALL
SELECT SD.RowNumber,
SD.Type,
SD.Area,
SD.name
FROM rCTE r
JOIN dbo.SampleData SD ON r.RowNumber = SD.ParentID)
SELECT r.RowNumber,
r.[Type],
r.Area,
r.[name]
FROM rCTE r;
If you have a known or maximum number of levels
Example
Select *
,ID = RowNumber
,Pt = choose( [Type]-1
,max(case when [Type]=1 then RowNumber end) over (Order By RowNumber)
,max(case when [Type]=2 then RowNumber end) over (Order By RowNumber)
,max(case when [Type]=3 then RowNumber end) over (Order By RowNumber)
,max(case when [Type]=4 then RowNumber end) over (Order By RowNumber)
,max(case when [Type]=5 then RowNumber end) over (Order By RowNumber)
)
From YourTable A
Returns

SQL Server - Group last paid price by customer and product code

I am trying to write a query that will do the following.
I have a table with separate sales order lines on it. Each line details the customer, product sold, the price sold at, and the date of the sale.
I am trying to establish for each product code, what the last price we sold it for was for each separate customer.
For example using my input below I would expect Product code ABC to return '10' for Brian, '20' for Gary, and '50 for Sam.
Below is complete set of results I would expect for all product codes.
Input
Order No Customer Product Code Price Date
-----------------------------------------------------------
1 Brian ABC 10 12/04/2018
2 Brian ABC 14 01/04/2018
3 Gary ABC 20 12/04/2018
4 Gary ABC 35 12/04/2017
5 Sam ABD 40 06/08/2017
6 Sam ABC 50 20/08/2017
7 Adam ABE 20 15/06/2016
8 Adam ABE 30 17/03/2017
Output
Order No Customer Product Code Price Date 1 Brian ABC 10 12/04/2018 3 Gary ABC 20 12/04/2018 6 Sam ABC 50 20/08/2017 5 Sam ABD 40 06/08/2017 8 Adam ABE 30 17/03/2017
You can you Row_number() with partition BY [product code], [customer] for this.
Following query should work for you scenario
SELECT *
FROM (SELECT [order no],
[customer],
[product code],
[price],
[date],
Row_number()
OVER(
partition BY [product code], [customer]
ORDER BY [date] DESC) AS RN
FROM [table]) T
WHERE T.rn = 1
This is all about the row_number():
Allows you to partition (Similar to group) and provide an order
select top 1 with ties *
from table
order by row_number() over (partition by [Product Code],Customer order by date desc)
I think this is what you are looking for:
select a.* from #temp a join (
select customer, [product code], max(Date) maxdate
from #temp
group by customer, [product code])b
on a.customer=b.customer and a.date=b.maxdate and a.[product code]=b.[product code]

sequence Rank in query

I would like to get sequence number in mssql. Please see below.
There is a table.
UserID Score TeamID
------------------------------
1 100 1
2 200 1
3 500 2
4 600 2
5 700 2
6 1000 3
I would like to sort by total score group by team. see below
RankID UserID Score TeamID TotalScore
-----------------------------------------------------------
1 3 500 2 1800
1 4 600 2 1800
1 5 700 2 1800
2 6 1000 3 1000
3 1 100 1 300
3 2 200 1 300
I want to code only one sql query. Help me someone how can I do this? Thanks.
This should work:
;WITH TotalScore AS (
SELECT UserID, Score, TeamID,
SUM(Score) OVER (PARTITION BY TeamID) AS TotalScore
FROM mytable
)
SELECT DENSE_RANK() OVER (ORDER BY TotalScore DESC) AS RankID,
UserID, Score, TeamID, TotalScore
FROM TotalScore
ORDER BY TotalScore DESC, Score
The Common Table Expression used calculates the total score per TeamID using windowed version of SUM. Using DENSE_RANK together with this calculated field we can easily generate the required RankID.
You can try this
SELECT
RANK() OVER(ORDER BY i.TotalScore DESC) AS RankID
,A.*
FROM
(
SELECT
UserID
,Score
,TeamID
,(SELECT SUM(Score) FROM yourTable tb2 WHERE tb2.TeamID = tb1.TeamID) AS TotalScore
FROM yourTable tb1
) A
ORDER BY A.TotalScore DESC
Have a Try with below,
Select DENSE_RANK() over(Order by (Select Sum(Score) from #tablename V where V.TeamID=T.TeamID ) desc )RankID
,*,
Sum(Score) over(Partition by TeamID) TotalScore from #tablename T
order by DENSE_RANK() over(Order by (Select Sum(Score) from #tablename V where V.TeamID=T.TeamID ) desc )
Dense Rank in the 'Order by' to sort the results by RANK Id and the same is used in Select statement, Subquery in the Dense Rank will rank based on the sum(Score) for a TeamID

T-SQL : how to select row with multiple conditions

I have below data set in SQL Server and I need to select the data with conditions in order below:
First, check to see if date_end is 1/1/2099, then select the row that has smallest days gap and skill_group is not SWAT for rows have same employee_id, in this case that is row 2.
Second, for rows that do not have 1/1/2099 date_end, select row that has most recent day date_end, in this case it's row 4.
ID employee_id last_name first_name date_start date_end skill_group
---------------------------------------------------------------------------
1 N05E0F Mike Pamela 12/19/2013 1/1/2099 SWAT
2 N05E0F Mike Pamela 9/16/2015 1/1/2099 Welcome Team
3 NSH8A David Smith 12/19/2013 9/16/2016 Unlicensed
4 NSH8A David Smith 8/16/2015 10/16/2016 CMT
There are many ways to do this. Here are some of them:
top with ties version:
select top 1 with ties
*
from tbl
where skill_group != 'SWAT'
order by
row_number() over (
partition by employee_id
order by date_end desc, datediff(day,date_start,date_end) asc
)
with common_table_expression as () using row_number() version:
with cte as (
select *
, rn = row_number() over (
partition by employee_id
order by date_end desc, datediff(day,date_start,date_end) asc
)
from tbl
where skill_group != 'SWAT'
)
select *
from cte
where rn = 1

ORACLE Join table to select multiple record in 1 row

I have 2 tables
TableA: Main table with 1 record for each Field called ID
TableB: Can contain multiple record for field called ID
I want to select everything based on ID from TableA and TableB in 1 line for the end result
Example
Sample Records
From TableA
ID Name Address
--- ---- ----------
1 Jack 123 blahST
2 John 234 blahAVE
321 Sam 2123 blahWay
From TableB
ID AccNO
-- -------------
1 12345
1 345345
1 443453
2 99999
3 88888
3 77777
End Result should be like
Select TableA.ID,
TableA.Name,
TableA.Address,
TableB.ID,
TableB.AccNO1,
TableB.AccNO2, --if it exist
TableB.AccNO3, --if it exist
TableB.AccNO4, --if it exist MAX
From TableA Full Outer Join TableB on TableB.ID = TableA.ID
TableA.ID TableA.Name TableA.Address TableB.ID TableB.AccNO TableB.AccNO2 TableB.AccNo3,TableB.AccNo4
--------- ----------- -------------- --------- ------------ ------------- ------------- -------------
1 Jack 123 Blahst 1 12345 345345 443453
2 John 234 BlahAVE 2 99999
3 Sam 2123 Blahway 3 88888 7777777
Here are a couple of ways of doing it - one using the PIVOT keyword available in 11g and above, the other using the old-style pivot using MAX() and group by.
Method 1:
with tablea as (select 1 id, 'Jack' name, '123 blahST' address from dual union all
select 2 id, 'John' name, '234 blahAVE' address from dual union all
select 3 id, 'Sam' name, '2123 blahWay' address from dual),
tableb as (select 1 id, 12345 accno from dual union all
select 1 id, 345345 accno from dual union all
select 1 id, 443453 accno from dual union all
select 2 id, 99999 accno from dual union all
select 3 id, 88888 accno from dual union all
select 3 id, 77777 accno from dual),
b_res as (select *
from (select id,
accno,
row_number() over (partition by id order by accno) rn
from tableb)
pivot (max(accno)
for rn in (1 as accno1,
2 as accno2,
3 as accno3,
4 as accno4,
5 as accno5)))
select ta.id ta_id,
ta.name ta_name,
ta.address ta_address,
tb.id tb_id,
tb.accno1 tb_accno1,
tb.accno2 tb_accno2,
tb.accno3 tb_accno3,
tb.accno4 tb_accno4,
tb.accno5 tb_accno5
from tablea ta
inner join b_res tb on ta.id = tb.id;
TA_ID TA_NAME TA_ADDRESS TB_ID TB_ACCNO1 TB_ACCNO2 TB_ACCNO3 TB_ACCNO4 TB_ACCNO5
---------- ------- ------------ ---------- ---------- ---------- ---------- ---------- ----------
1 Jack 123 blahST 1 12345 345345 443453
2 John 234 blahAVE 2 99999
3 Sam 2123 blahWay 3 77777 88888
Method 2:
with tablea as (select 1 id, 'Jack' name, '123 blahST' address from dual union all
select 2 id, 'John' name, '234 blahAVE' address from dual union all
select 3 id, 'Sam' name, '2123 blahWay' address from dual),
tableb as (select 1 id, 12345 accno from dual union all
select 1 id, 345345 accno from dual union all
select 1 id, 443453 accno from dual union all
select 2 id, 99999 accno from dual union all
select 3 id, 88888 accno from dual union all
select 3 id, 77777 accno from dual),
b_res as (select id,
max(case when rn = 1 then accno end) accno1,
max(case when rn = 2 then accno end) accno2,
max(case when rn = 3 then accno end) accno3,
max(case when rn = 4 then accno end) accno4,
max(case when rn = 5 then accno end) accno5
from (select id,
accno,
row_number() over (partition by id order by accno) rn
from tableb)
group by id)
select ta.id ta_id,
ta.name ta_name,
ta.address ta_address,
tb.id tb_id,
tb.accno1 tb_accno1,
tb.accno2 tb_accno2,
tb.accno3 tb_accno3,
tb.accno4 tb_accno4,
tb.accno5 tb_accno5
from tablea ta
inner join b_res tb on ta.id = tb.id;
TA_ID TA_NAME TA_ADDRESS TB_ID TB_ACCNO1 TB_ACCNO2 TB_ACCNO3 TB_ACCNO4 TB_ACCNO5
---------- ------- ------------ ---------- ---------- ---------- ---------- ---------- ----------
1 Jack 123 blahST 1 12345 345345 443453
2 John 234 blahAVE 2 99999
3 Sam 2123 blahWay 3 77777 88888

Resources