0

フォローアップ:このXML形式は正しいですか?

QABLOCKをループして出力するSQLコードがいくつか動作しています(本番環境ではPRINTがINSERTに変更されます)。

-- XML instance
DECLARE    @x1 XML
SELECT @x1 = 
'
<tests>
    <test id="1">
        <qablock number="1">
            <question>What is 1 + 1?</question>
            <explanation>It"s 2.</explanation>
            <options>
                <option number="1" value="1" correct="0" />
                <option number="2" value="2" correct="1" />
                <option number="3" value="3" correct="0" />
                <option number="4" value="4" correct="0" />
                <option number="5" value="5" correct="0" />
            </options>
        </qablock>
        <qablock number="2">
            <question>What is 2 + 2?</question>
            <explanation>It"s 4.</explanation>
            <options>
                <option number="1" value="1" correct="0" />
                <option number="2" value="2" correct="0" />
                <option number="3" value="3" correct="0" />
                <option number="4" value="4" correct="1" />
                <option number="5" value="5" correct="0" />
            </options>
        </qablock>
    </test>
</tests>
'

DECLARE 
    @cnt INT, 
    @totCnt INT,
    @child XML

-- counter variables
SELECT 
    @cnt = 1,
    @totCnt = @x1.value('count(/tests/test/qablock)','INT')

-- loop
WHILE @cnt <= @totCnt BEGIN
    SELECT
        1 AS tests_id, --this is hard-coded
        @cnt AS qablock_number, 
        @x1.value('(/tests/test/qablock[position()=sql:variable("@cnt")]/question/text())[1]','varchar(500)') AS question, 
        @x1.value('(/tests/test/qablock[position()=sql:variable("@cnt")]/explanation/text())[1]','varchar(1000)') AS explanation

    PRINT 'Processing Child Element: ' + CAST(@cnt AS VARCHAR)
    PRINT 'Child element:  ' + CAST(@child AS VARCHAR(max))
    PRINT ''

    -- increment the counter variable
    SELECT @cnt = @cnt + 1
END

