Длина кода против организации - PullRequest
2 голосов
/ 01 сентября 2009

У меня есть несколько вложенных команд вставки. Некоторые из вложенных циклов совместно используют избыточный код. Должен ли я сделать избыточный код своим собственным циклом или создать отдельные экземпляры одного и того же кода в каждом цикле?

ПРИМЕР (отредактировано для уточнения):

--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

Один и тот же шаблон повторяется снова и снова, с различными значениями @values ​​и @ question.

Ответы [ 7 ]

3 голосов
/ 01 сентября 2009

Согласен с комментатором - избавьтесь от петель. У вас есть мощный, основанный на множестве язык, и вы пишете процедурный код. Я бы рекомендовал переоценить проблему, чтобы сформировать решение, которое будет работать лучше для SQL Server (у вас есть сообщество, которое поможет вам). Хотя то, что вы делаете, будет работать (и, вероятно, работает), это будет / является головной болью при обслуживании.

3 голосов
/ 04 сентября 2009

ОК, это должно работать:

**

Смотри, мама, без петель!:

**

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;
1 голос
/ 01 сентября 2009

Я использую следующее правило:

  • Если код повторяется один раз. подумайте, стоит ли проводить рефакторинг (он снова понадобится).
  • Если код повторяется более одного раза, рефакторинг.
0 голосов
/ 02 сентября 2009

Я бы разделил свои входные данные на временную таблицу или табличную переменную, а затем использовал бы это в операторе вставки, основанном на предложении select, а не values.

0 голосов
/ 02 сентября 2009

Как и все, кому приходилось работать с существующей кодовой базой, я столкнулся с таким кодом. Плакат "делает правильные вещи", ТМ в том смысле, что они используют циклы, а не курсоры (Yeck!).

Один из способов решить проблему с необходимостью циклов - посмотреть, что у вас есть в заполнителях STUFF и OTHER STUFF. Может быть, вам не нужен цикл, но два разных утверждения. Постарайтесь выяснить, зачем вам нужны циклы и можно ли вместо этого вставить / обновить набор данных.

В любом случае, люди, которые должны работать над кодом после того, как вы перешли к чему-то другому, будут вам благодарны, если пойдете в этот лишний ярд сейчас.

0 голосов
/ 01 сентября 2009

Я бы все это собрал в один цикл. Поскольку единственное отличие состоит в том, что один набор элементов выполняется для @foo с 0..4, а другой - для 5..9, используйте оператор IF для переключения между ними, например ::

.
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
0 голосов
/ 01 сентября 2009

Не зная всех подробностей, я бы порекомендовал использовать sproc или функцию для инкапсуляции вашего избыточного кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...