0

I'm trying to insert some XML data from a XML column into a temp table in SQL Server 2012.

This is my current query

DECLARE @XML AS XML, @hDoc AS INT, @SQL NVARCHAR (MAX)

IF OBJECT_ID('tempdb..dbo.#txn','u') IS NOT NULL
BEGIN
    PRINT '#temp exists! drop table'
    DROP TABLE tempdb.dbo.#txn;
END
ELSE
BEGIN
    PRINT '#temp does not exist! create table'

    CREATE TABLE #txn
    (
        accountcode varchar(100),
        tienda varchar(100),
        caja varchar(100),
        cajero varchar(100),
        fecha varchar(100),
        transaccion varchar(100),
        itemcode varchar(100),
        description varchar(100),
        quantity numeric(10,3),
        weight numeric(10,3),
        qty_weight numeric(10,3),
        unitprice numeric(15,3),
        totalprice numeric(15,3),
        vatcode varchar(100),
        hashcode varchar(100),
        anulado varchar(100)    
    )
END

SELECT @XML = [LoadedXML] FROM [dbo].[XmlImport]

EXEC sp_xml_preparedocument @hDoc OUTPUT, @XML

INSERT INTO #txn (accountcode, tienda, caja, cajero, fecha, transaccion, itemcode, description, quantity, weight, qty_weight, unitprice, totalprice, vatcode, hashcode, anulado)

    SELECT 
        CASE
            WHEN codigotienda = 1 THEN '01'
        END as accountcode,
        tienda,
        caja,
        cajero,
        fecha,
        transaccion,
        itemcode,
        description,
        quantity,
        weight,
        CASE
            WHEN quantity IS NULL THEN weight
            WHEN weight IS NULL THEN quantity
        END as qty_weight,
        unitprice,
        totalprice,
        CASE
            WHEN vatcode = 4 THEN 'V0'
            WHEN vatcode = 1 THEN 'V1'
            WHEN vatcode = 2 THEN 'V2'
            WHEN vatcode = 3 THEN 'V3'
            WHEN vatcode is NULL THEN 'V0'
        END AS vatcode,
        hashcode,
        anulado
    FROM 
        OPENXML(@hDoc, 'tcpos-export/transactions/transaction/trans-item') 
    WITH 
        (
            codigotienda [varchar](100) '../shop/code',
            tienda [varchar](100) '../shop/description',
            caja [varchar](100) '../till/code',
            cajero [varchar](100) '../cashier/code',
            fecha [varchar](100) '../beginning-timestamp',
            transaccion [varchar](100) '../trans-num',
            itemcode [varchar](100) 'code',
            description [varchar](100) 'description',
            quantity numeric(10,3) 'quantity',
            weight numeric(10,3) 'weight',
            unitprice numeric(15,3) 'unit-price',
            totalprice numeric(15,3) 'taxable-amount',
            vatcode [varchar](100) 'vat-code',
            hashcode [varchar](100) 'hash-code',
            anulado [varchar](100) 'delete-operator-id'
         )

SELECT * 
FROM #txn
WHERE hashcode IS NOT NULL
  AND totalprice NOT LIKE '%-%'
  AND unitprice NOT LIKE '%-%'
  AND anulado IS NULL
ORDER BY 
  CAST(hashcode AS int)

--LEFT JOIN [MAXIMERCADODEMO].[dbo].OITM sap

--ON #txn.itemcode = sap.itemcode COLLATE SQL_Latin1_General_CP1_CI_AS

--where #txn.itemcode is null

--SELECT #txn.itemcode FROM #txn

--LEFT JOIN [MAXIMERCADODEMO].[dbo].OITM sap

--ON #txn.itemcode = sap.itemcode COLLATE SQL_Latin1_General_CP1_CI_AS

--where #txn.itemcode is null

EXEC sp_xml_removedocument @hDoc

This works the first time. When I run it a second time, it should drop the temp table, but I get this error instead:

#temp does not exist! create table

Msg 2714, Level 16, State 6, Line 11
There is already an object named '#txn' in the database.

