2 Stimmen

Code-Länge vs. Organisation

Ich habe mehrere verschachtelte Einfügebefehle. Einige der verschachtelten Schleifen enthalten redundanten Code. Sollte ich den redundanten Code zu einer eigenen Schleife machen oder separate Instanzen desselben Codes in jeder Schleife erstellen?

BEISPIEL (zur Verdeutlichung bearbeitet):

--Questions 32<->37

SET @index=0

SET @values = 'at your primary grocery store^at WalMart or Sam''s Club^at any other chain (e.g. Target, K-Mart)^in general'

IF SUBSTRING(@values, LEN(@values), 1) <> '^' SET @values = @values + '^'
WHILE (LEN(@values)<>0)
BEGIN

SET @index=CHARINDEX('^', @values)
SET @result=SUBSTRING(@values, 0, @index)
SET @values=SUBSTRING(@values, LEN(@result)+2, LEN(@values)-LEN(@result)-1)

    SET @question = 'How much do you spend <b>'+@result+'</b> per trip compared to this time last year?'
    SET @qnum=@qnum+1

    INSERT INTO checklist_questions (
        checklist_id
        ,checklist_question_id
        ,checklist_answer_category_id
        ,autofail_flag
        ,checklist_responsible_type_id
        ,correction_days
        ,checklist_question_header_id
        ,question
    )
    VALUES (
        @checklist_id
        ,@qnum --question #
        ,40    --answer category id
        ,0     --autofail flag
        ,'P'   --checklist_responsible_type_id
        ,27    --correction_days
        ,4     --correction_days
        ,@question
    )

    SET @i=1
    WHILE (@i<=6)
    BEGIN
        INSERT INTO checklist_answers (
        checklist_id
        ,checklist_question_id
        ,checklist_answer_category_id
        ,checklist_answer_type_id
        ,detail_flag
        )
            VALUES (
            @checklist_id
            ,@qnum --question number
            ,38    --category
            ,@i    --answer type 
            ,0     --detail flag
        )
    SET @i=@i+1
    END
END

Das gleiche Muster wiederholt sich immer wieder, mit unterschiedlichen Werten für @values und @question.

3voto

Austin Salonen Punkte 47404

Ich stimme dem Kommentator zu - die Schleifen sollten abgeschafft werden. Sie haben eine mächtige, mengenbasierte Sprache, und Sie schreiben prozeduralen Code. Ich würde empfehlen, das Problem neu zu bewerten und eine Lösung zu finden, die besser für SQL Server geeignet ist (Sie haben hier eine Community, die Ihnen dabei helfen kann). Das, was Sie tun, wird zwar funktionieren (und tut es wahrscheinlich auch), aber es wird/ist ein Wartungsproblem.

3voto

RBarryYoung Punkte 53364

OK, das sollte funktionieren:

**

Sieh mal, Mama, keine Schleifen!:

**

declare @checklist_id INT;
SET @checklist_id = 99  -- ??

declare @index INT, @values VARCHAR(MAX);
SET @index=0
SET @values = 'at your primary grocery store^at WalMart or Sam''s Club^at any other chain (e.g. Target, K-Mart)^in general'

-- make sure all substring are bounded on both sides
IF SUBSTRING(@values, LEN(@values), 1) <> '^' SET @values = @values + '^'
IF LEFT(@values,1) <> '^'  SET @values = @values + '^'

;WITH cteNumbers AS 
(
    SELECT ROW_NUMBER() OVER(ORDER BY object_id) as N
    FROM master.sys.system_columns      --just a convenient source of rows
)
, cteValues AS
(
    SELECT  SUBSTRING(@values, N+1, CHARINDEX('^', @values, N+1)-1) as value
        ,   ROW_NUMBER() OVER(ORDER BY N) AS qnum
    FROM    cteNumbers
    WHERE   N < LEN(@values)
    AND     SUBSTRING(@values, N, 1) = '^'
)
INSERT INTO checklist_questions (
    checklist_id
    ,checklist_question_id
    ,checklist_answer_category_id
    ,autofail_flag
    ,checklist_responsible_type_id
    ,correction_days
    ,checklist_question_header_id
    ,question
    )
SELECT
    @checklist_id
    ,qnum --question #
    ,40    --answer category id
    ,0     --autofail flag
    ,'P'   --checklist_responsible_type_id
    ,27    --correction_days
    ,4     --correction_days
    ,'How much do you spend <b>'+ value +'</b> per trip compared to this time last year?'
FROM cteValues;

;WITH cteNumbers AS 
(
    SELECT ROW_NUMBER() OVER(ORDER BY object_id) as N
    FROM master.sys.system_columns      --just a convenient source of rows
)
, cteValues AS
(
    SELECT  SUBSTRING(@values, N+1, CHARINDEX('^', @values, N+1)-1) as value
        ,   ROW_NUMBER() OVER(ORDER BY N) AS qnum
    FROM    cteNumbers
    WHERE   N < LEN(@values)
    AND     SUBSTRING(@values, N, 1) = '^'
)
INSERT INTO checklist_answers (
    checklist_id
    ,checklist_question_id
    ,checklist_answer_category_id
    ,checklist_answer_type_id
    ,detail_flag
    )
SELECT
    @checklist_id
    ,qnum --question number
    ,38    --category
    , N    --answer type 
    ,0     --detail flag
FROM cteValues AS v
CROSS JOIN (SELECT N FROM cteNumbers WHERE N <= 6) AS num;

1voto

Sergio Punkte 7951

Ich wende die folgende Regel an:

  • Wenn der Code einmal wiederholt wird, sollte man überlegen, ob es sich lohnt, ihn zu refaktorieren (er könnte wieder gebraucht werden).
  • Wenn der Code mehr als einmal wiederholt wird, muss er überarbeitet werden.

0voto

Adam Bellaire Punkte 103525

Ich würde das alles in eine Schleife packen. Da der einzige Unterschied darin besteht, dass ein Satz von Dingen für @foo von 0..4 und die andere für 5..9, verwenden Sie eine IF-Anweisung, um zwischen ihnen zu wechseln, z.B.:

DECLARE @foo SMALLINT
DECLARE @bar SMALLINT

SET @foo=0

WHILE (@foo<10)
BEGIN

    IF (@foo<5) 
        --STUFF
    ELSE
        --DIFFERENT STUFF
    END

    SET @bar=0
    WHILE (@bar < 5)
    BEGIN
        --CODE
        SET @bar = @bar + 1
    END

SET @foo = @foo+1
END

0voto

Wie alle Leute, die mit einer bestehenden Codebasis arbeiten mussten, bin ich auf Code wie diesen gestoßen. Das Plakat ist "das Richtige tun "TM in, dass sie Schleifen und nicht Cursor (Yeck!) verwenden.

Eine Möglichkeit, das Problem der benötigten Schleifen zu lösen, besteht darin, sich anzusehen, was Sie in den Platzhaltern STUFF und OTHER STUFF haben. Vielleicht brauchen Sie keine Schleife, sondern zwei verschiedene Anweisungen. Versuchen Sie herauszufinden, warum Sie die Schleifen benötigen und ob Sie stattdessen einen Datensatz einfügen/aktualisieren können.

Auf jeden Fall werden die Leute, die den Code bearbeiten müssen, nachdem Sie sich etwas anderem zugewandt haben, es Ihnen danken, wenn Sie jetzt noch einen Schritt weitergehen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X