0

在添加记录时,我有一个要插入答案表的问题 ID 列表。

<!--- answers query --->
<cfquery name="answers">
    SELECT answer, rank 
    FROM answers 
    WHERE question_id IN (<cfqueryparam  cfsqltype="cf_sql_integer" list="true" separator="," value="#qid#">)                       
</cfquery>

qid是我检索答案的旧问题 ID 的列表,然后我用新的问题 ID 复制相同的答案。

<!--- list of questionids --->
<cfset questionid = ArrayToList(idArray)> 
    <cfquery name="insertanswers">
        INSERT INTO answers (
            question_id, answer, rank
        )
        VALUES 
            <cfloop query="answers">
                (
                <cfqueryparam cfsqltype="cf_sql_integer" list="true" separator="," value="#questionid#">
                ,<cfqueryparam cfsqltype="cf_sql_varchar" value="#answers.answer#">
                ,<cfqueryparam cfsqltype="cf_sql_numeric" value="#answers.rank#">
                )
                <cfif answers.CurrentRow LT answers.RecordCount>,</cfif> 
            </cfloop>
    </cfquery>

在添加记录时column count doesn't match value count出现错误,但是当我用它包装代码cftry并转储它时,我发现它以逗号分隔的形式为每个答案获取两个 id。有没有办法为每个答案只传递一个 id?我只是用较新的问题 ID 替换较旧的问题 ID。

4

1 回答 1

1

由于您需要链接新旧 id,因此您需要一种与此处使用的方法不同的方法。当您生成新的问题记录时,将 id 存储在一个结构中,而不是一个数组中,这样您就可以维护旧 => 新值的映射。

<!--- initialize mapping of old => new ids --> 
 <cfset idMapping = {}>

  <cfloop ...>

         <!--- use the "result" attribute to capture the new id --->
         <cfquery result="addRecord" ....>
           INSERT INTO YourTable (...) VALUES (...);
         </cfquery>

         <!--- save the id in the array -->
         <cfset idMapping[ oldQuestionID ] = addRecord.GENERATED_KEY>

 </cfloop>

当您插入新答案时,使用旧 id 进行查找并从结构中获取新问题 id。这需要验证,但这是一般的想法。

注意:为确保数据完整性,两个查询块应包含在单个<cftransaction>

   <cfquery name="insertanswers">
        INSERT INTO answers (
            question_id, answer, rank
        )
        VALUES 
            <cfloop query="answers">
                (
                <!--- get the new id from the structure --->
                <cfqueryparam cfsqltype="cf_sql_integer" value="#idMapping[ oldQuestionID ]#">
                ,<cfqueryparam cfsqltype="cf_sql_varchar" value="#answers.answer#">
                ,<cfqueryparam cfsqltype="cf_sql_numeric" value="#answers.rank#">
                )
                <cfif answers.CurrentRow LT answers.RecordCount>,</cfif> 
            </cfloop>
    </cfquery>

更新1:

这是一个完整的例子:

更新 2:

如果这是经常发生的情况,我会建议一种不同的方法来消除循环。向主表添加一个 UUID 列(用于标识新记录)。然后使用临时表(带有自动填充的 UUID 列)来存储您要传输的记录。它并不像听起来那么复杂..

(我没有方便的 MySQL 语法,所以这是针对 SQL Server 的,但总体概念是相同的)。

    -- use DEFAULT to automatically generate a UUID for each record
    CREATE TABLE #NewQuestions ( 
        , OldQuestionID int
        , TheUUIDColumn uniqueidentifier DEFAULT(NewID())
    )

    --- insert the records you want to transfer  
    INSERT INTO #NewQuestions ( OldQuestionID )
    SELECT  QuestionID
    FROM    Questions
    WHERE   .....

接下来,使用 JOIN 将这些问题重新插入到主表中。请注意,它如何存储 UUID,以便我们稍后可以识别新记录。

    INSERT INTO Questions( TheUUIDColumn, Question, ... )
    SELECT  tmp.TheUUIDColumn, q.Question, ....
    FROM    Questions q INNER JOIN #NewQuestions tmp 
                 ON tmp.OldQuestionID = q.QuestionID

最后,使用 UUID 来识别新旧 id 并插入相关的“答案”

    INSERT INTO answers ( QuestionID, Answer, ....)
    SELECT q.QuestionID, a.Answer
    FROM   Questions q 
                INNER JOIN #NewQuestions tmp ON tmp.TheUUIDColumn = q.TheUUIDColumn
                INNER JOIN answers a ON a.QuestionID = tmp.OldQuestionID

临时表方法提供了更好的控制。它也是基于集合的,这比通过循环一次处理一条记录要高效得多。

于 2013-08-30T16:06:49.433 回答