2010-01-04 34 views
1

我有一個存儲過程,它可以排序pnd尋址,就像Scott Michell的Sorting Custom Paged Results of一樣。INNER JOIN和Row_Num()函數問題

我有兩個表格:ArticleCategory。我的存儲過程適用於Article表,但我想從Category表中添加一列到查詢中(Inner Join I mean)。

其實我不能像斯科特米歇爾所做的那樣做,因爲在這兩個表格中都有一些相似的列(當我一直喜歡斯科特時,我得到「不明確的列錯誤」)。

我沒有內部連接存儲過程是:

set ANSI_NULLS ON 
set QUOTED_IDENTIFIER ON 
go 

ALTER PROCEDURE [dbo].[sp_Articles_SelectByCategoryId] 
    @CategoryId int, 
    @startRowIndex int = -1, 
    @maximumRows int = -1, 
    @sortExpression nvarchar(50), 
    @recordCount int = NULL OUTPUT 
AS 
    IF (@recordCount IS NOT NULL) 
    BEGIN 
     SET @recordCount = (SELECT COUNT(*) 
          FROM [dbo].[Articles] 
          WHERE [CategoryId] = @CategoryId) 
     RETURN 
    END 

    IF LEN(@sortExpression) = 0 
     SET @sortExpression = 'Id' 

    DECLARE @sql nvarchar(4000) 

    SET @sql = 'SELECT [Id], [AddedDate], [AddedBy], [CategoryId], 
         [Title], [Abstract], [Body] 
       FROM 
        (SELECT 
         [Id], [AddedDate], [AddedBy], [CategoryId], 
         [Title], [Abstract], [Body], 
         ROW_NUMBER() OVER(ORDER BY ' + @sortExpression + ') as RowNum 
        FROM [dbo].[Articles] 
        WHERE CategoryId = ' + CONVERT(nvarchar(10), @CategoryId) + ') as CategoryIdInfo 
     WHERE ((RowNum between (' + CONVERT(nvarchar(10), @startRowIndex) + ') AND ' + CONVERT(nvarchar(10), @startRowIndex) + ' + ' + CONVERT(nvarchar(10), @maximumRows) + ' - 1) 
    OR ' + CONVERT(nvarchar(10), @startRowIndex) + ' = -1 OR ' + CONVERT(nvarchar(10), @maximumRows) + ' = -1)' 

     -- Execute the SQL query 
     EXEC sp_executesql @sql 

Category表:

CREATE TABLE [dbo].[Category] 
(
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [AddedDate] [datetime] NOT NULL, 
    [AddedBy] [nvarchar](250) COLLATE Arabic_CI_AS NOT NULL, 
    [Title] [nvarchar](50) COLLATE Arabic_CI_AS NOT NULL, 
    [Importance] [int] NOT NULL, 
    [Description] [nvarchar](300) COLLATE Arabic_CI_AS NULL, 
    [ImageUrl] [nvarchar](50) COLLATE Arabic_CI_AS NULL, 

    CONSTRAINT [PK_Category] 
     PRIMARY KEY CLUSTERED ([Id] ASC) 
) 

Article表:

