如何在执行INSERT时加入TOP 1?

时间:2012-12-29 23:19:10

标签: sql sql-server

我想从SQL Server进行特殊查询。它来自2个表:

  1. 具有列catParentId
  2. 的Cat表
  3. catId
  4. 相关的消息表

    我希望通过catId获取与该类别相关的最后消息详细信息。换句话说,我想为父猫下的每只猫获取最后一条消息。

    我创建了表变量并将值插入其中。这是性能的最佳方式吗?

    SP代码:

    USE [Lovely_umbraco_cms]
    GO
    /****** Object:  StoredProcedure [dbo].[SP_Categories_GetCatsMsgs]    Script Date: 12/30/2012 01:21:33 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    ALTER PROCEDURE [dbo].[SP_Categories_GetCatsMsgs]
     @CatId int
    AS
    set @catId =1;
    declare @CatMessages Table(
         RowID       INT    IDENTITY ( 1 , 1 ), 
         CatName Nvarchar(50),
         MessageCount int,
         LastMessageName nvarchar(50),
         OwnerID uniqueidentifier, 
         CreatedDate date,
         Watched int,
         commentCount int
    )
    --------------- @CatTable --------
    declare @RowsCount int;
    Set @rowscount =1;
    
    declare @CatTable table(
        id int identity(1,1),
        catId int,
        CatName nvarchar(50),
        CatParentId int
    ); 
    --- Insert into @CatTable
    insert into @CatTable(catId,catName,CatParentId )
    select catId, CatName ,CatParentId from LS_Categories WHERE(CatParentId = @CatId);
    -----------------------------------
    
    declare @CatTableID int;
    
    declare @CatName nvarchar(50);
    
    -------Temp Message Table --------
    declare @Temp_MessagesTable table(
        [Subject] nvarchar(255),
        [Date] [nvarchar](15) NULL,
        [OwnerId] [uniqueidentifier] NULL,
        [WatchCount] [bigint] NULL
    );
    --------------- @CatMessages Varibles-----
    
         declare @MessageCount int;
         declare @LastMessageName nvarchar(50);
         declare @OwnerID uniqueidentifier; 
         declare @CreatedDate date;
         declare @Watched int;
         declare @commentCount int;
    -------
    while @rowsCount <=(SELECT count(Catid) FROM  @CatTable)
    begin
        select @CatTableID = CatId, @CatName = CatName from @CatTable where id= @rowsCount;
    
        delete from @Temp_MessagesTable;
    
        insert into @Temp_MessagesTable ([Subject],[Date],[OwnerId],[WatchCount])(
        SELECT      Subject, Date, OwnerId, WatchCount
        FROM         (SELECT     TOP (1) Subject, Date, OwnerId, WatchCount
        FROM         LS_Mssages 
        WHERE     (CatId = @CatTableID) ORDER BY MsgId DESC
        ) as s 
        );
        select @LastMessageName=[Subject],@CreatedDate=[Date],
                @OwnerID=[OwnerId],@Watched= [WatchCount] from @Temp_MessagesTable
    
        -- insert into CatMessages Table
        insert into @CatMessages(CatName,MessageCount,LastMessageName,OwnerID,CreatedDate,Watched,commentCount)
                                 (select @CatName,@MessageCount,@LastMessageName,@OwnerID,@CreatedDate,@Watched,@commentCount);
        set @rowsCount = @rowsCount+1
    End
    
    select * from @CatMessages;
    

    我的表格:http://ss-projects.com/t1.jpg

    数据样本:http://ss-projects.com/data.jpg

    结果:http://ss-projects.com/result.jpg

1 个答案:

答案 0 :(得分:4)

这不是在SQL中执行此操作的最佳方法。

SQL不是为循环而设计的,而是您希望一次编写对所有元素都有效的查询,而不是一次。

以下内容与您的代码相同,并且还会点亮错误(选择列表中的NULLS)。

INSERT INTO CatMessages
  SELECT C.CatName, M.Subject, NULL as LastMessageName, M.OwnerID, M.Date, M.WatchCount, NULL as CommentCount
  FROM CatTable C
  JOIN LS_Mssage M ON C.CatID = M.CatID

限制LS_Mssage表的最简单方法:

INSERT INTO CatMessages
  SELECT C.CatName, M.Subject, NULL as LastMessageName, M.OwnerID, M.Date, M.WatchCount, NULL as CommentCount
  FROM CatTable C
  JOIN (SELECT *, ROW_NUMBER() OVER (PARTITION BY CatID ORDER BY [Date] DESC) AS RN
        FROM LS_Mssage) M ON C.CatID = M.CatID AND M.RN = 1

这是如何运作的:

首先请阅读JOINS如何在SQL中工作。这是一个很深刻的主题,任何网上搜索都会让你得到比我在这个短片空间里写的更好的解释。

我使用的高级技术是OVER clause。这个over子句在LS_Mssage表中添加了一个新列,我称之为RN。 RN是一个自动增加索引,每次CatID更改(PARTITION BY)时都会重新启动,并应用于按日期降序排序的结果(ORDER BY [Date] DESC)。这意味着最新的一个将始终具有1的RN。然后,我只在查看RN为1的行时加入此表。

要真正理解这一点,请自行运行此查询:

SELECT *, 
       ROW_NUMBER() OVER (PARTITION BY CatID ORDER BY [Date] DESC) AS RN
FROM LS_Mssage

查看并了解新表。

这比你的代码快得多,这个表只需要创建一次,但是在循环中,需要为循环的每次迭代完成相同数量的工作。这就是在使用SQL时需要考虑集合(或查询)的原因。