INNER JOIN 和 Row_Num() 函数问题

发布于 2024-08-17 11:18:01 字数 4233 浏览 6 评论 0原文

我有一个存储过程,它对 pnd 分页进行排序,如 对 Scott Michell 的自定义分页结果进行排序

我有两个表:ArticleCategory。我的存储过程适用于 Article 表,但我想将 Category 表中的一列添加到查询中(我的意思是内部联接)。

实际上我不能像斯科特·米歇尔那样做,因为两个表中都有一些相似的列(当我一直喜欢斯科特时,我会得到“不明确的列错误”)。

我没有内部联接的存储过程是:

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”表的“Title”列添加到询问。

如果我的 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

如果您想测试,可以下载 附件(表和 StoredProcedure) 谢谢

I have a stored procedure which does sorting pnd Paging like the Sorting Custom Paged Results of by Scott Michell.

I have two tables: Article and Category. My stored procedure works fine for Article table, but I want add a column from the Category table into the query (Inner Join I mean ).

Actually I can't do it like Scott Michell has done, because there are some columns that are similar in both tables (when I do like Scott all the time I get "Ambiguous Column Error").

My stored procedure without inner join is :

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

My Category table is :

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)
)

My Article table :

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]

I don't know how to add The "Title" column of "Category" table into query.

If my Category table hadn't similar fields, surely this query works :

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

If you want to Test you can download the Attachment(Tables and StoredProcedure)
Thank you

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

与之呼应 2024-08-24 11:18:01

以下代码在您提供的表上完美运行 - 其中没有数据,但这应该不会产生影响,因为我只想证明查询执行,而不是结果。

此代码需要注意的事项:

排序表达式必须包含别名

SET @sortExpression = 'a.Id'       

所有重复列都必须有别名

请注意 a.[Id]、a.[AddedDate]、a.[Id]、a.[AddedDate]、a.[Id]、a.[AddedDate]、a. [AddedBy]、a.[CategoryId]、a.[Title]、b.[Title] 都是别名

内部和外部查询之间的列名称必须匹配

您的列名称为 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  

The following code works perfectly on your provided tables - with no data in them but that shouldn't make a difference since I just want to prove the query execution, not the results.

Things to note with this code:

The sort expression must include an alias

SET @sortExpression = 'a.Id'       

All duplicated columns must be aliased

Note how a.[Id], a.[AddedDate], a.[AddedBy], a.[CategoryId], a.[Title], b.[Title] are all aliased

Column names must match between the inner and outer queries

You had a column name of ArticleTitle in your outer select, but a column of CategoryTitle in your inner select. That would never work.

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  
知足的幸福 2024-08-24 11:18:01

您是否尝试过类似下面的代码?

这使用 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 

其作用是为 Articles 和 Category 表(分别为 a 和 c)声明一个别名,允许您明确地引用它们的列。

我还没有尝试过使用 Row_Number 的确切情况,但想不出它不起作用的原因。

然后使用 AS 关键字应该为您提供一个与外部选择一起使用的唯一名称。

Have you tried something like the code below?

This uses the AS keyword to give unique names to columns in your subquery, and aliases to allow unambiguous references to columns within the subquery join itself.

Also note that ALL references to columns that are ambiguous must be aliases, this includes in your case the @sortExpression that you are dynamically injecting.

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 

What that does is declare an alias for both the Articles and the Category table (a and c respectively) that allows you to reference their columns unambiguously.

I haven't tried this with the exact case of using Row_Number but can think of no reason why it wouldn't work.

Then using the AS keyword should give you a unique name to use with your outer select.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文