Get the first record from the result set - sql

I want to only select the highlighted records. how can i do it in sql and preferably in linq. there is a separate table Emp with EmployeeID as PK.
here is the schema for my tables

I could be way off but I believe following statement satisfies your requirements
SELECT *
FROM (
SELECT e.EmployeeID, h.FromDate, h.ToDate
, rn = ROW_NUMBER() OVER (PARTITION BY e.EmployeeID ORDER BY DesignationID DESC)
FROM employee e
INNER JOIN history h ON h.EmployeeID = e.EmployeeID
) eh
WHERE rn = 1

Try:
select * from
(select t.*,
row_number() over (partition by EmployeeID order by FromDate) as rn) sq
where rn = 1

Can't see exactly what you're asking for. The highlighted ID's are just unique occurrences. So you can do this easily with:
SELECT DISTINCT EmployeeID FROM MyTable

Not sure what you're looking for, but try something like this (no subqueries needed and should work on most DBMS, although it looks like your running SQL Server):
select t1.DisignationHistoryIDs, t1.employeeId, t1.fromDate from history t1
left join history t2
on t1.employeeId = t2.employeeId and t1.fromDate > t2.fromDate
where t2.fromDate is null
This should work to get the oldest fromDate. To get the newest from date just change the > for a <.

Related

Average of top 2