I don't know if you guys recommend me using a temp table or create a real table in my database to manage this situation?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
alexistkd
  • 906
  • 2
  • 14
  • 34
  • 1
    You need to separate _batches_, e.g. by using the [`go`](https://learn.microsoft.com/en-us/sql/t-sql/language-elements/sql-server-utilities-statements-go?view=sql-server-ver15) SQL Server Utilities statement, when you are creating tables on-the-fly. – HABO Aug 31 '21 at 17:01
  • 2
    Too many dots in `IF OBJECT_ID('tempdb..dbo.#txn','u') IS NOT NULL`, it's either `tempdb..#txn` or `tempdb.dbo.#txn`, not both. – RBarryYoung Aug 31 '21 at 17:08
  • i made that change IF OBJECT_ID('tempdb..#txn','u') IS NOT NULL but still #temp exists! drop table Msg 208, Level 16, State 0, Line 23 Invalid object name '#txn'. – alexistkd Aug 31 '21 at 17:10
  • 1
    Yes, this is a typo, also the bulk of your question could just be 12 lines or so, the rest of the code has zero bearing on your typo. If you moved to a *supported* version of SQL Server, you could really simplify with `DROP TABLE IF EXISTS #txn;`. – Aaron Bertrand Aug 31 '21 at 17:10
  • @HABO where should i put those GO ? – alexistkd Aug 31 '21 at 17:10
  • 1
    You don't need an `ELSE` at all. `IF EXISTS ... BEGIN ... DROP ... END ... GO ... CREATE` - the create doesn't have to be part of the conditional. – Aaron Bertrand Aug 31 '21 at 17:11
  • @AaronBertrand what you mean a supported sql ? newer version? – alexistkd Aug 31 '21 at 17:22
  • 1
    Yes, SQL Server 2012 is [no longer supported](https://learn.microsoft.com/en-us/lifecycle/products/microsoft-sql-server-2012) unless you pay for extended support. Time to think about a more modern version (plenty of benefits that don't involve support). – Aaron Bertrand Aug 31 '21 at 17:27

2 Answers2

2

This

 IF OBJECT_ID('tempdb..#txn','u') IS NOT NULL

Should be

 IF OBJECT_ID('tempdb..#txn', 'u') IS NOT NULL DROP TABLE #txn;

You could even get away with just:

 IF OBJECT_ID('tempdb..#txn') IS NOT NULL

Once you make this change you no longer need the big IF statement checking for this.

Doug Coats
  • 6,255
  • 9
  • 27
  • 49
1

Do yourself a favour and don't use that ancient XML procedure OPENXML. Instead use .nodes and .value

You can even use XQuery predicates instead of the WHERE clause

SELECT CASE
        WHEN trans.value('(shop/code/text())[1]','varchar(100)') = '1' THEN '01'
        END as accountcode,
        trans.value('(shop/description/text())[1]','varchar(100)') tienda,
        trans.value('(till/code/text())[1]','varchar(100)') caja,
        trans.value('(cashier/code/text())[1]','varchar(100)') cajero,
        trans.value('(beginning-timestamp/text())[1]','varchar(100)') fecha,
        trans.value('(trans-num/text())[1]','varchar(100)') transaccion,
        item.value('(code/text())[1]','varchar(100)') itemcode,
        item.value('(description/text())[1]','varchar(100)') description,
        v.quantity,
        v.weight,
        CASE
            WHEN v.quantity is null THEN v.weight
            WHEN v.weight is null THEN v.quantity
        END as qty_weight,
        item.value('(unit-price/text())[1]','numeric(15,3)') unitprice,
        item.value('(taxable-amount/text())[1]','numeric(15,3)') totalprice,
        CASE
            WHEN vatcode = '4' THEN 'V0'
            WHEN vatcode = '1' THEN 'V1'
            WHEN vatcode = '2' THEN 'V2'
            WHEN vatcode = '3' THEN 'V3'
            WHEN vatcode is NULL THEN 'V0'
        END AS vatcode,
        item.value('(hash-code/text())[1]','int') hashcode,
        item.value('(delete-operator-id/text())[1]','varchar(100)') anulado

FROM [dbo].[XmlImport] xi
CROSS APPLY xi.[LoadedXML].nodes('tcpos-export/transactions/transaction') x1(trans)
CROSS APPLY x1.trans.nodes('trans-item[
    hash-code/text() and
    not( unit-price[contains(text()[1], "-")] ) and
    not( taxable-amount[contains(text()[1], "-")] ) and
    not( delete-operator-id/text() )
]') x2(item)
CROSS APPLY (VALUES (
    item.value('(quantity/text())[1]','numeric(10,3)'),
    item.value('(weight/text())[1]','numeric(10,3)'),
    item.value('(vat-code/text())[1]','varchar(100)')
) ) v(quantity, weight, vatcode)

ORDER BY hashcode;
Charlieface
  • 52,284
  • 6
  • 19
  • 43
  • very good, but why i should use like that? i know openxml is old but what are the advantages of this new query vs openxml? – alexistkd Sep 01 '21 at 02:58
  • 1
    No need for `sp_xml_preparedocument` or temp tables, it's also far more flexible with XQuery. See also https://stackoverflow.com/questions/44429246/what-is-the-different-between-using-sp-xml-preparedocument-and-selecting-from-xm – Charlieface Sep 01 '21 at 03:16
  • thank you so much, it helps me alot. you right its more flexible just like a regular query – alexistkd Sep 01 '21 at 03:23
  • something i saw with that xquery its slower? – alexistkd Sep 01 '21 at 03:27
  • so you dont recommend using temp tables? i can use that xquery and save it to a temp table for future reading no? – alexistkd Sep 01 '21 at 03:42
  • 1
    You could, but why bother when it can be done in one query? Inserting and then reading from temp tables is going to be slower. The only times you need temp tables is when either you need to update/insert multiple other tables from this, or the processing is so complex that it makes sense to store a temporary intermediate snapshot of the data. I don't think XQuery is slower than `OPENXML`, if anything it's probably faster. – Charlieface Sep 01 '21 at 09:12
  • yes i think will need temp table. As i need to read the data and then update another table like the header table with fields like: status, date, processed yes or no. etc. – alexistkd Sep 01 '21 at 13:20
  • you think is not necessary in my case to use temptable? i can use the original query and pass that data to update another table? – alexistkd Sep 01 '21 at 13:23
  • 1
    Go ahead, use a temp table, but use `.nodes` to select the data to insert, like this `insert #tmp (....) select ..... from xml.nodes(....` – Charlieface Sep 01 '21 at 13:31
  • 1
    Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/236650/discussion-between-charlieface-and-alexistkd). – Charlieface Sep 01 '21 at 13:32