无效的列名称不能使用变量

时间:2012-02-10 23:08:24

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

我的程序中最后一个select语句的列名无效。我需要获取ThreadTitle并由列ThreadID选中。由于F.ForumD select子句,我无法使用局部变量并进行设置。我只需要获取ThreadID并将其传递给ThreadTitle有没有人知道如何做到这一点

SELECT ForumGroup = (
  CASE WHEN ParentID IS NOT NULL THEN
    (SELECT Title FROM Forums WHERE ForumID = F.ParentID)           
  ELSE
    (SELECT Title FROM Forums WHERE ParentID IS NULL)
  END),
  Title, 
  Description, 
  ThreadCount = (SELECT COUNT(*) FROM Posts P WHERE  P.ForumID = F.ForumID),
  LastPostBy = (SELECT TOP 1 AddedBy FROM Posts P 
    WHERE P.ForumID = F.ForumID ORDER BY P.PostID DESC), 
  LastPostDate = (SELECT TOP 1 AddedDate FROM Posts P 
    WHERE P.ForumID = F.ForumID ORDER BY P.PostID DESC), 
  LastPostTitle = (SELECT TOP 1 Title FROM Posts P 
    WHERE P.ForumID = F.ForumID ORDER BY P.PostID DESC),
  ThreadID =  CAST(SUBSTRING((SELECT TOP 1 Path_String 
    FROM Posts P WHERE P.ForumID = F.ForumID ORDER BY P.PostID DESC), 0, 
    CHARINDEX('/', (SELECT TOP 1 Path_String FROM Posts P 
    WHERE P.ForumID = F.ForumID ORDER BY P.PostID DESC))) AS INT),
  ThreadTitle = (SELECT TOP 1 Title FROM Posts P 
    WHERE P.PostID = ThreadID ORDER BY P.PostID DESC) 
  FROM Forums F WHERE ParentID IS NOT NULL
  ORDER BY Title

2 个答案:

答案 0 :(得分:1)

由于我们没有所有的架构,所以我会对你所拥有的假设以及你应该拥有什么的建议采取一些自由。你应该把它们当作一粒盐,因为它们适合于满足这个查询,我不知道这些建议可能会影响哪些其他查询。

我要猜测基表:

USE tempdb;
GO

CREATE TABLE dbo.Forums
(
    ForumID     INT PRIMARY KEY,
    Title       VARCHAR(32),
    Description VARCHAR(255),
    ParentID    INT NULL FOREIGN KEY REFERENCES dbo.Forums(ForumID)
);
CREATE INDEX t ON dbo.Forums(ParentID);
GO

CREATE TABLE dbo.Threads
(
    ThreadID INT PRIMARY KEY,
    Title    VARCHAR(32)
);
GO

CREATE TABLE dbo.Posts
(
    PostID      INT PRIMARY KEY,
    AddedBy     VARCHAR(32),
    AddedDate   DATETIME, 
    Title       VARCHAR(32),
    Path_String VARCHAR(255),
    ForumID     INT FOREIGN KEY REFERENCES dbo.Forums(ForumID)
);
CREATE INDEX f ON dbo.Posts(ForumID, PostID DESC) INCLUDE(AddedBy, AddedDate, Title);
GO

现在,因为Path_String几乎肯定只写了一次,所以你可以从使这个为持久计算列并为其编制索引中获益匪浅。这样,您只需在插入行时计算昂贵的子字符串,而不是每次运行查询时都要付出代价。

ALTER TABLE dbo.Posts ADD ThreadID AS 
    CONVERT(INT,SUBSTRING(Path_String, 0, CHARINDEX('/', Path_String))) 
    PERSISTED FOREIGN KEY REFERENCES dbo.Threads(ThreadID);

CREATE INDEX t ON dbo.Posts(ThreadID);

CREATE INDEX f ON dbo.Posts(ForumID, PostID DESC) 
    INCLUDE(AddedBy, AddedDate, Title, ThreadID) WITH (DROP_EXISTING = ON);
