首页 > 解决方案 > MS-SQL 选择没有记录的行为空

问题描述

我有以下 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 的最后一条记录,其中 test name = AD1。

我设法创建了一个执行此操作的查询,只是在没有 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 上的连接进行集成。

标签: sqlsql-server

解决方案


例如,我需要获取每个 LinkID 的最后一条记录,其中 test name = AD1。

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

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 JOIN, aLEFT JOIN就足够了。


推荐阅读