How do I find the oldest date in Group - sql

I have a table where I need to get the oldest date from a group and be able to return all rows. I'm finding it difficult since I need to return the system_id field.
AssignedProfsHistory MatterID EffectiveDate
1 33434-3344 08/22/2005
2 33434-3344 07/12/2004
3 33434-3344 07/12/2004
4 21122-323 12/05/2007
5 43332-986 10/18/2014
6 43332-986 03/23/2013
So in this example, the rows for systemid 2 & 3 should return because they are tied for earliest date. The row for systemid 4 should return and systemid 6 should be returned.
This is what I have so far. Because I need to include the systemid(AssignedProfHistory) I'm not getting the results I need.
SELECT aph.AssignedProfsHistory,
m.MatterID,
Min(aph.EffectiveDate) as 'EffectiveDate'
from AssignedProfsHistory aph
INNER JOIN Matters m
ON aph.Matters = m.Matters
WHERE aph.AssignedType = 'Originating'
Group by m.matters,m.matterid,aph.assignedprofshistory
order by m.MatterID
Any idea how to get the results I need?
Thank you in advance.

select AssignedProfsHistory, MatterID, EffectiveDate
from (
SELECT
aph.AssignedProfsHistory,
m.MatterID,
aph.EffectiveDate,
row_number() over(partition by m.MatterID order by aph.EffectiveDate) as rn
from AssignedProfsHistory aph
INNER JOIN Matters m ON aph.Matters = m.Matters
WHERE aph.AssignedType = 'Originating'
) t
where rn = 1;
You can use the row_number window function to assign row numbers to dates for each matterid. Because the ordering is based on the ascending EffectiveDate, rows with the oldest date get assigned 1 and you select those.
If a matterid can have multiple rows with the oldest dates, you can use rank or dense_rank to get all the rows for the oldest date.

Since you want to keep the ties, I'd do it like this:
SELECT t2.AssignedProfsHistory, m.MatterID, t2.EffectiveDate
FROM (
SELECT MatterID, MIN(EffectiveDate) med
FROM AssignedProfsHistory
WHERE AssignedType = 'Originating'
GROUP BY MatterID
) t1
INNER JOIN AssignedProfsHistory t2 ON t2.MatterID = t1.MatterID
and t2.EffectiveDate = t1.med and t2.AssignedType = 'Originating'
INNER JOIN Matters m on m.Matters = t2.Matters
ORDER BY m.MatterId
Here is an SQLFiddle without the Matters table that demonstrates it can work, no windowing functions or CTE required, though a CTE would allow you to avoid repeating the AssignedType='Originating' condition.

this should get you what you need
with cte as (
SELECT aph.AssignedProfsHistory,
m.MatterID,
aph.EffectiveDate as 'EffectiveDate'
from AssignedProfsHistory aph
INNER JOIN Matters m
ON aph.Matters = m.Matters
WHERE aph.AssignedType = 'Originating'
Group by m.matters,m.matterid,aph.assignedprofshistory
)
select
AssignedProfsHistory,
MatterID,
EffectiveDate
from
cte
join (
select
min(EffectiveDate) min_effectivedate,
MatterID
from
cte
group by
MatterID
) b on cte.EffectiveDate = b.min_effectivedate and
cte.MatterID = b.MatterID
order by AssignedProfsHistory

First take the older date and then join it with your table.
WITH OlderAPH AS (
SELECT
AssignedProfsHistory,
Matters,
MIN(EffectiveDate) OlderDate
FROM AssignedProfsHistory
WHERE AssignedType = 'Originating'
GROUP BY Matters, AssignedProfsHistory )
SELECT
O.AssignedProfsHistory, M.MatterID, O.OlderDate
FROM OlderAPH O
INNER JOIN Matters M ON O.Matters = M.Matters
ORDER BY M.MatterID

Related

Left outer join and necessary subquery with date in Oracle