CREATE TABLE [dbo].[Articles] 
(
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [AddedDate] [datetime] NOT NULL, 
    [AddedBy] [nvarchar](250) COLLATE Arabic_CI_AS NOT NULL, 
    [CategoryId] [int] NOT NULL, 
    [Title] [nvarchar](255) COLLATE Arabic_CI_AS NOT NULL, 
    [Abstract] [nvarchar](4000) COLLATE Arabic_CI_AS NULL, 
    [Body] [nvarchar](max) COLLATE Arabic_CI_AS NOT NULL, 
    [ReleaseDate] [datetime] NULL, 
    [ExpireDate] [datetime] NULL, 
    [Approved] [bit] NOT NULL, 
    [Listed] [bit] NOT NULL, 
    [CommentEnabled] [bit] NOT NULL, 
    [OnlyForMembers] [bit] NOT NULL, 
    [ViewCount] [int] NOT NULL, 
    [Votes] [int] NOT NULL, 
    [TotalRating] [int] NOT NULL, 
CONSTRAINT [PK_Articles] PRIMARY KEY CLUSTERED 
(
    [Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

我不知道怎麼加將「類別」表的「標題」列轉換爲查詢。

如果我Category表有沒有類似的領域,當然這查詢的工作:

DECLARE @sql nvarchar(4000) 
SET @sql = 
'SELECT 
    [Id], 
    [AddedDate], 
    [AddedBy], 
    [CategoryId], 
    [Title], 
    [Abstract], 
    [Body], 
    ArticleTitle 
FROM 
    (SELECT 

    [Id], 
    [AddedDate], 
    [AddedBy], 
    a.[CategoryId], 
    [Title], 
    [Abstract], 
    [Body], 
    b.Title as CategoryTitle , 
ROW_NUMBER() OVER(ORDER BY ' + @sortExpression + ') as RowNum 

    FROM [dbo].[Articles] a INNER JOIN Category b on a.CategoryId = b.Id 

    WHERE a.CategoryId = ' + CONVERT(nvarchar(10), @CategoryId) + ' 
    ) as CategoryIdInfo 

如果你想測試你可以下載Attachment(Tables and StoredProcedure) 謝謝

+1

不明確的列錯誤 - 如果你有相同的列名,那麼你可以用表名/別名限定列名,以便它一點也不含糊 – David 2010-01-04 22:50:40

+0

穆斯塔法 - 伊夫增加了第二個答案,以基本相同的代碼但基於你的例子sproc。我會整理這個,如果它適合你,我只是增加了新的答案清晰(因爲我擔心我的原來的答案去社區維基) – 2010-01-05 00:54:20

回答

2

以下代碼完美地適用於您提供的表格 - 其中沒有數據,但這不應該有所作爲,因爲我只是想證明查詢執行,而不是結果。

事情,此代碼要注意:

排序表達式必須包括一個別名

SET @sortExpression = 'a.Id'  

所有複製列必須別名

。注[ID]如何,a。[AddedDate],a。[AddedBy],a。[CategoryId],a。[Title],b。[Title] all aliased

列名必須在內部和外部查詢

你在你的外選擇有ArticleTitle的列名,但CategoryTitle在你的內選擇一列之間的匹配。那絕對不行。

DECLARE @SortExpression nvarchar(100) 
SET @sortExpression = 'a.Id'   

DECLARE @sql nvarchar(4000) 
SET @sql = 
'SELECT 
    [Id], 
    [AddedDate], 
    [AddedBy], 
    [CategoryId], 
    [Title], 
    [Abstract], 
    [Body], 
    CategoryTitle 
FROM 
    (SELECT 

    a.[Id], 
    a.[AddedDate], 
    a.[AddedBy], 
    a.[CategoryId], 
    a.[Title], 
    [Abstract], 
    [Body], 
    b.Title as CategoryTitle , 
ROW_NUMBER() OVER(ORDER BY ' + @sortExpression + ') as RowNum 

    FROM [dbo].[Articles] a INNER JOIN Category b on a.CategoryId = b.Id 

    WHERE a.CategoryId = ' + CONVERT(nvarchar(10), @CategoryId) + ' 
    ) as CategoryIdInfo' 

     -- Execute the SQL query 
    EXEC sp_executesql @sql 
+0

大衛謝謝你!你幫了我很多。如果我再花一天時間,我無法解決我的問題。你怎麼看待刪除我們以前的評論,因爲答案是這篇文章。 – Mostafa 2010-01-05 08:23:50

0

您是否嘗試過類似的代碼下面?

這使用AS關鍵字爲子查詢中的列提供唯一的名稱,並使用別名來明確引用子查詢連接本身內的列。

另請注意,所有對不明確的列的引用必須是別名,這包括您的情況下動態注入的@sortExpression。

ALTER PROCEDURE [dbo].[sp_Articles_SelectByCategoryId] 
@CategoryId int, 
@startRowIndex int = -1, 
@maximumRows int = -1, 
@sortExpression nvarchar(50), 
@recordCount int = NULL OUTPUT 

AS 

IF (@recordCount IS NOT NULL) 
BEGIN 
    SET @recordCount = (SELECT COUNT(*) FROM [dbo].[Articles] WHERE [CategoryId] = @CategoryId 
) 
    RETURN 
END 

IF LEN(@sortExpression) = 0 
    SET @sortExpression = 'Id' 

DECLARE @sql nvarchar(4000) 
SET @sql = 
'SELECT 
[Id], 
[AddedDate], 
[AddedBy], 
[CategoryId], 
[Title], 
-- CategoryTitle refers to the column name declared by that AS inside the subquery 
CategoryTitle 
[Abstract], 
[Body], 

FROM 
(SELECT 

[Id], 
[AddedDate], 
[AddedBy], 
-- The column aliases a and c allow us to refer to similarly names column unambiguously 
a.[CategoryId], 
a.[Title], 
c.[Title] as CategoryTitle, 
[Abstract], 
[Body], 

--- This now includes an alias on the sortExpression order by 
ROW_NUMBER() OVER(ORDER BY a.' + @sortExpression + ') as RowNum 

FROM [dbo].[Articles] a 
Join [dbo].[Category] c 
ON c.CategoryID = a.CategoryID 
WHERE c.CategoryId = ' + CONVERT(nvarchar(10), @CategoryId) + ' 

) as CategoryIdInfo 
WHERE 
((RowNum between (' + CONVERT(nvarchar(10), @startRowIndex) + ') AND ' + CONVERT(nvarchar(10), @startRowIndex) + ' + ' + CONVERT(nvarchar(10), @maximumRows) + ' - 1) 
    OR ' + CONVERT(nvarchar(10), @startRowIndex) + ' = -1 OR ' + CONVERT(nvarchar(10), @maximumRows) + ' = -1)' 

    -- Execute the SQL query 
    EXEC sp_executesql @sql 

,做什麼是聲明的別名文章和分類表(分別爲A和C),使您可以明確地引用其列兩者。

我還沒有嘗試過使用Row_Number的確切情況,但可以認爲沒有理由爲什麼它不起作用。

然後使用AS關鍵字應該給你一個唯一的名字用於你的外部選擇。

+0

大衛,我不擅長與SQL,但我試過每一個我想到的方式,這個查詢不起作用。我知道如何使用別名,但問題是我有兩個選擇(select,,,... from(,,,, Rownum .....) – Mostafa 2010-01-04 23:08:26

+0

您是否看到我的答案的部分談論AS關鍵字對於標題列?我只是試圖用一個子選擇,它按預期工作,允許選擇兩個標題列。 – 2010-01-04 23:16:30

+0

另外,你有沒有嘗試只運行內部查詢,與聯盟?我一直髮現,打破東西 – 2010-01-04 23:17:57