Selecting max value from 2nd table in first table results - sql

I have 2 tables as below-
Table I
ID DATE
1 05/11/12
2 23/11/12
3 29/11/12
4 04/10/12
5 20/11/12
And another table (IH) with the following info-
ID RECNO NOTE
1 1 Open
1 2 Update
1 3 Close
2 1 Open
2 2 Update
2 3 Hold
2 4 Close
3 1 Open
4 1 Open
4 2 Update
5 1 Open
I would like to output a result as shown below, displaying the Note field using the highest value of RecNo for each ID. So using the data above the output should be-
ID DATE NOTE
2 23/11/12 Close
3 29/11/12 Open
The code I have is-
SELECT I.ID, I.DATE, IH.NOTE FROM
I I, IH IH
JOIN (SELECT MAX([RECNO]) [RECNO] FROM
IH
GROUP BY RECNO) IH2 ON IH2.ID = IH.ID AND
IH2.[RECNO] = IH.[RECNO]
JOIN I I2 ON I2.ID = IH.ID WHERE
(I2.DATE>={TS ‘2012-11-22 00:00:002}) GROUP BY I2.ID
However when I execute the code I get-
Invalid Column Name 'RECNO'. Statement(s) could not be prepared.

How about this? Note, haven't tried it, I'm on my Mac at the moment.
SELECT I.ID, I.DATE, IH.NOTE
FROM I I
OUTER APPLY
(SELECT TOP 1 *
FROM IH
WHERE IH.ID = I.ID
ORDER BY RECNO DESC) IH
WHERE I.DATE >= '2012-11-22'

Your SQL is rather, uh, messy.
Assuming you are using SQL Server 2005 or greater, you can use the row_number() function, as follows:
SELECT I.ID, I.DATE, IH.NOTE
FROM I join
(select ih.*, ROW_NUMBER() over (PARTITION by id order by recno desc) as seqnum
from IH
) ih
on IH2.[RECNO] = IH.[RECNO] and seqnum = 1
WHERE I2.DATE>='2012-11-22 00:00:002'
This is assigning a sequence number in the IH table, for each id with the highest record number getting the value "1". The rest is just SQL.
Your original query is simply not correct syntactically, but I think this is what you want based on the description.

and another one
SELECT I.ID, I.DATE
,(Select TOP 1 IH.NOTE FROM IH where IH.ID=i.ID Order by Recno DESC) as Note
from I
WHERE
I.DATE>'20121122'

maybe this will help
SELECT a.ID, a.DATE, b.NOTE FROM a
inner join b on a.ID = b.ID
where b.recno in (select max(bb.recno)
from b as bb where bb.id = b.id)
http://sqlfiddle.com/#!3/fd141/2

If you don't mind the different identifiers, look at this solution:
select t1.MyID, t1.MyDate, y.Note
from t1
join
(
select MyID, max(RecNo) as RecNo
from t2
group by MyID
) x
on t1.MyID = x.MyID
left join
(
select *
from t2
) y
on t1.MyID = y.MyID
and x.RecNo = y.RecNo
where t1.MyDate >= '2012.11.22'
The complete solution is here: http://sqlfiddle.com/#!3/4ca09/3
Update: Oops, forgot to bring in the date in where clause. Updated SQL Fiddle and the query above.

Related

Select MAX() or Select TOP 1 on Join

