ここでは、私が期待していたよりも少し時間がかかりそうなストアドプロシージャがあります。このアルゴリズムを非常に長くしたのは、SQLの新しいテーブルに要素を追加すると、必ずしもトップに置かれないように思えたからです。ルーピングストアドプロシージャが遅すぎる
また、別のテーブルを作成したクエリをクエリする必要がありました。全体として、このアルゴリズムは大きすぎます。誰にも短くするためのアイデアはありますか?
DECLARE @RecipeQuery TABLE(
RecipeID NCHAR(100),
MaterialID NCHAR(100),
Quantity DECIMAL(18,4));
INSERT INTO @RecipeQuery
(RecipeID, MaterialID, Quantity)
SELECT RecipeID, MaterialID, Quantity
FROM Recipe
DECLARE @PrevRecipeQuery TABLE(
prevRecipeID NCHAR(100),
prevMaterialID NCHAR(100),
prevQuantity DECIMAL(18,4));
DECLARE @TempRecipeQuery TABLE(
TempRecipeID NCHAR(100),
TempMaterialID NCHAR(100),
TempQuantity DECIMAL(18,4));
DECLARE @MaterialFinder TABLE(
RID NCHAR(100),
MID NCHAR(100),
Q DECIMAL(18,4));
DECLARE @PrevMaterialFinder TABLE(
PRID NCHAR(100),
PMID NCHAR(100),
PQ DECIMAL(18,4));
DECLARE @CalcMaterial TABLE(
CalcRecipeID NCHAR(100),
CalcMaterialID NCHAR(100),
CalcQuantity DECIMAL(18,4));
DECLARE @ROWCOUNT1 INT
SET @ROWCOUNT1 = 0
DECLARE @ROWCOUNT2 INT
SET @ROWCOUNT2 = 0
DECLARE @ROWCOUNT3 INT
SET @ROWCOUNT3 = 0
DECLARE @isDone INT
SET @isDone = 0
DECLARE @mainRowCount INT
--------------------------------------------------------------------------------------------------
--LOOP UNTIL ALL LEVELS HAVE BEEN FOUND
WHILE(@isDone != 1)
BEGIN
SET @mainRowCount = (SELECT COUNT(*) FROM @RecipeQuery)
--LOOP THROUGH EACH ROW IN THE TABLE UNTIL ALL ROWS HAVE BEEN LOOKED AT
WHILE(@ROWCOUNT1 < @mainRowCount)
BEGIN
--IF THE ROW'S MATERIAL STARTS WITH A "TempRecipeID" THAT MEANS IT IS DONE
IF(PATINDEX('R%', (SELECT TOP 1 MaterialID FROM @RecipeQuery)) = 1)
BEGIN
--INSERT THE ROW RIGHT INTO TABLE new
INSERT INTO @CalcMaterial (CalcRecipeID, CalcMaterialID, CalcQuantity) SELECT TOP 1 RecipeID, MaterialID, Quantity FROM @RecipeQuery
SET @ROWCOUNT3 = @ROWCOUNT3 + 1
END
--OTHERWISE
ELSE
BEGIN
--FIND THE MATERIAL'S RECIPE AND PLACE THE NEW RECIPEID AND MATERIALID INTO TABLE TempMaterialID
INSERT INTO @PrevMaterialFinder (PRID, PMID, PQ) SELECT TOP(1) RecipeID, MaterialID, Quantity FROM @RecipeQuery
INSERT INTO @MaterialFinder (RID, MID, Q) SELECT (SELECT TOP 1 RecipeID FROM @RecipeQuery), MaterialID, Quantity FROM Recipe WHERE RecipeID = (SELECT TOP 1 MaterialID FROM @RecipeQuery)
DECLARE @ROWCOUNT4 INT
SET @ROWCOUNT4 = (SELECT COUNT(*) FROM @MaterialFinder)
WHILE(@ROWCOUNT2 < @ROWCOUNT4)
BEGIN
INSERT INTO @CalcMaterial
(CalcRecipeID, CalcMaterialID, CalcQuantity)
SELECT TOP 1 RID, MID, Q*(SELECT TOP 1 PQ FROM @PrevMaterialFinder)*0.001
FROM @MaterialFinder
DELETE TOP(1) FROM @MaterialFinder
SET @ROWCOUNT2 = @ROWCOUNT2 + 1
END
SET @ROWCOUNT2 = 0
END
SET @ROWCOUNT2 = 0
--DELETE THE TOP ROW
DELETE TOP(1)
FROM @RecipeQuery
--INSERT THE UPDATED ROW(S) FROM TABLE TempMaterialID INTO TABLE W
INSERT INTO @TempRecipeQuery
(TempRecipeID, TempMaterialID, TempQuantity)
SELECT CalcRecipeID, CalcMaterialID, CalcQuantity
FROM @CalcMaterial
--DELETE THE UPDATED ROWS FROM TABLE TempMaterialID
DELETE FROM @MaterialFinder
DELETE FROM @PrevMaterialFinder
DELETE FROM @CalcMaterial
--INCREASE ROW COUNTER C
SET @ROWCOUNT1 = @ROWCOUNT1 + 1
--LOOP ONTO NEXT ROW
END
--AT THIS POINT ALL OF THE ROWS HAVE BEEN GONE THROUGH AT LEAST ONCE
--INSERT THE UPDATED ROWS IN TABLE W INTO THE MAIN TABLE
INSERT INTO @RecipeQuery
(RecipeID, MaterialID, Quantity)
SELECT TempRecipeID, TempMaterialID, TempQuantity
FROM @TempRecipeQuery
--TO COMPARE
--IF THE COUNT OF BOTH TABLES IS THE SAME THEY COULD BE THE SAME
IF((SELECT COUNT(*) FROM @prevRecipeQuery) = (SELECT COUNT(*) FROM @RecipeQuery))
BEGIN
--IF THE DIFFERENCES BETWEEN THE TWO ARE NULL THEN THEY ARE THE SAME;
IF(SELECT MaterialID FROM @RecipeQuery EXCEPT SELECT prevMaterialID FROM @prevRecipeQuery) IS NULL
--SET DONE TO 1 TO END LOOP
SET @isDone = 1
END
--DELETE PREV TABLE FOR NEW UPDATE
DELETE FROM @prevRecipeQuery
--SET COPY INTO PREV
INSERT INTO @prevRecipeQuery
(prevRecipeID, prevMaterialID, prevQuantity)
SELECT RecipeID, MaterialID, Quantity
FROM @RecipeQuery
--SET THE ROW COUNTER BACK TO 0
SET @ROWCOUNT1 = 0
--DELETE ALL FROM THE TEMP UPDATED TABLE SO THAT IT CAN BE FILLED WITH UPDATED ROWS IF AGAIN
DELETE FROM @TempRecipeQuery
--AT THIS POINT THE LOOP WILL REPEAT IF THERE ARE ANY MORE STOCK SOLUTIONS AS MATERIALS
END
--AT THIS POINT, ALL LOOPS ARE DONE AND THE MAIN TABLE DOES NOT CONSIST OF ANY STOCK MATERIALS AS MATERIALS
--PRINT THE MAIN TABLE
SELECT RecipeID, MaterialID, Quantity FROM @RecipeQuery
ORDER BY RecipeID
入力はレシピテーブル ある出力は、クエリは、各レシピに材料を見つけるために、自分自身を照会として追加された行が黄色で見ることができます テーブルを必要と出力、です。
最後のクエリでは、列と行3のみが表示されなければならないことに注意してください。レベル3の生成方法を示すために追加しました。
INPUT:
レシピ材料
AA01のB1
AA01のB2
AA01 BB01
BB01 B1
BB01 CC01
CC01 B3
CC01のB4
B1のB1
B2 B2
B3 B3
B4 B4
OUTPUT:
レシピ材料
AA01 B1
AA01 B2
AA01のB1
AA01のB3
AA01のB4
BB01 B1
bb01 B3
bb01 B4
CC01 B3
CC01のB4
B1のB1
B2のB2
B3のB3
B4のB4私はSPでwhileループの性能を改善する方法の
いくつかの管理タスクを除いてループを回避する必要があります。ここには、テーブル変数にデータを挿入するだけで何もしない複数のループがあります。あなたの全体の手順は、単一のクエリに減らすことができると思われます。テーブル全体をテーブル変数にコピーすることによって、この現在のプロシージャ。この全体は、行を苦労させることによる行の代わりに、集合ベースの操作として、最初から完全に再設計する必要があります。 –
私はそれをやろうとしましたが、それを行うために既存のクエリーを継続的にクエリーしなければならず、クエリーしなければならない回数を事前に計算することができませんでした。 – SQLUser
これを行うには再帰が必要です。私たちは2005年からsqlサーバで再帰的なcteを利用できました。現在、あまり一般的ではないことを除いて誰もこのことを行うことができません。すべてのテーブル変数の定義がありますが、開始するサンプルデータや必要な出力はありません。私はこれがセットベースのアプローチで2〜2回実行できると思うが、誰も細部なしでは助けることができない。 –