2

特定のマシンのすべてのパーツとサブパーツを入手する手順を書いています。ただし、サブパーツにサブパーツなどがある場合もあります。トップ レベルでは、パーツにはリビジョン番号があります。その後、サブ パーツの最大リビジョン番号を取得します。これは、最新のものが必要なためです (各リビジョンには同じサブ パーツがあり、変更された図面だけであり、変更されていません。気にしないでください)。これまでのところ、私はこれを得ました:

CREATE TABLE [dbo].[PartMtl_3](
[PartNum] [nvarchar](50) ,
[RevisionNum] [nvarchar](16) NULL,
[MtlPartNum] [nvarchar](70)
) ON [PRIMARY]
--Here I can't put a primary key because 
--it should be PartNum and RevisionNum and MtlPartNum together
-- but i know some of the data have a null in the revision
-- and tsql don't support a pk null

Input parameter for the procedure @Machine VARCHAR(30)

DECLARE @Mytable TABLE
(
id INT IDENTITY(1,1) NOT NULL,
PartNum VARCHAR(70),
RevisionNum VARCHAR(16),
Processed TINYINT,
ParentId INT
)

DECLARE @ID INT;
DECLARE @PartNum VARCHAR(70)
DECLARE @RevisionNum VARCHAR(16)

INSERT INTO @Mytable(PartNum,RevisionNum,Processed,ParentId)
SELECT PartNum,RevisionNum,0,NULL WHERE Machine=@Machine

--Whith this insert I have my top parts for the machine

WHILE (SELECT COUNT(*) FROM @Mytable WHERE Processed=0)>0
BEGIN
     SELECT TOP 1 @ID=id,@PartNum=PartNum,@RevisionNum=RevisionNum Where Processed=0
     INSERT INTO @MyTable(PartNum,RevisionNum,Processed,ParentId)
     SELECT MtlPartNum,(SELECT MAX(RevisionNum) FROM PartMtl_3  
      WHERE PartNum=MtlPartNum) AS RevisionNum,0,@Id FROM PartMtl_3 
        WHERE PartNum=@PartNum AND RevisionNum=@RevisionNum
     UPDATE @Matable SET Processed=1 Where id=@Id
END
--other code here to basically insert the result of @Mytable in a real table

この手順が機能することはわかっていますが、非常に遅く、サーバーのすべてのリソースを消費します。それで、カーソルを使用して最適化することは可能ですか(非常に近いと思うので、そのアプローチについては疑問があります)またはセットベース操作ですか?

4

1 に答える 1

0

基本的に、パスごとに取得した未処理の部分をすべて保持するテーブル変数を作成します。

これにより、ループの頻度を減らし、同時に複数のエントリを更新できます。

また、事前に MaxRevisionNum を計算する CTE を作成します。これにより、レコードごとにクエリを再実行する必要がなくなります (これは基本的に、クエリをフィールドに入れるときに発生することです。

次に、結合を使用して必要なものを挿入し@MyTable、ループの最後で処理された部分を更新します。

コードは次のようになります。

データセットに対してテストできなかったため、微調整が必​​要になる場合がありますが、必要なものに非常に近いはずです。

declare @Unprocessed TABLE
(
id INT IDENTITY(1,1) NOT NULL,
PartNum VARCHAR(70),
RevisionNum VARCHAR(16)
)

WHILE (SELECT COUNT(*) FROM @Mytable WHERE Processed=0)>0
BEGIN
     delete from @Unprocessed
     insert into @Unprocessed
     select id, PartNum, RevisionNum 
           FROM @Mytable Where Processed=0

     ;WITH cte_partNum as
        ( select PartNum, MAX(RevisionNum) as RevisionNum 
           FROM PartMtl_3 group by PartNum )

     INSERT INTO @MyTable(PartNum,RevisionNum,Processed,ParentId)
     SELECT PartMtl_3.MtlPartNum, cte_partNum.RevisionNum ,0, Unprocessed.id 
     FROM PartMtl_3 
       inner join cte_partNum 
            on PartMtl_3.MtlPartNum = cte_partNum.PartNum
       inner join @Unprocessed  as Unprocessed 
            on Unprocessed.PartNum = PartMtl_3.PartNum 
                and Unprocessed.RevisionNum = PartMtl_3.RevisionNum

     UPDATE tbl
     set Processed = 1
     from @Matable tbl
        inner join @Unprocessed as Unprocessed
            on tbl.id = Unprocessed.id
END

OPコメントに基づいていくつかの修正が行われました。

于 2013-06-28T14:42:23.757 に答える