How can I fix my GROUP BY clause - sql

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.

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);

SQL where in sql subquery with order by

This is my query
SELECT * FROM Place WHERE Place.Id IN (
SELECT TOP 10 PlaceId from #ResultPlaceList order by CPlaceId desc)
my result is ordered by Place.ID, but i want to have a result with ordered CPlaceId.
You could use a join to use the cPlaceId column for ordering:
select p.*
from Place p
join (
select top 10 PlaceId,
CPlaceId
from #ResultPlaceList
order by CPlaceId desc
) r on p.Id = r.PlaceId
order by r.CPlaceId;
You will have to do a JOIN to accomplish this. It will look something like this:
SELECT TOP 10 Place.*
FROM Place
JOIN #ResultPlaceList ON #ResultPlaceList.PlaceId = Place.Id
ORDER BY CPlaceId DESC
Something like this....
SELECT * FROM PLACE WHERE PLACE.ID IN (
SELECT PLACEID
FROM (
SELECT PLACEID
, ROW_NUMBER() OVER (ORDER BY CPLACEID DESC) RNUM
FROM #RESULTPLACELIST
) TMP
WHERE RNUM <= 10
)
'SELECT C.ID
FROM CustomerDetails C
LEFT JOIN UserInfo U ON C.ID = U.ID
Order by U.ID'
Can you modify your query like this

Highest Count with a group

I'm having an absolute brain fade
SELECT p.ProductCategory, f.ProductSubCategory, COUNT(*) AS Cnt
FROM Sales f
JOIN Products p ON f.ProductSubCategory = p.ProductSubCategory
GROUP BY p.ProductCategory, f.ProductSubCategory
ORDER BY 1,3 DESC
This shows me the count for each ProductSubCategory, I would like to see only the highest ProductSubCategory per ProductCategory.
I wish to see (I don't care about the Count value)
There are a couple of different ways to do this. One involves joining the results back to themselves and using the max aggregate. But since you are using SQL Server, you can use ROW_NUMBER to achieve the same result:
with cte as (
select p.productcategory, p.ProductSubCategory, COUNT(*) cnt,
ROW_NUMBER() over (partition by p.productcategory order by count(*) desc) rn
from products p
join sales s on p.ProductSubCategory = s.ProductSubCategory
group by p.productcategory, p.ProductSubCategory
)
select *
from cte
where rn = 1
You already got the answer, Please see the following code to. It may help you.
SELECT p.ProductCategory,
f.ProductSubCategory,
COUNT(*) AS Cnt
FROM Sales f
JOIN Products p ON f.ProductSubCategory = p.ProductSubCategory
JOIN (
SELECT p.ProductCategory,
f.ProductSubCategory,
ROW_NUMBER() OVER ( PARTITION BY p.ProductCategory,
f.ProductSubCategory
ORDER BY COUNT(*) DESC) [Row]
FROM Sales f
JOIN Products p ON f.ProductSubCategory = p.ProductSubCategory) Lu
ON P.ProductCategory = Lu.ProductCategory
AND f.ProductSubCategory = Lu.ProductSubCategory
WHERE Lu.Row = 1
GROUP By p.ProductCategory,
f.ProductSubCategory

Get the first record from the result set

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 <.