Reputation: 405
I have the following 3 tables:
A) Unit information [Unit]
+-----------+---------+-------+
| record_ID | SN | Data1 |
+-----------+---------+-------+
| 1 | 123 123 | info |
+-----------+---------+-------+
B) Test related information [TestingData]
+---------+------------------+-----------+
| SN | Info1 | Data1 |
+---------+------------------+-----------+
| 123 123 | Some information | Some data |
+---------+------------------+-----------+
C) Join table to more testing information [Link]
+--------+---------+
| LinkID | SN |
+--------+---------+
| 1 | 123 123 |
+--------+---------+
D) Testing details [Tests]
+--------+---------------------+-----------+
| LinkID | testdate | Testname |
+--------+---------------------+-----------+
| 1 | 10.05.2015 22:22:00 | AD1 |
+--------+---------------------+-----------+
Now the tricky part:
I need to get the last record for each LinkID where test name = AD1 for example.
I managed to create a query that does just this, except that it returns no rows in case there was no AD1 named test:
SELECT * FROM (
SELECT
ROW_NUMBER() OVER(PARTITION BY rf2.linkID ORDER BY rf2.testDate DESC) AS rn
,rf2.*, rs.*
FROM dbo.Unit rs
FULL OUTER JOIN dbo.TestingData rf ON ( rs.SN = rf.SN )
FULL OUTER JOIN dbo.Link rf1 ON ( rf.SN = rf1.SN)
FULL OUTER JOIN dbo.Tests rf2 ON ( rf1.linkID = rf2.linkID )
WHERE rf2.testType = 'AD1'
) T
WHERE rn = 1
ORDER BY SN ASC;
How can I extend (if possible at all) above query so that I will also get rows with null values in case there has not been a testType of AD1?
Reason behind this is that I will need to integrate this part to a larger report, which I will integrate through a join on SN.
Upvotes: 1
Views: 81
Reputation: 1271003
I need to get the last record for each LinkID where test name = AD1 for example.
I can't figure out why your question has references to four tables, when one table has all the information you need. The full join
s are even less explanable.
This gets the rows from tests
that you want:
select top (1) with ties t.*
from tests t
where t.testName = 'AD1'
order by row_number() over (partition by t.linkid order by t.testdate desc)
union all
select t.*
from tests t
where not exists (select 1 from tests t2 where t2.linkid = t.linkid and t.testName = 'AD1');
You can also do this with window functions:
select t.*
from (select t.*,
row_number() over (partition by linkid, testname order by testdate desc) as seqnum,
sum(case when testName = 'AD1' then 1 else 0 end) over (partition by linkid) as num_ad1
from tests t
) t
where (l.num_ad1 > 0 and testName = 'AD1' and seqnum = 1) or
(l.num_ad1 = 0);
You can JOIN in the other tables, for additional columns you may want. There is no need for FULL JOIN
, a LEFT JOIN
should suffice.
Upvotes: 1
Reputation: 5656
You are saying where test name = AD1
so I think you should check Testname
instead of testType
in the WHERE
clause as below:
SELECT * FROM (
SELECT
ROW_NUMBER() OVER(PARTITION BY rf2.linkID ORDER BY rf2.testDate DESC) AS rn
,rf2.*, rs.*
FROM dbo.Unit rs
FULL OUTER JOIN dbo.TestingData rf ON ( rs.SN = rf.SN )
FULL OUTER JOIN dbo.Link rf1 ON ( rf.SN = rf1.SN)
FULL OUTER JOIN dbo.Tests rf2 ON ( rf1.linkID = rf2.linkID )
WHERE rf2.Testname = 'AD1' -- You should use `Testname` instead of `testType`
) T
WHERE rn = 1
ORDER BY SN ASC;
OUTPUT:
rn LinkID testdate Testname record_ID SN Data1
1 1 2015-10-05 22:22:00.000 AD1 1 123 123 info
Upvotes: 0