GO

有了这些东西,您的查询可以重写为:

;WITH p AS
(
    SELECT PostID, AddedBy, AddedDate, Title, ForumID, ThreadID, 
        rn = ROW_NUMBER() OVER (PARTITION BY ForumID ORDER BY PostID DESC),
        c  = COUNT(*)     OVER (PARTITION BY ForumID)
    FROM dbo.Posts
)
SELECT
    ForumGroup    = fp.Title,
    f.Title,
    f.Description,
    ThreadCount   = p.c,
    LastPostBy    = p.AddedBy,
    LastPostDate  = p.AddedDate,
    LastPostTitle = p.Title,
    ThreadID      = p.ThreadID,
    ThreadTitle   = t.Title
FROM dbo.Forums AS f
  INNER JOIN p                      ON p.ForumID  = f.ForumID
  LEFT OUTER JOIN dbo.Threads AS t  ON t.ThreadID = p.ThreadID
  LEFT OUTER JOIN dbo.Forums  AS fp ON fp.ForumID = f.ParentID
WHERE p.rn = 1
AND f.ParentID IS NOT NULL
ORDER BY f.Title;

随意比较执行计划。由于您使用的所有子查询,您将在查询版本中看到更多扫描/搜索/嵌套循环。

当然,如果没有样本数据和期望的结果,我不知道你写的查询(我根据我的答案)是否能得到你需要的结果。但希望你能来到这里并提供更多细节。

答案 1 :(得分:1)

你是否可以尝试在select语句中使用TreadID代替上次选择的TreadID?如果是这样,你可以使用相同的查询并将其替换为TreadID。

    SELECT ForumGroup = ( 
      CASE WHEN ParentID IS NOT NULL THEN 
        (SELECT Title FROM Forums WHERE ForumID = F.ParentID)            
      ELSE 
        (SELECT Title FROM Forums WHERE ParentID IS NULL) 
      END), 
      Title,  
      Description,  
      ThreadCount = (SELECT COUNT(*) 
                     FROM Posts P 
                     WHERE  P.ForumID = F.ForumID), 
      LastPostBy = (SELECT TOP 1 AddedBy 
                    FROM Posts P  
                    WHERE P.ForumID = F.ForumID 
                    ORDER BY P.PostID DESC),  
      LastPostDate = (SELECT TOP 1 AddedDate 
                      FROM Posts P  
                      WHERE P.ForumID = F.ForumID 
                      ORDER BY P.PostID DESC),  
      LastPostTitle = (SELECT TOP 1 Title 
                       FROM Posts P  
                       WHERE P.ForumID = F.ForumID 
                       ORDER BY P.PostID DESC), 
      ThreadID =  CAST(SUBSTRING((SELECT TOP 1 Path_String  
                                  FROM Posts P 
                                  WHERE P.ForumID = F.ForumID 
                                  ORDER BY P.PostID DESC), 0,  CHARINDEX('/', (SELECT TOP 1 Path_String 
                                                                               FROM Posts P  
                                                                               WHERE P.ForumID = F.ForumID 
                                                                               ORDER BY P.PostID DESC)
                                                                        )
                                ) AS INT), 
      ThreadTitle = (SELECT TOP 1 Title 
                     FROM Posts P  
                     WHERE P.PostID = (CAST(SUBSTRING((SELECT TOP 1 Path_String  
                                                        FROM Posts P 
                                                        WHERE P.ForumID = F.ForumID 
                                                        ORDER BY P.PostID DESC), 0,  CHARINDEX('/', (SELECT TOP 1 Path_String 
                                                                                                     FROM Posts P  
                                                                                                     WHERE P.ForumID = F.ForumID 
                                                                                                     ORDER BY P.PostID DESC)
                                                                                               )
                                                       ) AS INT)) 
                    ORDER BY P.PostID DESC
                    )  
      FROM Forums F WHERE ParentID IS NOT NULL 
      ORDER BY Title