I'm struggling with a left outer join where the right portion, the one that could contain nulls, doesn't show me values. I think the situation is called an implicit inner join. The reason is that the subquery doesn't return nulls but rather nothing for what I'd like to have on my right part.
(This question differs from Left Outer Join Not Working? in that a subquery to find the maximum date is needed.)
Here is a simplified example:
Table Contracts:
customer_id, status
Table Values:
customer_id, value_code, value, begin_date
I want to display all customers with status = 'active' and the latest value for a certain value_code, lets say 'volume'. There are more value_codes and the values have a certain date from which they are valid. There can also be no value_code BUT then I want a NULL on the right side.
So here is what I tried to do:
SELECT * FROM CONTRACTS C
LEFT JOIN VALUES V ON C.CUSTOMER_ID = V.CUSTOMER_ID
AND VALUE_CODE = 'VOLUME'
WHERE C.STATUS = 'ACTIVE'
AND V.BEGIN_DATE = (
SELECT MAX(BEGIN_DATE) FROM VALUES V2
WHERE V2.CUSTOMER_ID = V.CUSTOMER_ID
AND V2.VALUE_CODE = 'VOLUME'
)
I can't put the subquery in the join clause, Oracle won't accept that. On the other hand my subquery makes it so that all the rows that have no entry for a value with code 'volume' are omitted. What I want is to have value = NULL instead with all the customers on the left.
Thanks for helping!
Filter the VALUE rows first and then LEFT JOIN:
SELECT *
FROM CONTRACTS C
LEFT JOIN
( SELECT *
FROM (
SELECT V.*,
ROW_NUMBER() OVER ( PARTITION BY CUSTOMER_ID ORDER BY BEGIN_DATE DESC )
AS rn
FROM VALUES V
)
WHERE rn = 1
) V
ON ( C.CUSTOMER_ID = V.CUSTOMER_ID
AND VALUE_CODE = 'VOLUME' )
WHERE C.STATUS = 'ACTIVE'
As MT0 suggested using partitioning and sorting by row number helped. Only had to include value_code in the partitioning for my purpose.
So this query finally did what I wanted:
SELECT *
FROM CONTRACTS C
LEFT JOIN
( SELECT *
FROM (
SELECT V.*,
ROW_NUMBER() OVER ( PARTITION BY CUSTOMER_ID, VALUE_CODE ORDER BY BEGIN_DATE DESC )
AS rn
FROM VALUES V
)
WHERE rn = 1
) V
ON ( C.CUSTOMER_ID = V.CUSTOMER_ID
AND VALUE_CODE = 'VOLUME' )
WHERE C.STATUS = 'ACTIVE'

Count with row_number function SQL CTE

I have the below CTEs that work perfectly, but I want to count the "cl.memb_dim_id" by "cl.post_date" but I am not sure how to do that? When adding in the count function I get an error that highlights the ' row number' so I am assuming I cant have both order and group together ????
WITH
DATES AS
(
select to_date('01-jan-2017') as startdate,to_date('02-jan-2017') as enddate
from dual
),
Claims as (select distinct
cl.memb_dim_id,
row_number () over (partition by cl.Claim_number order by cl.post_date desc) as uniquerow,
cl.Claim_number,
cl.post_date,
ct.claim_type,
ap.claim_status_desc,
dc.company_desc,
dff.io_flag_desc,
pr.product_desc,
cl.prov_dim_id,
cl.prov_type_dim_id
from dw.fact_claim cl
inner join dates d
on 1=1
and cl.post_date >= d.startdate
and cl.post_date <= d.enddate
and cl.provider_par_dim_id in ('2')
and cl.processing_status_dim_id = '1'
and cl.company_dim_id in ('581','585','586','589','590','591','588','592','594','601','602','603','606','596','598','597','579','599','578','577','573','574','576','575')
left join dw.DIM_CLAIM_STATUS ap
on cl.claim_status_dim_id = ap.claim_status_dim_id
left join dw.dim_claim_type ct
on cl.claim_type_dim_id = ct.claim_type_dim_id
and cl.claim_type_dim_id in ('1','2','6','7')
left join dw.DIM_COMPANY dc
on cl.company_dim_id = dc.company_dim_id
left join dw.DIM_IO_FLAG dff
on cl.io_flag_dim_id = dff.io_flag_dim_id
left join dw.dim_product pr
on cl.product_dim_id = pr.product_dim_id
)
Select * from claims where uniquerow ='1'
First, does this work?
count(cl.memb_dim_id) over (partition by cl.Claim_number, cl.post_date) as cnt,
Second, it is strange to be using analytic functions with select distinct.

