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てダンプすると、回答ごとにコンマ区切りの形式で 2 つの ID が取得されていることがわかりました。回答ごとに 1 つの ID のみを渡す方法はありますか? 古い質問IDを新しい質問IDに置き換えているだけです。

4

1 に答える 1

1

古い ID と新しい 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 と新しい 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

一時テーブルのアプローチは、より優れた制御を提供します。また、セットベースであるため、ループを介して一度に 1 つのレコードを処理するよりもはるかに効率的です。

于 2013-08-30T16:06:49.433 に答える