I'm using SQL Server 2012 to import a simple XML document. Here's a sample of what the XML looks like:
<Orders>
    <Order>
        <Customer>Bob Smith</Customer>
        <Address>123 Main St, Anytown, NY</Address>
        <OrderItems>
            <Item>
                <ItemName>Table</ItemName>
                <Quantity>1</Quantity>
            </Item>
            <Item>
                <ItemName>Chair</ItemName>
                <Quantity>4</Quantity>
            </Item>
        </OrderItems>
    </Order>
    <Order>
        <Customer>Jane Doe</Customer>
        <Address>456 Broadway Ave, Someplace, TX</Address>
        <OrderItems>
            <Item>
                <ItemName>Banana Slicer</ItemName>
                <Quantity>1</Quantity>
            </Item>
        </OrderItems>
    </Order>
    <Order>
        <Customer>Joe Public</Customer>
        <Address>789 Euclid Rd, Random, ID</Address>
        <OrderItems>
            <Item>
                <ItemName>Hammer</ItemName>
                <Quantity>1</Quantity>
            </Item>
            <Item>
                <ItemName>Nails</ItemName>
                <Quantity>50</Quantity>
            </Item>
            <Item>
                <ItemName>Chisel</ItemName>
                <Quantity>2</Quantity>
            </Item>
        </OrderItems>
    </Order>
</Orders>
Note that each order can have one or more items in it.
Here are the destination tables (using temp tables for now):
CREATE TABLE dbo.#Order
(
    [OrderID] int IDENTITY(1001,1) PRIMARY KEY,
    [Customer] varchar(200) NOT NULL,
    [Address] varchar(200) NOT null
);
CREATE TABLE dbo.#OrderItem
(
    [OrderItemID] int IDENTITY(5001,1) PRIMARY KEY,
    [OrderID] int
        FOREIGN KEY REFERENCES dbo.#Order(OrderID)
        ON DELETE CASCADE,
    [ItemName] varchar(100) NOT NULL,
    [Quantity] int NOT NULL
);
The above should be imported as follows:
OrderID     Customer    Address
-------     --------    -------
1001        Bob Smith   123 Main St, Anytown, NY
1002        Jane Doe    456 Broadway Ave, Someplace, TX
1003        Joe Public  789 Euclid Rd, Random, ID
OrderItemID OrderID ItemName        Quantity
----------- ------- --------        --------
5001        1001    Table           1
5002        1001    Chair           4
5003        1002    Banana Slicer   1
5004        1003    Hammer          1
5005        1003    Nails           50
5006        1003    Chisel          2
Is there a way to insert all the data into both the Order and the OrderItem tables without using a cursor? I'm not against using a cursor for this, but I would like to know if there is a simpler, set-based alternative. The tricky part is that OrderItem needs to know about the inserted OrderID of each order that was imported.
Here's my initial attempt at importing the data (using a cursor). I'm using temp tables (instead of permnanent tables) and hardcoding the XML to make it easier to just copy and run this code:
-------------------------------------------------------------------------------
-- Create Temp Tables
-------------------------------------------------------------------------------
IF OBJECT_ID('tempdb.dbo.#OrderItem') IS NOT NULL
    DROP TABLE #OrderItem
GO
IF OBJECT_ID('tempdb.dbo.#Order') IS NOT NULL
    DROP TABLE #Order
GO
CREATE TABLE dbo.#Order
(
    [OrderID] int IDENTITY(1001,1) PRIMARY KEY,
    [Customer] varchar(200) NOT NULL,
    [Address] varchar(200) NOT null
);
CREATE TABLE dbo.#OrderItem
(
    [OrderItemID] int IDENTITY(5001,1) PRIMARY KEY,
    [OrderID] int
        FOREIGN KEY REFERENCES dbo.#Order(OrderID)
        ON DELETE CASCADE,
    [ItemName] varchar(100) NOT NULL,
    [Quantity] int NOT NULL
);
-------------------------------------------------------------------------------
-- Define Sample XML Document
-------------------------------------------------------------------------------
DECLARE @xml xml = '
    <Orders>
        <Order>
            <Customer>Bob Smith</Customer>
            <Address>123 Main St, Anytown, NY</Address>
            <OrderItems>
                <Item>
                    <ItemName>Table</ItemName>
                    <Quantity>1</Quantity>
                </Item>
                <Item>
                    <ItemName>Chair</ItemName>
                    <Quantity>4</Quantity>
                </Item>
            </OrderItems>
        </Order>
        <Order>
            <Customer>Jane Doe</Customer>
            <Address>456 Broadway Ave, Someplace, TX</Address>
            <OrderItems>
                <Item>
                    <ItemName>Banana Slicer</ItemName>
                    <Quantity>1</Quantity>
                </Item>
            </OrderItems>
        </Order>
        <Order>
            <Customer>Joe Public</Customer>
            <Address>789 Euclid Rd, Random, ID</Address>
            <OrderItems>
                <Item>
                    <ItemName>Hammer</ItemName>
                    <Quantity>1</Quantity>
                </Item>
                <Item>
                    <ItemName>Nails</ItemName>
                    <Quantity>50</Quantity>
                </Item>
                <Item>
                    <ItemName>Chisel</ItemName>
                    <Quantity>2</Quantity>
                </Item>
            </OrderItems>
        </Order>
    </Orders>';
-------------------------------------------------------------------------------
-- Query XML Document
-------------------------------------------------------------------------------
--SELECT
--  Tbl.Col.value('Customer[1]', 'varchar(200)') AS [Customer],
--  Tbl.Col.value('Address[1]', 'varchar(200)') AS [Address],
--  Tbl.Col.query('./OrderItems/Item') AS [ItemsXML]
--FROM
--  @xml.nodes('//Order') AS Tbl(Col)
-------------------------------------------------------------------------------
-- Import XML document (Attempt 1 - using a cursor)
-------------------------------------------------------------------------------
DECLARE @OrderNode xml;
DECLARE @OrderID int;
DECLARE cur CURSOR FAST_FORWARD READ_ONLY LOCAL FOR
    SELECT Tbl.Col.query('.') FROM @xml.nodes('//Order') AS Tbl(Col)
OPEN cur
FETCH NEXT FROM cur INTO @OrderNode
WHILE @@FETCH_STATUS = 0 BEGIN
    ------------------------------------------
    -- Import order
    ------------------------------------------
    INSERT INTO #Order
    (
        [Customer],
        [Address]
    )
    SELECT
        Tbl.Col.value('Customer[1]', 'varchar(200)'),
        Tbl.Col.value('Address[1]', 'varchar(200)')
    FROM @OrderNode.nodes('Order') AS Tbl(Col);
    ------------------------------------------
    -- Get the inserted order ID
    ------------------------------------------
    SELECT @OrderID = SCOPE_IDENTITY();
    ------------------------------------------
    -- Import order items
    ------------------------------------------
    INSERT INTO #OrderItem
    (
        OrderID,
        ItemName,
        Quantity
    )
    SELECT
        @OrderID,
        Tbl.Col.value('ItemName[1]', 'varchar(100)'),
        Tbl.Col.value('Quantity[1]', 'int')
    FROM @OrderNode.nodes('Order/OrderItems/Item') AS Tbl(Col);
    -------------------------------------------------------------------------------
    -- Move on to next order
    -------------------------------------------------------------------------------
    FETCH NEXT FROM cur INTO @OrderNode
END
CLOSE cur
DEALLOCATE cur
-------------------------------------------------------------------------------
-- Show results
-------------------------------------------------------------------------------
SELECT * FROM #Order
SELECT * FROM #OrderItem