代码长度与组织

时间:2009-09-01 13:52:15

标签: sql sql-server tsql

我有几个嵌套的插入命令。一些嵌套循环共享冗余代码。我应该将冗余代码作为自己的循环,还是在每个循环中创建相同代码的单独实例?

示例(编辑以供澄清):

--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 个答案:

答案 0 :(得分:3)

我同意评论者的意见 - 摆脱循环。你有一个强大的,基于集合的语言,你正在编写程序代码。我建议重新评估问题,以形成一个更适合SQL Server的解决方案(这里有一个可以帮助你的社区)。虽然你正在做的事情会起作用(并且可能确实如此),但这将是一个维护问题。

答案 1 :(得分:3)

好的,这应该有效:

**

看Ma,没有循环!:

**

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;

答案 2 :(得分:1)

我使用以下规则:

  • 如果代码重复一次。想想它是否值得重构(再次需要迁移)。
  • 如果代码重复多次,请重构。

答案 3 :(得分:0)

我把所有这些放在一个循环中。因为唯一的区别是,一组东西是从{0}到{4}完成的,另一组是5..9,使用IF语句在它们之间切换,例如:

@foo

答案 4 :(得分:0)

像所有必须使用现有代码库的人一样,我遇到了这样的代码。海报是“做正确的事”TM,因为他们使用循环而不是游标(Yeck!)。

解决需要循环问题的一种方法是查看STUFF和OTHER STUFF占位符中的内容。也许你不需要一个循环,但两个不同的陈述。尝试弄清楚为什么需要循环以及是否可以插入/更新一组数据。

在任何情况下,在你转移到其他东西之后必须处理代码的人会感谢你,如果现在去那个额外的院子。

答案 5 :(得分:0)

我将输入拆分为临时表或表变量,然后在基于select not a values子句的insert语句中使用它。

答案 6 :(得分:-1)

在不知道所有细节的情况下,我建议使用sproc或函数来封装冗余代码。