Error when adding order by

Goodday, Please check my query first.
SELECT *
FROM
(
SELECT DISTINCT row, a.tanggal, b.OutletCode, c.Nilai, a.Nip, b.Fullname,
a.KodePenilaian, f.Description AS posisilama, d.ShortDesc AS posisibaru
FROM penilaian_header a
LEFT JOIN Employee b
ON a.Nip = b.Nip
LEFT JOIN Position f
ON b.PositionCode = f.PositionCode
LEFT JOIN Position d
ON a.PositionCode = d.PositionCode
LEFT JOIN arealeader g
ON g.OutletCode = b.OutletCode
LEFT JOIN
(
SELECT ROW_NUMBER() OVER (PARTITION BY KodePenilaianH
ORDER BY idPenilaiand DESC) AS Row,
Nilai, KodePenilaianH
FROM penilaian_Detail
) c
ON a.KodePenilaian = c.KodePenilaianH
WHERE a.Outlet LIKE '%%' AND Periode LIKE '%%'
ORDER BY b.OutletCode ASC
) nilai PIVOT (SUM(nilai) FOR ROW IN ([1],[2],[3],[4],[5])) piv;
My problem is when i'm add Order by my query error. Here is the error :
The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.
Without Order By my query working fine.
I believe that ORDER BY b.OutletCode ASC is the cause of the error, rather than the ORDER BY inside the partition, which is necessary and should be allowed.
If you want to return all records, you can use TOP with a large number, e.g.
SELECT *
FROM
(
SELECT DISTINCT TOP 2147483647 row, a.tanggal, b.OutletCode, c.Nilai, a.Nip,
b.Fullname, a.KodePenilaian, f.Description AS posisilama, d.ShortDesc AS posisibaru
FROM penilaian_header a
LEFT JOIN Employee b
ON a.Nip = b.Nip
...
ORDER BY b.OutletCode ASC
) nilai PIVOT (SUM(nilai) FOR ROW IN ([1],[2],[3],[4],[5])) piv;

Get Distinct results of all columns based on MAX DATE of one

Using SQL Server 2012
I have seen a few threads about this topic but I can't find one that involves multiple joins in the query. I can't create a VIEW on this database so the joins are needed.
The Query
SELECT
p.Price
,s.Type
,s.Symbol
, MAX(d.Date) Maxed
FROM AdventDW.dbo.FactPrices p
INNER JOIN dbo.DimSecurityMaster s
ON s.SecurityID = p.SecurityID
INNER JOIN dbo.DimDateTime d
ON
p.DateTimeKey = d.DateTimeKey
GROUP BY p.Price ,
s.Type ,
s.Symbol
ORDER BY s.Symbol
The query works but does not produce distinct results. I am using Order by to validate the results, but it is not required once I get it working. I The result set looks like this.
Price Type Symbol Maxed
10.57 bfus *bbkd 3/31/1989
10.77 bfus *bbkd 2/28/1990
100.74049 cbus 001397AA6 8/2/2005
100.8161 cbus 001397AA6 7/21/2005
The result set I want is
Price Type Symbol Maxed
10.77 bfus *bbkd 2/28/1990
100.74049 cbus 001397AA6 8/2/2005
Here were a few other StackOverflow threads I tried but couldn't get t work with my specific query
How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?
SQL Selecting distinct rows from multiple columns based on max value in one column
If you want data for the maximum date, use row_number() rather than group by:
SELECT ts.*
FROM (SELECT p.Price, s.Type, s.Symbol, d.Date,
ROW_NUMBER() OVER (PARTITION BY s.Type, s.Symbol
ORDER BY d.Date DESC
) as seqnum
FROM AdventDW.dbo.FactPrices p INNER JOIN
dbo.DimSecurityMaster s
ON s.SecurityID = p.SecurityID INNER JOIN
dbo.DimDateTime d
ON p.DateTimeKey = d.DateTimeKey
) ts
WHERE seqnum = 1
ORDER BY s.Symbol;
You should use a derived table since you really only want to group the DateTimeKey table to get the MAX date.
SELECT p.Price ,
s.Type ,
s.Symbol ,
tmp.MaxDate
FROM AdventDW.dbo.FactPrices p
INNER JOIN dbo.DimSecurityMaster s ON s.SecurityID = p.SecurityID
INNER JOIN
( SELECT MAX(d.Date) AS MaxDate ,
d.DateTimeKey
FROM dbo.DimDateTime d
GROUP BY d.DateTimeKey ) tmp ON p.DateTimeKey = tmp.DateTimeKey
ORDER BY s.Symbol;
/*
this is your initial select which is fine because this is base from your original criteria,
I cannot ignore this so i'll keep this in-tact. Instead from here i'll create a temp
*/
SELECT
p.Price
, s.Type
, s.Symbol
, MAX(d.Date) Maxed
INTO #tmpT
FROM AdventDW.dbo.FactPrices p
INNER JOIN dbo.DimSecurityMaster s
ON s.SecurityID = p.SecurityID
INNER JOIN dbo.DimDateTime d
ON p.DateTimeKey = d.DateTimeKey
GROUP BY p.Price ,
s.Type ,
s.Symbol
ORDER BY s.Symbol
SELECT innerTable.Price, innerTable.Symbol, innerTable.Type, innerTable.Maxed
FROM (
SELECT
ROW_NUMBER () OVER (PARTITION BY t1.Symbol, t1.Type, t1.Maxed ORDER BY t1.Maxed DESC) as row
, *
FROM #tmpT AS t1
) AS innerTable
WHERE row = 1
DROP TABLE #tmpT