それが正しい手順かどうかはわかりませんが、少なくともうまくいくようです。次に実行したいのは、すべてのオプションをループしてそれらを出力する別の同様のスクリプトを実行することです。OPTIONごとに、QABLOCK番号、OPTION番号、OPTION値、およびOPTIONis_correctを出力する必要があります。近づくことすらできません。:(これが私がこれまでに得たものです:

-- XML instance
DECLARE    @x1 XML
SELECT @x1 = 
'
<tests>
    <test id="1">
        <qablock number="1">
            <question>What is 1 + 1?</question>
            <explanation>It"s 2.</explanation>
            <options>
                <option number="1" value="1" correct="0" />
                <option number="2" value="2" correct="1" />
                <option number="3" value="3" correct="0" />
                <option number="4" value="4" correct="0" />
                <option number="5" value="5" correct="0" />
            </options>
        </qablock>
        <qablock number="2">
            <question>What is 2 + 2?</question>
            <explanation>It"s 4.</explanation>
            <options>
                <option number="1" value="1" correct="0" />
                <option number="2" value="2" correct="0" />
                <option number="3" value="3" correct="0" />
                <option number="4" value="4" correct="1" />
                <option number="5" value="5" correct="0" />
            </options>
        </qablock>
    </test>
</tests>
'

DECLARE 
    @cnt INT, 
    @totCnt INT,
    @child XML

-- counter variables
SELECT 
    @cnt = 1,
    @totCnt = @x1.value('count(/tests/test/qablock/options/option)','INT')

-- loop
WHILE @cnt <= @totCnt BEGIN
    SELECT
        1 AS tests_id, --hard-coded value
        @x1.value('(/tests/test/qablock/@number)[1]','varchar(500)') AS qablock_number, 
        @x1.value('(/tests/test/qablock/options/option[position()=sql:variable("@cnt")]/@number)[1]','varchar(500)') AS option_number

    PRINT 'Processing Child Element: ' + CAST(@cnt AS VARCHAR)
    PRINT 'Child element:  ' + CAST(@child AS VARCHAR(max))
    PRINT ''

    -- increment the counter variable
    SELECT @cnt = @cnt + 1
END

それで、明らかにそれはめちゃくちゃです、しかし私は何を変えるべきか理解できないようです。

まず、現在のOPTIONの親QABLOCK番号を取得する方法がわかりません。

次に、最初の5つのoption_numberだけが正しく番号を表示し、次の5つはNULLを表示しています。

PSこのコードの一部は次のものからのものです:http: //beyondrelational.com/modules/2/blogs/28/posts/10316/xquery-lab-35-how-to-write-a-loop-to-process-all- the-child-elements-of-an-xml-value.aspx

4

1 に答える 1

1

これでうまくいくはずです:

-- XML instance
DECLARE    @x1 XML
SELECT @x1 = 
'
<tests>
    <test id="1">
        <qablock number="1">
            <question>What is 1 + 1?</question>
            <explanation>It"s 2.</explanation>
            <options>
                <option number="1" value="1" correct="0" />
                <option number="2" value="2" correct="1" />
                <option number="3" value="3" correct="0" />
                <option number="4" value="4" correct="0" />
                <option number="5" value="5" correct="0" />
            </options>
        </qablock>
        <qablock number="2">
            <question>What is 2 + 2?</question>
            <explanation>It"s 4.</explanation>
            <options>
                <option number="1" value="1" correct="0" />
                <option number="2" value="2" correct="0" />
                <option number="3" value="3" correct="0" />
                <option number="4" value="4" correct="1" />
                <option number="5" value="5" correct="0" />
            </options>
        </qablock>
    </test>
</tests>
'

declare @testCount int
, @testIndex int 
, @qaCount int
, @qaIndex int 
, @optCount int
, @optIndex int 

, @testId int
, @qaNo int
, @question nvarchar(500)
, @explanation nvarchar(500)
, @optNo int
, @optVal int
, @optCorrect bit


--for each test
set @testCount = @x1.value('count(/tests/test)','int')
set @testIndex = 1 
while @testIndex <= @testCount
begin

    --insert a record for this test
    set @testId = @x1.value('(/tests/test[sql:variable(''@testIndex'')]/@id)[1]','int')
    print 'insert into tests (id, ...) values (' + + cast(@testId as nvarchar(9)) + ')'
    print 'set @testIdDB = scope_identity()' --if we're using db generated ids rather than relying on the ids in the imported xml

    --for each qablock
    set @qaCount = @x1.value('count(/tests/test[sql:variable(''@testIndex'')]/qablock)','int')
    set @qaIndex = 1    
    while @qaIndex <= @qaCount
    begin   
        --insert a qa record
        select @qaNo = @x1.value('(/tests/test[sql:variable(''@testIndex'')]/qablock[sql:variable(''@qaIndex'')]/@number)[1]','int')
        , @question = @x1.value('(/tests/test[sql:variable(''@testIndex'')]/qablock[sql:variable(''@qaIndex'')]/question/text())[1]','nvarchar(500)')
        , @explanation = @x1.value('(/tests/test[sql:variable(''@testIndex'')]/qablock[sql:variable(''@qaIndex'')]/explanation/text())[1]','nvarchar(500)')
        print 'insert into qa (testId, qaNo, Question, Explanation) values (@testIdDB, ' + cast(@qaNo as nvarchar(9)) + ', ' + quotename(@question,'''') + ', ' + quotename(@explanation,'''') + ')'
        print 'set @qaIdDB = scope_identity()' 

        --for each option
        set @optCount = @x1.value('count(/tests/test[sql:variable(''@testIndex'')]/qablock[sql:variable(''@qaIndex'')]/options/option)','int')
        set @optIndex = 1   
        while @optIndex <= @optCount
        begin   
            --insert an option record
            select @optNo = @x1.value('(/tests/test[sql:variable(''@testIndex'')]/qablock[sql:variable(''@qaIndex'')]/options/option[sql:variable(''@optIndex'')]/@number)[1]','int') 
            , @optVal  = @x1.value('(/tests/test[sql:variable(''@testIndex'')]/qablock[sql:variable(''@qaIndex'')]/options/option[sql:variable(''@optIndex'')]/@value)[1]','int')
            , @optCorrect  = @x1.value('(/tests/test[sql:variable(''@testIndex'')]/qablock[sql:variable(''@qaIndex'')]/options/option[sql:variable(''@optIndex'')]/@correct)[1]','bit')
            print 'insert into tests (qaId, number, value, isCorrect) values (@qaIdDB, ' + cast(@optNo as nvarchar(9)) + ', ' + cast(@optVal as nvarchar(9)) + ', ' + cast(@optCorrect as nchar(1)) +  ')'

            set @optIndex = @optIndex + 1
        end
        set @qaIndex = @qaIndex + 1
    end
    set @testIndex = @testIndex + 1
end

またはさらに良い(私を促すためにあなたが提供したリンクに感謝します):

select x.value('@id','int') testId
FROM @x1.nodes('/tests/test') d(x)

select x.value('../@id','int') parentTestId
, x.value('@number','int') qaNumber
,  x.value('(question/text())[1]','nvarchar(500)') question
,  x.value('(explanation/text())[1]','nvarchar(500)') explanation
FROM @x1.nodes('/tests/test/qablock') d(x)

select x.value('../../@number','int') parentQaNumber
, x.value('@number','int') number
, x.value('@value','int') value
, x.value('@correct','bit') correct
FROM @x1.nodes('/tests/test/qablock/options/option') d(x)
于 2012-10-19T23:17:50.293 に答える