MS-SQL选择没有记录为null的行

时间:2018-05-09 09:35:36

标签: sql sql-server

我有以下3个表格:

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

现在是棘手的部分:

我需要获取每个LinkID的最后一条记录,例如测试名称= AD1。

我设法创建了一个只执行此操作的查询,除非在没有名为test的AD1的情况下不返回任何行:

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;

如何在查询上方扩展(如果可能的话)以便在没有AD1的testType的情况下获取具有空值的行?

这背后的原因是我需要将此部分集成到更大的报告中,我将通过SN上的联接进行整合。

2 个答案:

答案 0 :(得分:1)

  

我需要获取每个LinkID的最后一条记录,例如测试名称= AD1。

当一张表格中包含您需要的所有信息时,我无法弄清楚为什么您的问题会引用四个表格。 full join更难解释。

这会获得您想要的tests行:

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

您也可以使用窗口功能执行此操作:

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

您可以在其他表格中加入,以获取您可能需要的其他列。不需要FULL JOINLEFT JOIN就足够了。

答案 1 :(得分:0)

您说的是where test name = AD1所以我认为您应该在Testname子句中检查testType而不是WHERE,如下所示:

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;

<强>输出:

rn  LinkID  testdate                Testname    record_ID   SN      Data1
1   1       2015-10-05 22:22:00.000 AD1         1           123 123 info