【问题标题】:Issue inserting into a temp table in SQL Server 2012在 SQL Server 2012 中插入临时表时出现问题
【发布时间】:2021-08-31 16:48:54
【问题描述】:

我正在尝试将 XML 列中的一些 XML 数据插入到 SQL Server 2012 中的临时表中。

这是我当前的查询

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

这是第一次。当我第二次运行它时,它应该删除临时表,但我得到了这个错误:

#temp 不存在!创建表

消息 2714,第 16 级,状态 6,第 11 行
数据库中已经有一个名为“#txn”的对象。

我不知道你们是否建议我使用临时表或在我的数据库中创建一个真实表来管理这种情况?

【问题讨论】:

  • 您需要分开批次,例如在动态创建表时使用go SQL Server Utilities 语句。
  • IF OBJECT_ID('tempdb..dbo.#txn','u') IS NOT NULL 中的点太多,要么是 tempdb..#txn 要么是 tempdb.dbo.#txn,而不是两者。
  • 是的,这是一个错字,您的大部分问题也可能只有 12 行左右,其余代码对您的错字零影响。如果您迁移到支持版本的 SQL Server,您可以使用DROP TABLE IF EXISTS #txn; 进行真正的简化。
  • 您根本不需要ELSEIF EXISTS ... BEGIN ... DROP ... END ... GO ... CREATE - 创建不一定是条件的一部分。
  • 是的,SQL Server 2012 是no longer supported,除非您为扩展支持付费。是时候考虑一​​个更现代的版本了(很多不涉及支持的好处)。

标签: sql-server tsql


【解决方案1】:

这个

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

应该是

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

你甚至可以侥幸逃脱:

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

一旦你做出这个改变,你就不再需要大的 IF 语句来检查这个了。

【讨论】:

    【解决方案2】:

    帮自己一个忙,不要使用那个古老的 XML 过程 OPENXML 而是使用 .nodes.value

    您甚至可以使用 XQuery 谓词代替 WHERE 子句

    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;
    

    【讨论】:

    • 很好,但我为什么要那样使用?我知道 openxml 很旧,但是这个新查询与 openxml 相比有什么优势?
    • 不需要sp_xml_preparedocument 或临时表,XQuery 也更加灵活。另见stackoverflow.com/questions/44429246/…
    • 你可以,但是当它可以在一个查询中完成时,为什么还要麻烦呢?插入然后从临时表中读取会更慢。您需要临时表的唯一情况是您需要从中更新/插入多个其他表,或者处理非常复杂以至于存储数据的临时中间快照是有意义的。我不认为 XQuery 比 OPENXML 慢,如果有的话它可能更快。
    • 继续,使用临时表,但使用.nodes 选择要插入的数据,像这样insert #tmp (....) select ..... from xml.nodes(....
    猜你喜欢
    • 2011-08-31
    • 1970-01-01
    • 1970-01-01
    • 2013-06-02
    • 2011-06-12
    • 2015-11-26
    • 2011-02-05
    • 2011-08-21
    • 1970-01-01
    相关资源
    最近更新 更多