Getting 4th row of query result - sql-server

I am using Microsoft SQL Server 2012 and I have this query (below). It returns everything correctly but I cannot figure out how to get only the 4th row to return.
I know how to do it with a simple query but with a query this complex I don't know how to only return the 4th row. Since I am using MS SQL Server, I cannot use Limit/Offset. How and where should I place code to only print the 4th row? I'm stumped. Thanks.
SELECT T.[First Name],
T.[Last Name],
T.[Middle Name],
T.[Country Name],
T.[Designation Name],
Salary.Emp_Salary AS 'Current Salary'
FROM
(
SELECT
Emp_First_Name AS "First Name",
Emp_Last_Name AS "Last Name",
Emp_Middle_Name AS "Middle Name",
Country_Name AS "Country Name",
Desig_Name as "Designation Name",
MAX(Emp_Salary_Change_Year) AS "Time"
FROM Employee_Details
INNER JOIN Country ON Employee_Details.Emp_Country_Id = Country.Country_Id
INNER JOIN State ON Employee_Details.Emp_State_Id = State.State_Id
INNER JOIN Designation ON Employee_Details.Desig_Id = Designation.Desig_Id
INNER JOIN Salary ON Employee_Details.Emp_Id = Salary.Emp_Id
GROUP BY Emp_First_Name, Emp_Last_Name,
Emp_Middle_Name, Country_Name, Desig_Name) AS T
INNER JOIN Salary ON T.Time = Salary.Emp_Salary_Change_Year
ORDER BY [Current Salary];

Use a CTE with ROW_NUMBER()
;WITH Cte AS
(
SELECT Col1, Col2, ...,
ROW_NUMBER() OVER (ORDER BY ...) AS RowNum
FROM Table
)
SELECT *
FROM Cte
WHERE RowNum = 4

You can also, use the OFFSET/FETCH keyword.
SELECT *
FROM yourTable
ORDER by yourSortColumn
OFFSET 3 ROWS -- Skip Three rows.
FETCH FIRST 1 ROW ONLY;

You can use TOP this way (first you select only 4 rown and the ordering desc select 1 row)
select TOP 1 from (
SELECT TOP 4 T.[First Name],
T.[Last Name],
T.[Middle Name],
T.[Country Name],
T.[Designation Name],
Salary.Emp_Salary AS 'Current Salary'
FROM
(
SELECT
........
) AS T
INNER JOIN Salary ON T.Time = Salary.Emp_Salary_Change_Year
ORDER BY [Current Salary])
ORDER BY [Current Salary] DESC

Related

How do I select the top 1 results of the if the same identifier exist? SQL Server

I have a data table in sql server 2008 that I would like to select the top 1 out of each identifier:
The results shld looks like this during before and after:
Thus it should only select the 1st results if the same identifier do exist. Thanks a lot.
select distinct [Primary Identifier] from tbl
If you have entire records (other columns) instead of that single column, you can row number them and choose one.
select {list of columns}
from
(
select *, rn = row_number over (partition by [Primary Identifier]
order by 1/0)
from tbl
) X
where rn = 1;
order by 1/0 is arbitrary. If you need to choose a specific one from the "duplicates", for example the highest cost, you order by cost descending, i.e.
(partition by [Primary Identifier]
order by [cost] descending)
Just distinct them:
select distinct [primary identifier] from tablename
Or by grouping:
select [primary identifier] from tablename group by [primary identifier]
If more columns exist you can rank rows with window function:
;with cte as(select *, row_number() over(partition by [primary identifier] order by (select null)) rn from tablename)
select * from cte where rn = 1
Change order by (select null) to appropriate ordering column.
i think this will be an appropriate solution to your need-
;WITH cte AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY [Primary Identifier] ORDER BY [sort columns]) AS rowid
FROM [table]
)
SELECT *
FROM cte
WHERE rowid = 1

Select Multiple Columns join SQL Server

I have an Employee table like this
And a second table for EmployeeComments with the EmployeeID as foreign key:
I would like to query the employees with their comments in the following format:
select Name, Comment
from Employee emp
left join EmployeeComments empC on empC.EmployeeID = emp.ID
I would like the results to be like:
I have already looked at Pivot, but it doesn't resolve my issue
Use window function:
select case when row_number() over(partition by emp.name order by empC.ID) = 1
then Name
else '' end as Name,
Comment
from Employee emp
left join EmployeeComments empC On empC.EmployeeID = emp.ID
This might give you some kind of order in your result window at least
WITH cte AS(
SELECT emp.Name ,
empC.Comment,
RANK() OVER (ORDER BY emp.Name) NameOrder,
ROW_NUMBER() OVER (PARTITION BY emp.Name ORDER BY empC.ID) RN
FROM Employee emp
LEFT JOIN EmployeeComments empC ON empC.EmployeeID = emp.ID
)
SELECT
Name = (CASE WHEN RN = 1 THEN Name ELSE '' END),
Comment
FROM
cte
ORDER BY
NameOrder,
RN
"use Cross Join:"
Query:
select case t.cnt
when 1 then
coalesce(t.Name,' ')
end as Name,t.comment
from
(
select t1.Name,t2.comment,row_number()
over(partition by t1.name order by t1.Name)
as cnt
from
EmployeeComments t1
cross join
Employee t2
where t1.ID=t2.Employeeid
)t

