选择没有SubQuery的数据

时间:2013-04-24 19:01:57

标签: sql sql-server sql-server-2008

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

Test table data

testHistory table data

现在我想从表TestHistory中选择带有测试表记录的Top 1 Inserted数据。

我想要的输出是:

enter image description here

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

enter image description here

我用子查询实现了这一点,如:

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

From Test T

但我不想使用子查询。 我想在没有子查询的情况下选择数据。

如果没有Sub查询,请建议我如何做到这一点,这将是解决此问题的最佳替代方法。

2 个答案:

答案 0 :(得分: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行,那么您将使用LEFT JOIN代替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;

请参阅Demo

答案 1 :(得分: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
;

Try this out yourself in a 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 APPLY 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
;

Try this out yourself in a SQL Fiddle

找出TOP 1Row_Number()解决方案是否表现更好的唯一方法是尝试使用大量具有正确代表性的数据来​​尝试数据库中的每个解决方案。如果您的历史记录条目和主要参赛作品很少,那么可能可以使用Row_Number()获得更好的结果。但是,如果每个主条目都有许多历史条目,TOP方法可能表现最佳。

表上的索引也会产生巨大的差异。确保您拥有允许正确访问表的合理索引(例如,表TestHistory上的聚簇索引应该在TestID, ID上,即使PK在ID上也是如此)。如果每次都查询整个表,那么索引可能并不重要,但是当你有一个限制Test行的条件时,索引将变得非常重要。