0

SQL Server から特別なクエリを作成したいと考えています。それは2つのテーブルからです:

  1. 列のある猫のテーブルcatParentId
  2. catId列に関連するメッセージ テーブル

そのカテゴリに関連する最後のメッセージの詳細を含む 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

4

1 に答える 1

4

これは、SQL でこれを行う最良の方法ではありません。

SQL はループ用に設計されていません。代わりに、一度に 1 つずつではなく、すべての要素に対して機能するクエリを作成する必要があります。

以下はコードコードと同じで、バグを強調しています (選択リストの 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 でどのように機能するかをお読みください。これは深いトピックであり、Web で検索すると、この短いスペースに書ききれないほど詳しい説明が表示されます。

私が使用する高度な手法は、OVER 句です。この over 句は、私が RN と呼ぶ LS_Mssage テーブルに新しい列を追加します。RN は、CatID が変更されるたびに再開される自動増加インデックス (PARTITION BY) であり、日付の降順 (ORDER BY [Date] DESC) で並べ替えられた結果に適用されます。これは、最新のテーブルの RN が常に 1 であることを意味します。次に、このテーブルに参加して、RN が 1 の行だけを調べます。

これを本当に理解するには、次のクエリを単独で実行します。

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

新しいテーブルを見て理解してください。

これはコードよりもはるかに高速です。このテーブルは一度だけ作成する必要がありますが、ループでは、ループの反復ごとに同じ量の作業を行う必要があります。これが、SQL を扱うときにセット (またはクエリ) で考える必要がある理由です。

于 2012-12-29T23:49:47.047 に答える