SQL Query to return last value from a number of tags

I hope you might be able to help. I'm a novice at SQL so this one is starting to bug me.
Currently I am collecting data every day for a Meter Name. This data is currently being logged in a table with the columns TimeStamp, Name, Value. However I would like to create a query which will only return the most recent (last) value recorded against each Name in the table.
I've built this query so far but the Top 1 syntax doesn't seem to be what I need.
SELECT Top 1 (DataLog.Timestamp), MeterTags.Name, DataLog.Value
FROM Meters
INNER JOIN MeterTags
ON Meters.MeterId = MeterTags.MeterId
INNER JOIN DataLog
ON MeterTags.MeterTagId = DataLog.MeterTagId
WHERE Meters.MeterTypeId = 8
GROUP By MeterTags.Name, DataLog.Timestamp
Any advice you could give would be appreciated.
Thanks in advance.
You can use ROW_NUMBER to give each record a rownumber (resetting to 0 for each MeterTags.Name) then just select the first for each name:
WITH CTE AS
( SELECT DataLog.Timestamp,
MeterTags.Name,
DataLog.Value,
RowNumber = ROW_NUMBER() OVER(PARTITION BY MeterTags.Name
ORDER BY DataLog.TimeStamp DESC)
FROM Meters
INNER JOIN MeterTags
ON Meters.MeterId = MeterTags.MeterId
INNER JOIN DataLog
ON MeterTags.MeterTagId = DataLog.MeterTagId
WHERE Meters.MeterTypeId = 8
)
SELECT CTE.Timestamp,
CTE.Name,
CTE.Value
FROM CTE
WHERE CTE.RowNumber = 1;
Another solution is to use the TOP 1 inside an APPLY:
SELECT DataLog.Timestamp,
MeterTags.Name,
DataLog.Value
FROM Meters
INNER JOIN MeterTags
ON Meters.MeterId = MeterTags.MeterId
CROSS APPLY
( SELECT TOP 1 TimeStamp, Value
FROM DataLog
WHERE MeterTags.MeterTagId = DataLog.MeterTagId
ORDER BY TimeStamp DESC
) DataLog
WHERE Meters.MeterTypeId = 8;
Try below query
select Timestamp,Name,Value
from
(
SELECT (DataLog.Timestamp), MeterTags.Name, DataLog.Value,rownum,ROW_NUMBER() OVER
(PARTITION BY MeterTags.Name ORDER BY DataLog.Timestamp desc) AS rownum FROM Meters
INNER JOIN MeterTags
ON Meters.MeterId = MeterTags.MeterId
INNER JOIN DataLog
ON MeterTags.MeterTagId = DataLog.MeterTagId
)data
where rownum=1