SQL内连接的问题

时间:2010-09-20 18:54:35

标签: sql sql-server

在尝试优化我的SQL时遇到一些问题。

我有两张这样的桌子:

Names
id, analyseid, name

Analyses
id, date, analyseid.

我希望从名称中的每个名称(它们都是唯一的)获得Analyses(按日期排序)的最新分析。如果不使用2 x嵌套选择,我无法真正看到如何做到这一点。

我的尝试(不要对名字感到困惑。这是相同的原则):

SELECT
 B.id,
 B.chosendatetime,
 vStockNames.name
FROM
 vStockNames
INNER JOIN
 (
 SELECT TOP 1
  vAnalysesHistory.id,
  vAnalysesHistory.chosendatetime,
  vAnalysesHistory.companyid
 FROM
  vAnalysesHistory
 ORDER BY
  vAnalysesHistory.chosendatetime DESC
 ) AS B
ON
 B.companyid = vStockNames.stockid

在我的例子中,问题是我只返回1行(因为前1名)。但如果我排除这个,我可以得到同名的多个分析。

你能帮帮我吗? - 提前谢谢。

4 个答案:

答案 0 :(得分:3)

SQL Server 2000 +:

 SELECT (SELECT TOP 1 
                a.id
           FROM vAnalysesHistory AS a 
          WHERE a.companyid = n.stockid 
       ORDER BY a.chosendatetime DESC) AS id,
        n.name, 
        (SELECT TOP 1 
                a.chosendatetime 
           FROM vAnalysesHistory AS a 
          WHERE a.companyid = n.stockid 
       ORDER BY a.chosendatetime DESC) AS chosendatetime
   FROM vStockNames AS n 

SQL Server 2005+,使用CTE:

WITH cte AS (
   SELECT a.id,
          a.date,
          a.analyseid,
          ROW_NUMBER() OVER(PARTITION BY a.analyseid
                                ORDER BY a.date DESC) AS rk
     FROM ANALYSES a)
SELECT n.id, 
       n.name,
       c.date
  FROM NAMES n
  JOIN cte c ON c.analyseid = n.analyseid
            AND c.rk = 1

......没有CTE:

SELECT n.id, 
       n.name,
       c.date
  FROM NAMES n
  JOIN (SELECT a.id,
               a.date, 
               a.analyseid,
               ROW_NUMBER() OVER(PARTITION BY a.analyseid
                                     ORDER BY a.date DESC) AS rk
          FROM ANALYSES a) c ON c.analyseid = n.analyseid
                            AND c.rk = 1

答案 1 :(得分:1)

你只要求获得TOP 1,这就是你所得到的。如果每个companyId需要一个,则需要在vAnalysesHistory上的SELECT中指定。当然,JOIN必须是常量,不允许这样做。幸运的是,在这种情况下,CROSS APPLY可以解决这个问题。

SELECT
 B.id,
 B.chosendatetime,
 vStockNames.name
FROM
 vStockNames
CROSS APPLY
 (
 SELECT TOP 1
  vAnalysesHistory.id,
  vAnalysesHistory.chosendatetime,
  vAnalysesHistory.companyid
 FROM
  vAnalysesHistory
 WHERE companyid = vStockNames.stockid
 ORDER BY
  vAnalysesHistory.chosendatetime DESC
 ) AS B

你也可以使用ROW_NUMBER()来做同样的事情:

SELECT
 B.id,
 B.chosendatetime,
 vStockNames.name
FROM
 vStockNames
INNER JOIN
 (
 SELECT
  vAnalysesHistory.id,
  vAnalysesHistory.chosendatetime,
  vAnalysesHistory.companyid,
  ROW_NUMBER() OVER (PARTITION BY companyid ORDER BY chosendatetime DESC) AS row
 FROM
  vAnalysesHistory
 ) AS B
ON
 B.companyid = vStockNames.stockid AND b.row = 1

就个人而言,我是第一种方法的粉丝。它可能会更快,更容易阅读IMO。

答案 2 :(得分:0)

这样的事情对你有用吗?

;with RankedAnalysesHistory as 
(
 SELECT 
  vah.id,
  vah.chosendatetime,
  vah.companyid
  ,rank() over (partition by vah.companyid order by vah.chosendatetime desc) rnk
 FROM
  vAnalysesHistory vah
)
SELECT
 B.id,
 B.chosendatetime,
 vsn.name
FROM
 vStockNames vsn
 join RankedAnalysesHistory as rah on rah.companyid = vsn.stockid and vah.rnk = 1

答案 3 :(得分:0)

在我看来,你只需要SQL-92。当然,表之间的连接列的明确文档会有所帮助。

简单名称

SELECT B.ID, C.ChosenDate, N.Name
  FROM (SELECT A.AnalyseID, MAX(A.Date) AS ChosenDate
          FROM Analyses AS A
         GROUP BY A.AnalyseID) AS C
  JOIN Analyses AS B ON C.AnalyseID = B.AnalyseID AND C.ChosenDate = B.Date
  JOIN Names    AS N ON N.AnalyseID = C.AnalyseID

子选择为每个公司生成最新分析;使用Analyses连接将获取与最新分析对应的Analyse.ID值,并且使用Names连接将获取公司名称。 (当然,选择列表中的C.ChosenDate可以替换为B.Date AS ChosenDate。)

复杂的名称

SELECT B.ID, C.ChosenDateTime, N.Name
  FROM (SELECT A.CompanyID, MAX(A.ChosenDateTime) AS ChosenDateTime
          FROM vAnalysesHistory AS A
         GROUP BY A.CompanyID) AS C
  JOIN vAnalysesHistory AS B ON C.CompanyID      = B.CompanyID
                            AND C.ChosenDateTime = B.ChosenDateTime
  JOIN vStockNames AS N ON N.AnalyseID = C.AnalyseID

与系统重命名相同的查询(以及略微不同的布局以避免水平滚动条)。