I would like to get the average of the top2 limit1 per policyid. I need my resulting table to also have objectid.
Limit1 and objectid come from the table p_coverage.
Policyid comes from the table p_risk.
The table p_item is a linking table between p_risk and p_coverage.
The way I thought I should build my query is: create a ranking of limit1 within each policyid. Then take the avg top2.
However the ranking doesn't work and give wrong result. My query works if I take columns from ONE table, but as soon as I add joins between them it gives false ranking.
SELECT policyid, limit1, /*pcob,*/ RANK() OVER(PARTITION BY policyid ORDER BY limit1 DESC) AS rn
FROM (SELECT policyid, limit1/*, pc.objectid ASpcob*/
FROM p_risk pr
LEFT JOIN p_item
ON pr.objectid=p_item.riskobjectid
LEFT JOIN p_coverage pc
ON p_item.objectid=pc.insuranceitemid) AS s
) AS SubQueryAlias
GROUP BY
policyid, limit1/*, pcob*/, rn
ORDER BY rn,policyid,limit1 DESC
The table at the end of the picture is what I'd like to have. The first table is the result of the query of Golden Linoff
If I understand correctly, you want the ROW_NUMBER() in the subquery and then to aggregate and filter in the outer query:
SELECT policyid, AVG(limit1) as avg_top2_limit1
FROM (SELECT policyid, limit1,
DENSE_RANK() OVER (PARTITION BY policyid ORDER BY limit1 DESC) as seqnum
FROM p_risk pr LEFT JOIN
p_item i
ON pr.objectid = i.riskobjectid LEFT JOIN
p_coverage pc
ON i.objectid = pc.insuranceitemid) AS s
) p
WHERE seqnum <= 2
GROUP BY policyid
thanks to previous comment! I succeed to do what I wanted. There is the query
select b.policyid, avg(b.limit1) as avg_top2_limit1 from(
SELECT distinct(policyid) policyid, limit1
FROM (SELECT policyid, limit1,
Dense_rank() OVER (PARTITION BY policyid ORDER BY limit1 DESC) as
seqnum
FROM p_risk pr LEFT JOIN
p_item i
ON pr.objectid = i.riskobjectid LEFT JOIN
p_coverage pc
ON i.objectid = pc.insuranceitemid) AS s
WHERE seqnum <= 2 ) as b
GROUP BY policyid`

How to group/aggregate rows in a table based on values in a column

I have a table of chats between buyers and sellers, and in many cases there are chats between the same buyer and a seller (with different chatids), that have different lastactivity dates (shown here in Unix time).
My goal is to be able to query this table so that only a single chatid is returned for each buyer/seller pair, and this chatid corresponds to whichever chat had the most recent lastactivity - so like this:
I've tried:
SELECT max(lastactivity), chatid, buyerid, supplierid,
FROM chat_table
GROUP BY 2,3,4
but this doesn't seem to work...
Anyone able to help?
In Redshift, I would do use window functions:
select ct.*
from (select ct.*,
row_number() over (partition by least(buyerid, supplierid), greatest(buyerid, supplierid)
order by lastactivity
) as seqnum
from chat_table ct
) ct
where seqnum = 1;
Using a simpler approach, using self-JOIN,
SELECT a.buyerid, a.sellerid, a.chatid, a.lastactivity
FROM chat_table a
JOIN (SELECT MAX(lastactivity),buyerid, sellerid FROM chat_table GROUP BY buyerid, sellerid) b
ON a.buyerid = b.buyerid
AND a.sellerid = b.sellerid
AND a.lastactivity = b.lastactivity ;
With NOT EXISTS:
SELECT c.*
FROM chat_table c
WHERE NOT EXISTS (
SELECT 1 FROM chat_table
WHERE buyerid = c.buyerid AND supplierid = c.supplierid AND lastactivity > c.lastactivity
)
select a.lastactivity, a.buyerid, a.supplierid, a.chatid
from (SELECT max(lastactivity) lastactivity, buyerid, supplierid
FROM chat_table
GROUP BY 2,3) a
left join chat_table b on a.buyerid=b.buyerid and a.supplierid=b.supplierid and a.lastactivity=b.kastactivity;
You need to use window function like row_number.
The partition will be the buyer_id and seller_id,
order by the lastactivity.
In the outer query filter the rows where rownumber=1.
https://docs.aws.amazon.com/redshift/latest/dg/c_Window_functions.html
As this question is tagged to aws-redshift. Below query works. Try this.
Select *from chat_table
where (buyerid,sellerid, lastactivity)
IN(
Select buyerid,sellerid, max(lastactivity) as lastactivity
from chat_table
Group by buyerid,sellerid);

Find 2nd Most Recent Date SQL with JOINS

I'm trying to return the second most recent date for a set of projects in SQL, but I'm getting the error 'Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.'
Here is my code:
SELECT ProjectId, max(CreatedDateTime)
FROM NTNote.dbo.nProjectReference P
INNER JOIN NTNote.dbo.nJournal J
ON J.JournalID = P.JournalID
Where CreatedDateTime < (SELECT max(CreatedDateTime), projectid
FROM NTNote.dbo.nProjectReference P
INNER JOIN NTNote.dbo.nJournal J
ON J.JournalID = P.JournalID
Group by ProjectId)
Group by ProjectId
Any help would be greatly appreciated!
use the below code for desired output ( sql server).
with cte_grp
as
(SELECT ProjectId,CreatedDateTime,ROW_NUMBER () OVER(PARTITION BY ProjectId ORDER BY CreatedDateTime desc) RNo
FROM NTNote.dbo.nProjectReference P
INNER JOIN NTNote.dbo.nJournal J
ON J.JournalID = P.JournalID)
SELECT *
FROM cte_grp
WHERE RNO=2
You can use
Row_Number() over (partition by ProjectId order by CreatedDateTime desc) as rownum
and use 2 as predicate to get the output.

How can I fix my GROUP BY clause

I have 2 tables as seen below:
Now the question is :
How can I have a view which shows the details of the last Owner? in other words I need the details of person who has MAX(StartDate) in tbl_Owners table?
I want to find the latest owner of each apartment.
I tried different approaches but I couldn't find the way to do that.
I know I need to get the personID in a Group By clause which groups records by AppID but I can't do that
Thank you
Try this
select t1.* from tbl_persons as t1 inner join
(
select t1.* from tbl_owners as t1 inner join
(
select appid,max(startdate) as startdate from tbl_owners group by appid
) as t2
on t1.appid=t2.appid and t1.startdate=t2.startdate
) as t2
on t1.personid=t2.personid
Add this to your query:
JOIN (select AppId, MAX(StartDate) as MAxStartDate
from dbo.tbl_Owners
group by PersonId) o2
ON dbo.tbl_Owners.AppId= o2.AppId and
dbo.tbl_Owners.StartDate = o2.MAxStartDate
The sub-query above returns every AppId together with it's latest StartDate. Self-joining with that result will give you what you want.
You can USE CTE for this purpose
;WITH CTE AS
(
SELECT AppID,PersonID,StartDate,
ROW_NUMBER() OVER (PARTITION BY AppID ORDER BY StartDate DESC) RN
FROM TableNAme
GROUP BY AppID,PersonID,StartDate
)
SELECT * FROM CTE
WHERE RN=1
Using row_number
select t.*, p.* -- change as needed
from (select *, rn= row_number() over(partition by AppID order by StartDate desc)
from dbo.tbl_Owners
) t
join dbo.tbl_Persons p on t.rn=1 and t.PersonId = p.PersonId
using cross apply
select t.*, p.* -- change as needed
from dbo.tbl_Persons p
cross apply (
select top(1) *
from dbo.tbl_Owners o
where o.PersonId = p.PersonId
order by o.StartDate desc
) t
SELECT dbo.tbl_Owners.*,dbo.tbl_Persons.PersonFullname FROM dbo.tbl_Owners
INNER JOIN
dbo.tbl_Persons ON dbo.tbl_Owners.PersonID=dbo.tbl_Persons.PersonID
GROUP BY dbo.tbl_Owners.StartDate HAVING MAX(StartDate);
Use GROUP BY on StartDate instead on PersonID.

How to get a master table record by count of detail table records without top(1)

I have a master table (Team) and a detail table (TeamMember). TeamMember has a FK to Team.
I need to get the Team record for the team that has the most team members. I at first had
SELECT team.name
FROM team
INNER JOIN (SELECT TOP 1 COUNT(*) AS membercount,
teamID
FROM teammember
GROUP BY teamID
ORDER BY Count(*) DESC) AS team_with_most_members
ON team.id = team_with_most_members.teamID
I was informed that I cannot use TOP(1) in my queries. Anyone have an idea how I can do it without?
Thanks!
Team
ID, Name
TeamMember
ID, TeamID, UserID
This one is crude but it works:
SELECT t.name
FROM team AS t
JOIN teammember AS tm ON tm.teamID = t.ID
GROUP BY t.Name
HAVING COUNT(tm.id) = (SELECT MAX(members) FROM (SELECT COUNT(id) members FROM teammember GROUP BY teamid) AS sub)
This makes me feel dirty. It will return a single team name even if there is a tie - if you want all rows in the event of a tie, use DENSE_RANK() instead of ROW_NUMBER().
SELECT t.ID, t.Name FROM
(
SELECT
TeamID, rn = ROW_NUMBER() OVER (ORDER BY c DESC)
FROM
(
SELECT TeamID, c = COUNT(*)
FROM dbo.TeamMember GROUP BY TeamID
) AS x
) AS y
INNER JOIN dbo.Team AS t
ON y.TeamID = t.ID
WHERE y.rn = 1; -- **EDIT** forgot the most important part!
I'd really stand up and challenge the "no TOP 1" rule. Ask the person who told you it was for performance reasons to compare the performance of your existing query with any of the kludges we've come up with.
TOP 1 is cleanest way. Here's a really convoluted way that might work:
SELECT ID FROM (
SELECT ID, Tally, MAX(Tally) over (partition by ID) AS MaxTally
FROM (SELECT t1.ID,
COUNT(t2.ID) AS Tally
FROM #Team t1
JOIN #TeamMember t2
ON t2.TeamID = t1.ID
GROUP BY t1.ID) x
) y WHERE Tally = MaxTally