Place Data from Same Column in Different Columns in Resultset

I have a request I wasn't sure to handle. I was thinking of using PIVOT, but I wasn't sure if that would be the way to go.
I have the following Data:
EmployeeA, DepartmentB, 1/10/2010
EmployeeA, DepartmentA, 1/1/2000
EmployeeB, DepartmentC, 1/3/2011
They want output for only the employees that have been in different departments. Something that looks like this (order is important due to the dates):
EmployeeA, DepartmentA, DepartmentB
Any help is appreciated. For some reason, my mind isn't finding a good solution.
You can do this by doing a self JOIN on the table and then using a PIVOT to get the data in the format that you want:
SELECT *
FROM
(
SELECT t1.emp, t1.dept, t1.dt
FROM test t1
INNER JOIN test t2
ON t1.emp = t2.emp
AND t1.dept != t2.dept
) x
PIVOT
(
min(dt)
for dept in ([A], [B], [C], [D], [E])
) p
See SQL Fiddle with Demo
If you remove the JOIN you will get all records, but you stated you only want the records that have been in more than one department.
Here's the answer I got which I got largely based on your work. Pivot doesn't work because I don't know the categories (in this case Department) ahead of time and I can only have two of them.
Maybe there's an easier way. I didn't use a CTE, because I believe this should work for Sybase as well which I don't think supports that.
select Meta1.[Employee ID],
Meta1.Department as PreviousDepartment,
Meta2.Department as CurrentDepartment
from
(
SELECT t1.[First Name], t1.[Last Name],
t1.[Employee ID], t1.Department, t1.[Hire Date],
ROW_NUMBER() over(PARTITION by t1.[EMPLOYEE ID] order by t1.[Hire Date]) as RowNum
FROM EMPLOYEE t1
INNER JOIN EMPLOYEE t2
ON t1.[Employee ID] = t2.[Employee ID]
AND t1.Department != t2.Department
) Meta1
inner join
(
SELECT t1.[Employee ID], t1.Department, t1.[Hire Date],
ROW_NUMBER() over(PARTITION by t1.[EMPLOYEE ID] order by t1.[Hire Date]) as RowNum
FROM EMPLOYEE t1
INNER JOIN EMPLOYEE t2
ON t1.[Employee ID] = t2.[Employee ID]
AND t1.Department != t2.Department
) Meta2
on Meta1.[Employee ID]=Meta2.[Employee ID]
where Meta1.RowNum=1
and Meta2.RowNum=2

RANK() Over Partition BY not working