I'm working with the following code to only get one associated person per case, using the MAX Associated Type to get the top 1.
Associated Type is not a GUID, rather looks like:
Responsible Party, Primary Physician, etc.
It just so happens that Responsible Party is the last alphabetical option, so it's a lucky workaround. Not every case has a responsible party, however, and if there isn't a responsible party, the next top associated person is 'good enough' and will be highlighted as a data error anyway.
The result shows every single associated person (rather than top 1), but shows all of them as Responsible Party, which is not true. What am I doing wrong here?
FROM T_LatestIFSP Ltst
LEFT OUTER JOIN (
SELECT
Clas.ClientCase_ID,
MAX(Astp.AssociatedType) AS AssociatedType
FROM
T_ClientAssociatedPerson Clas
Inner Join T_AssociatedType Astp
ON Clas.AssociatedType_ID = Astp.AssociatedType_ID
GROUP BY Clas.ClientCase_ID
) AS Astp ON Ltst.ClientCase_ID = Astp.ClientCase_ID
LEFT OUTER JOIN T_ClientAssociatedPerson Clas
on Clas.ClientCase_ID = Astp.ClientCase_ID
LEFT OUTER JOIN T_AssociatedPerson Aspr
ON Aspr.AssociatedPerson_ID = Clas.AssociatedPerson_ID
To get AssocId in the select, you have to do a self join.
LEFT OUTER JOIN
(your subselect with max(AssociatedType) in it) AS Astp
INNER JOIN T_AssociatedType AS Astp2
ON (whatever the primary key is on that table)
Then you can add astp2.AssociationTypeId to the original SELECT.
You can try this query.
Make rn from your order condition in CASE WHEN
You can use Rank with window function to make rank number in subquery, then get rnk=1 data row.
;WITH CTE AS (
SELECT ClientCase_ID,
AssociatedPerson_ID,
AssociatedPersonType,
AssociatedType_ID,
RANK() OVER(PARTITION BY ClientCase_ID ORDER BY rn desc,AssociatedPerson_ID) rnk
FROM (
SELECT t1.ClientCase_ID,
t1.AssociatedPerson_ID,
t1.AssociatedPersonType,
t1.AssociatedType_ID,
(CASE
WHEN t1.AssociatedPersonType = 'ResPonsible Party' then 16
WHEN t1.AssociatedPersonType = 'Primary Physician' then 15
ELSE 14
END) rn
FROM T t1
INNER JOIN T t2 ON t1.ClientCase_ID = t2.AssociatedPerson_ID
UNION ALL
SELECT t2.AssociatedPerson_ID,
t1.AssociatedPerson_ID,
t1.AssociatedPersonType,
t2.AssociatedType_ID,
(CASE
WHEN t2.AssociatedPersonType = 'ResPonsible Party' then 16
WHEN t2.AssociatedPersonType = 'Primary Physician' then 15
ELSE 14
END) rn
FROM T t1
INNER JOIN T t2 ON t1.ClientCase_ID = t2.AssociatedPerson_ID
) t1
)
select DISTINCT ClientCase_ID,AssociatedPerson_ID,AssociatedPersonType,AssociatedType_ID
FROM CTE
WHERE rnk = 1
sqlfiddle
Also, you can try to use CROSS APPLY with value instead of UNION ALL
;with CTE AS (
SELECT v.*, (CASE
WHEN v.AssociatedPersonType = 'ResPonsible Party' then 16
WHEN v.AssociatedPersonType = 'Primary Physician' then 15
ELSE 14
END) rn
FROM T t1
INNER JOIN T t2 ON t1.ClientCase_ID = t2.AssociatedPerson_ID
CROSS APPLY (VALUES
(t1.ClientCase_ID,t1.AssociatedPerson_ID,t1.AssociatedPersonType, t1.AssociatedType_ID),
(t2.AssociatedPerson_ID,t1.AssociatedPerson_ID,t2.AssociatedPersonType, t2.AssociatedType_ID)
) v (ClientCase_ID,AssociatedPerson_ID,AssociatedPersonType,AssociatedType_ID)
)
SELECT distinct ClientCase_ID,AssociatedPerson_ID,AssociatedPersonType,AssociatedType_ID
FROM
(
SELECT *,
RANK() OVER(PARTITION BY ClientCase_ID ORDER BY rn desc,AssociatedPerson_ID) rnk
FROM CTE
) t1
WHERE rnk = 1
sqlfiddle
Note
you can add your customer order number in CASE WHEN
[Results]:
| ClientCase_ID | AssociatedPerson_ID | AssociatedPersonType | AssociatedType_ID |
|---------------|---------------------|----------------------|-------------------|
| 01 | 01 | ResPonsible Party | 16 |
| 02 | 03 | Physician Therapist | 24 |
I solved the problem with the following code:
LEFT OUTER JOIN T_ClientAssociatedPerson Clas
on Clas.ClientCase_ID = Ltst.ClientCase_ID
and
CASE
WHEN Clas.AssociatedType_ID = 16 AND Clas.ClientCase_ID = Ltst.ClientCase_ID THEN 1
WHEN Clas.AssociatedType_ID <> 16 AND Clas.AssociatedType_ID = (
SELECT TOP 1 Clas.AssociatedType_ID
FROM T_ClientAssociatedPerson Clas
WHERE Clas.ClientCase_ID = Ltst.ClientCase_ID
ORDER BY AssociatedType_ID DESC
) THEN 1
ELSE 0
END = 1

