0

我有两个名为 Test 的表,TestHistory 中的 testHistory 与 Test 有 FK 关系。

测试表数据

testHistory 表数据

现在我想从带有测试表记录的表 TestHistory 中选择前 1 个插入的数据。

我想要的输出是:

在此处输入图像描述

或者我的 TestHistory 表没有必要包含与 TestId 相关的记录,那么我的输出将是:

在此处输入图像描述

我已经通过子查询实现了这一点,例如:

Select Id,(select top(1) price from TestHistory HT Where T.Id=HT.TestId order by HT.Id desc) As Price 

From Test T

但我不想为此使用子查询。我想做没有子查询的选择数据。

请建议我如何在没有子查询的情况下做到这一点,解决这个问题的最佳替代方法是什么。

4

2 回答 2

1

我认为最简单的方法是使用row_number()来获取结果,但您仍然会有一个子查询。这将不是一个相关的子查询:

select id, price, testhistoryid
from
(
  select t.id,
    h.price,
    h.id testhistoryid,
    row_number() over(partition by t.id order by h.id desc) rn
  from test t
  inner join testhistory h
    on t.id = h.testid
) src
where rn = 1;

请参阅SQL Fiddle with Demo

如果要返回test历史记录表中不存在的行,那么您将使用 aLEFT JOIN而不是 a INNER JOIN

select id, price, testhistoryid
from
(
  select t.id,
    h.price,
    h.id testhistoryid,
    row_number() over(partition by t.id order by h.id desc) rn
  from test t
  left join testhistory h
    on t.id = h.testid
) src
where rn = 1;

演示

于 2013-04-24T19:05:55.317 回答
0

抱歉,如果没有某种子查询,就没有真正的方法可以做到这一点。你写的查询很好。在我看来,完成您正在寻找的最佳语法是:

SELECT
   T.ID,
   HT.*
FROM
   dbo.Test T
   OUTER APPLY (
      SELECT TOP 1 *
      FROM dbo.TestHistory HT
      WHERE T.ID = HT.TestID
      ORDER BY HT.ID DESC
   ) HT
;

在 SQL Fiddle 中自己尝试一下

如果您想限制它以便只显示Test具有匹配TestHistory行的那些行,则使用CROSS APPLY而不是OUTER APPLY.

TestHistory此外,这样的查询是可能的并且可能更容易理解,但很可能不会执行得那么好,而且它要求每行至少有Test一行。

SELECT
   T.ID,
   HT.*
FROM
   dbo.Test T
   INNER JOIN dbo.TestHistory HT
      ON T.ID = HT.TestID
WHERE
   HT.ID = (
      SELECT Max(HT2.ID)
      FROM dbo.TestHistory HT2
      WHERE T.ID = HT2.TestID
   )
;

您也可以使用一个Row_Number()解决方案,尽管我倾向于不使用它,因为它的性能通常不如CROSS APPLYwith TOP,当它可用时。

SELECT
   T.ID,
   HT.TestID,
   HT.Price
FROM
   dbo.Test T
   LEFT JOIN (
      SELECT
         Selector = Row_Number() OVER (
            PARTITION BY HT.TestID ORDER BY HT.ID DESC
         ),
         *
      FROM dbo.TestHistory HT
   ) HT
      ON T.ID = HT.TestID
      AND HT.Selector = 1
;

在 SQL Fiddle 中自己尝试一下

找出TOP 1Row_Number()解决方案是否性能更好的唯一方法是使用大量具有适当代表性的数据尝试数据库中的每一个。如果您的历史条目非常少而主要条目非常多,使用Row_Number(). 但是,如果每个主要条目都有许多历史条目,则该TOP方法可能会执行得最好。

表上的索引也可以产生巨大的影响。确保您有合理的索引,允许正确的表访问(例如,表上的聚集索引TestHistory应该是 on TestID, ID,即使 PK 是 on ID')。如果您每次都查询整个表,索引可能没那么重要,但是当您有限制Test行集的条件时,索引将变得非常重要。

于 2013-04-24T19:19:41.197 回答