When I run the code below the ROWID is always 1.
I need to the ID to start at 1 for each item with the same Credit Value.
;WITH CTETotal AS (SELECT
TranRegion
,TranCustomer
,TranDocNo
,SUM(TranSale) 'CreditValue'
FROM dbo.Transactions
LEFT JOIN customers AS C
ON custregion = tranregion
AND custnumber = trancustomer
LEFT JOIN products AS P
ON prodcode = tranprodcode
GROUP BY
TranRegion
,TranCustomer
,TranDocNo)
SELECT
r.RegionDesc
,suppcodedesc
,t.tranreason as [Reason]
,t.trandocno as [Document Number]
,sum(tranqty) as Qty
,sum(tranmass) as Mass
,sum(transale) as Sale
,cte.CreditValue AS 'Credit Value'
,RANK() OVER (PARTITION BY cte.CreditValue ORDER BY cte.CreditValue)AS ROWID
FROM transactions t
LEFT JOIN dbo.Regions AS r
ON r.RegionCode = TranRegion
LEFT JOIN CTETotal AS cte
ON cte.TranRegion = t.TranRegion
AND cte.TranCustomer = t.TranCustomer
AND cte.TranDocNo = t.TranDocNo
GROUP BY
r.RegionDesc
,suppcodedesc
,t.tranreason
,t.trandocno
,cte.CreditValue
ORDER BY CreditValue ASC
EDIT
All the credit values with 400 must have the ROWID set to 1. And all the credit values with 200 must have the ROWID set to 2. And so on and so on.
Do you need something like this?
with cte (item,CreditValue)
as
(
select 'a',8 as CreditValue union all
select 'b',18 union all
select 'a',8 union all
select 'b',18 union all
select 'a',8
)
select CreditValue,dense_rank() OVER (ORDER BY item)AS ROWID from cte
Result
CreditValue ROWID
----------- --------------------
8 1
8 1
8 1
18 2
18 2
In your code replace
,RANK() OVER (PARTITION BY cte.CreditValue ORDER BY cte.CreditValue)AS ROWID
by
,DENSE_RANK() OVER (ORDER BY cte.CreditValue)AS ROWID
You just don't have to use PARTITION, just DENSE_RANK() OVER (ORDER BY cte.CreditValue)
I think the problem is with the RANK() OVER (PARTITION BY clause
you have to partition it by item not by CreditValue
Try this
RANK() OVER (PARTITION BY cte.CreditValue ORDER BY cte.RegionDesc)AS ROWID
Edit: The issue here isn't actually the nesting of the subquery, it's potentially based on partition by having columns that truly make each row unique (or 1)
Rather than ranking within your complex query like this
select
rank() over(partition by...),
*
from
data_source
join table1
join table2
join table3
join table4
order by
some_column
Try rank() or row_number() on the resulting data set, not within it.
For example, using the query above, remove rank() and implement it this way:
select
rank() over(partition by...),
results.*
from (
select
*
from
data_source
join table1
join table2
join table3
join table4
order by
some_column
) as results

select top 1 with a group by

I have two columns:
namecode name
050125 chris
050125 tof
050125 tof
050130 chris
050131 tof
I want to group by namecode, and return only the name with the most number of occurrences. In this instance, the result would be
050125 tof
050130 chris
050131 tof
This is with SQL Server 2000
I usually use ROW_NUMBER() to achieve this. Not sure how it performs against various data sets, but we haven't had any performance issues as a result of using ROW_NUMBER.
The PARTITION BY clause specifies which value to "group" the row numbers by, and the ORDER BY clause specifies how the records within each "group" should be sorted. So partition the data set by NameCode, and get all records with a Row Number of 1 (that is, the first record in each partition, ordered by the ORDER BY clause).
SELECT
i.NameCode,
i.Name
FROM
(
SELECT
RowNumber = ROW_NUMBER() OVER (PARTITION BY t.NameCode ORDER BY t.Name),
t.NameCode,
t.Name
FROM
MyTable t
) i
WHERE
i.RowNumber = 1;
select distinct namecode
, (
select top 1 name from
(
select namecode, name, count(*)
from myTable i
where i.namecode = o.namecode
group by namecode, name
order by count(*) desc
) x
) as name
from myTable o
SELECT max_table.namecode, count_table2.name
FROM
(SELECT namecode, MAX(count_name) AS max_count
FROM
(SELECT namecode, name, COUNT(name) AS count_name
FROM mytable
GROUP BY namecode, name) AS count_table1
GROUP BY namecode) AS max_table
INNER JOIN
(SELECT namecode, COUNT(name) AS count_name, name
FROM mytable
GROUP BY namecode, name) count_table2
ON max_table.namecode = count_table2.namecode AND
count_table2.count_name = max_table.max_count
I did not try but this should work,
select top 1 t2.* from (
select namecode, count(*) count from temp
group by namecode) t1 join temp t2 on t1.namecode = t2.namecode
order by t1.count desc
Here are to examples that you could use but the temp table use is more efficient than the view, but was done on a small data sample. You would want to check your own statistics.
--Creating A View
GO
CREATE VIEW StateStoreSales AS
SELECT t.state,t.stor_id,t.stor_name,SUM(s.qty) 'TotalSales'
,ROW_NUMBER() OVER (PARTITION BY t.state ORDER BY SUM(s.qty) DESC) AS 'Rank'
FROM [dbo].[sales] s
JOIN [dbo].[stores] t ON (s.stor_id = t.stor_id)
GROUP BY t.state,t.stor_id,t.stor_name
GO
SELECT * FROM StateStoreSales
WHERE Rank <= 1
ORDER BY TotalSales Desc
DROP VIEW StateStoreSales
---Using a Temp Table
SELECT t.state,t.stor_id,t.stor_name,SUM(s.qty) 'TotalSales'
,ROW_NUMBER() OVER (PARTITION BY t.state ORDER BY SUM(s.qty) DESC) AS 'Rank' INTO #TEMP
FROM [dbo].[sales] s
JOIN [dbo].[stores] t ON (s.stor_id = t.stor_id)
GROUP BY t.state,t.stor_id,t.stor_name
SELECT * FROM #TEMP
WHERE Rank <= 1
ORDER BY TotalSales Desc
DROP TABLE #TEMP

Resources