Select one row that is a duplicate and also select the other rows that are not duplicates

here is my code
select i.RefNo,i.Premium,i.Description from (select d.Description,c.IsActiveRecord,c.RefNo,c.MovementID, c.Premium,ROW_NUMBER()
over(partition by c.premium order by c.refno) n from lif_mgm_t_contract c
inner join SDT_LJG_T_MovementDescription d with (nolock) on c.MovementID = d.MovementID ) i
where i.n = 1 and i.MovementID <> 0
so for instance
table
a
a
b
I want the query to return
a
b and not just a hope this makes sense --only a beginner
try using a group by clause
SELECT OrderNumber
FROM AccountOrder
group by OrderNumber
so if my table has the following order numbers
1
2
2
3
the query would return
1
2
3

Sql Query combine using Top and Ascending order

I have been creating sql query as shown below :
select * from (select DISTINCT * from (select po.tGroup_id,pp.tGroup_id as GroupID from tPhos_Line_Operator PO
LEFT join tPhos_Line_Parameter PP
on PO.tGroup_id = PP.tGroup_id) A) Ac
left JOIN
(SELECT top 1 tGroup_id FROM tGROUP_LOG order by id desc) B
on Ac.tGroup_id = B.tGroup_id
I was expecting to see records like in the image below :
But I keep getting this records :
I tried to hardcode in the left join by putting the tGroup_id=29 and it work as I got the exact record I want. Refer to first image.
select * from (select DISTINCT * from (select po.tGroup_id,pp.tGroup_id as GroupID from tPhos_Line_Operator PO
LEFT join tPhos_Line_Parameter PP
on PO.tGroup_id = PP.tGroup_id) A) Ac
left JOIN
(SELECT top 1 tGroup_id FROM tGROUP_LOG where tGroup_id = 29 order by id desc
) B
on Ac.tGroup_id = B.tGroup_id
I do not want to hardcode it.
Can someone tell me where did I missed out or did wrong?
Thanks in advance.
I have found a way, instead of using top 1, I can use max.
SELECT max(id) as TESTID,tGroup_id FROM tGROUP_LOG
group by tGroup_id
I consider this has fixed my issue. Thanks

Get Incremental index for specific rows

I want to get the incremental index when note exists for the row. I am trying to achieve the same with ROW_Number() but it seems there is a problem with the method being used to generate it.
SELECT * RowNo,
(SELECT CASE
WHEN LEN(Value) > 0 THEN ROW_NUMBER()
OVER (
ORDER BY ID)
ELSE ''
END
FROM Dictionary
WHERE ID = ABC.ID) Note
FROM ABCD AS ABC WITH(NOLOCK)
INNER JOIN XYZ AS XYZ WITH(NOLOCK)
ON ABC.Id = XYZ.ID
WHERE ABC.Id = 10
output expected:
ID Name Note
1 A 1
2 B
3 C 2
4 D
5 E
6 F 3
The subquery isn't needed here, and you want to use the partition by argument to separate values having len(value)>0 from those having no value:
SELECT
ID,
Name,
CASE WHEN LEN(Value)>0 THEN ROW_NUMBER() OVER (
PARTITION BY CASE WHEN LEN(Value)>0 THEN 1 ELSE 0 END
ORDER BY ID) ELSE '' END as Note
FROM ABCD AS ABC WITH(NOLOCK)
INNER JOIN XYZ AS XYZ WITH(NOLOCK)
ON ABC.Id = XYZ.ID
Where ABC.Id = 10
I think maybe you need to change the approach to make the Dictionary query the "main" query. It's hard to say without knowing exactly what your tables look like. Which Table does the "Id" in your expected output come from?
Try like this:
WITH cte AS (
SELECT ID, ROW_NUMBER() OVER (ORDER BY ID) AS Note
FROM Dictionary WHERE ID=10
AND LEN(Value)>0
)
SELECT ABC.ID, [Name], cte.Note
FROM ABCD AS ABC WITH(NOLOCK)
INNER JOIN XYZ AS XYZ WITH(NOLOCK) ON ABC.Id = XYZ.ID
LEFT OUTER JOIN cte ON ABC.Id=cte.ID

Top Row within the Second Table

I'm having an issue with getting TOP to work within my SQL query. I only want to see the first row within the PART_AML table. I'm not having any luck trying to only query that table without querying the PART table.
How can I go about only showing the top row within the PART_AML table? I'm using Microsoft SQL.
Thank you for your help its greatly appreciated.
SELECT innovator.PART.STATE,
innovator.PART.NAME,
innovator.PART.ITEM_NUMBER,
innovator.PART.ID,
innovator.PART.TYPE,
innovator.MANUFACTURER_PART.SPEC_URL
FROM innovator.PART
join innovator.PART_AML
on innovator.PART_AML.SOURCE_ID = innovator.PART.ID
join innovator.MANUFACTURER_PART
on innovator.MANUFACTURER_PART.ID = innovator.PART_AML.RELATED_ID
WHERE
(innovator.PART.IS_CURRENT = 1) AND (innovator.PART_AML.IS_CURRENT = 1) AND (innovator.MANUFACTURER_PART.IS_CURRENT = 1)
Current Output
Number Name ID Type Spec
E000836 1k ID1 Resistor SPEC 1
E000836 1k ID1 Resistor SPEC 2
E000836 1k ID1 Resistor SPEC 3
E003455 14.400MHz ID2 Crystal SPEC 1
E003455 14.400MHz ID2 Crystal SPEC 2
E003455 14.400MHz ID2 Crystal SPEC 3
Preferred Output
Number Name ID Type Spec
E000836 1k ID1 Resistor SPEC 1
E003455 14.400MHz ID2 Crystal SPEC 1
You can make use of the ranking function ROW_NUMBER() OVER(ORDER BY ...) to do this:
WITH CTE
AS
(
SELECT
i.STATE,
i.NAME,
i.ITEM_NUMBER,
i.ID,
i.TYPE,
p.SPEC_URL,
ROW_NUMBER() OVER(PARTITION BY i.ID
ORDER BY p.SPEC_URL) AS Rownum
FROM innovator.PART AS i
INNER JOIN innovator.PART_AML AS a on a.SOURCE_ID = i.ID
INNER JOIN innovator.MANUFACTURER_PART AS p on p.ID = a.RELATED_ID
WHERE i.IS_CURRENT = 1
AND a.IS_CURRENT = 1
AND p.IS_CURRENT = 1
)
SELECT *
FROM CTE
WHERE rownum = 1;
Also you can use simple GROUP BY clause with MIN() function
SELECT innovator.PART.STATE,
innovator.PART.NAME,
innovator.PART.ITEM_NUMBER,
innovator.PART.ID,
innovator.PART.TYPE,
MIN(innovator.MANUFACTURER_PART.SPEC_URL) AS SPEC_URL
FROM innovator.PART join innovator.PART_AML on innovator.PART_AML.SOURCE_ID = innovator.PART.ID
join innovator.MANUFACTURER_PART on innovator.MANUFACTURER_PART.ID = innovator.PART_AML.RELATED_ID
WHERE (innovator.PART.IS_CURRENT = 1) AND (innovator.PART_AML.IS_CURRENT = 1) AND (innovator.MANUFACTURER_PART.IS_CURRENT = 1)
GROUP BY innovator.PART.STATE, innovator.PART.NAME, innovator.PART.ITEM_NUMBER, innovator.PART.ID, innovator.PART.TYPE