【问题标题】:Multi Record via XML to stored procedure通过 XML 到存储过程的多记录
【发布时间】:2016-07-28 14:37:21
【问题描述】:

我希望根据EventIDGROUP 标识的现有表列,将以下XML 作为字符串传递给SQL 和UPDATE 目标表行......

<Item>
    <GroupItem>
        <Group1>A</Group1>
        <Price>100</Price>
        <Location>Here</Location>
    </GroupItem>

    <GroupItem>
        <Group2>B</Group2>
        <Price>200</Price>
        <Location>There</Location>
    </GroupItem>

    <GroupItem>
        <Group3>C</Group3>
        <Price>300</Price>
        <Location>Everywhere</Location>
    </GroupItem>

    <EVENTID>12345</EVENTID>
    <MATCHED>100</MATCHED>
</Item>

因此,在此示例中,我想更新具有 12345 的EventID 的表行并为列提供值:GROUP1 = AGROUP2 = BGROUP3 = C....

任何帮助我(再次)解开我所处的混乱状态将不胜感激......

目标表结构如下:

CREATE TABLE [dbo].[GROUPTABLE](
[EventID] [int] NOT NULL,
[Group1A] [nvarchar](50) NULL,
[Group1B] [nvarchar](50) NULL,
[Group1C] [nvarchar](50) NULL,
[Group1D] [nvarchar](50) NULL,
[Group1_Location] [nvarchar](50) NULL,
[Group1_Matched] [float] NULL,
[Group2A] [nvarchar](50) NULL,
[Group2B] [nvarchar](50) NULL,
[Group2_Matched] [float] NULL,
[Group2_Location] [nvarchar](50) NULL,
[Group3A] [nvarchar](50) NULL,
[Group3B] [nvarchar](50) NULL,
[Group3_Matched] [float] NULL,
[Group3_Location] [nvarchar](50) NULL,
[Group4A] [nvarchar](50) NULL,
[Group4B] [nvarchar](50) NULL,
[Group4_Matched] [float] NULL,
[Group4_Location] [nvarchar](50) NULL,

CONSTRAINT [PK_GROUPTABLE] PRIMARY KEY CLUSTERED 
(
[EventID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

虽然这在概念上可能没有意义——这不是我在我的应用程序中使用的确切表格——(我不想放弃太多),但这种结构完全模仿了我在“真实”中尝试做的事情' 表....

【问题讨论】:

  • 请标记您使用的是哪个 SQL 引擎
  • Engine?.... 我正在使用带有 SQl 服务器的 vbnet .. 这就是你的意思....?
  • 此 XML 是否在您的控制之下?换句话说:你会被允许/能够改变这个结构吗?其次:您是否真的想要一个名为“Group1”的列,其值为“A”,“Group2”为“B”。与价格和位置无关? “匹配”呢?
  • 更改结构...不确定您的意思...数据库由我单独控制。这是一个供我使用的应用程序...我希望将带有标签的 Group1 列设置为通过 XML 传入的任何值...对于 Group2 等也是如此,是的,价格和位置也是如此。我想如果有人回应仅对 Group 而言,我可以简单地复制 Price 、 location 等的代码。
  • 'Matched' 也需要根据通过 XML 传入的值进行更新 - 由 EventID 表行确定..

标签: sql sql-server xml stored-procedures sql-update


【解决方案1】:

更新2

只需将整个代码块复制到一个空的查询窗口中并尝试一下...

/*
This is your mimic table
Btw: It is - in almost all cases! - a very bad idea to store related data in a table like data1, data2, data3...
If possible you should introduce a table GroupValues with a foreign key onto group table
*/
CREATE TABLE [dbo].[GROUPTABLE](
[EventID] [int] NOT NULL,
[Group1A] [nvarchar](50) NULL,
[Group1B] [nvarchar](50) NULL,
[Group1_Matched] [float] NULL,
[Group1_Location] [nvarchar](50) NULL,
[Group2A] [nvarchar](50) NULL,
[Group2B] [nvarchar](50) NULL,
[Group2_Matched] [float] NULL,
[Group2_Location] [nvarchar](50) NULL,
[Group3A] [nvarchar](50) NULL,
[Group3B] [nvarchar](50) NULL,
[Group3_Matched] [float] NULL,
[Group3_Location] [nvarchar](50) NULL,
[Group4A] [nvarchar](50) NULL,
[Group4B] [nvarchar](50) NULL,
[Group4_Matched] [float] NULL,
[Group4_Location] [nvarchar](50) NULL,

CONSTRAINT [PK_GROUPTABLE] PRIMARY KEY CLUSTERED 
(
[EventID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY];

--here I insert two dummy rows
INSERT INTO GROUPTABLE VALUES
 (1,   'Gr1A','Gr1B',111,'Gr1Location'
      ,'Gr2A','Gr2B',222,'Gr2Location'
      ,'Gr3A','Gr3B',333,'Gr3Location'
      ,'Gr4A','Gr4B',444,'Gr4Location'
      )
,(12345,'Gr1A','Gr1B',111,'Gr1Location'
       ,'Gr2A','Gr2B',222,'Gr2Location'
       ,'Gr3A','Gr3B',333,'Gr3Location'
       ,'Gr4A','Gr4B',444,'Gr4Location'
      );

--one test to show the data
SELECT * FROM dbo.GROUPTABLE;

--Here's your XML
DECLARE @XML XML=
'<Item>
    <GroupItem>
        <Group1>A</Group1>
        <Price>100</Price>
        <Location>Here</Location>
    </GroupItem>

    <GroupItem>
        <Group2>B</Group2>
        <Price>200</Price>
        <Location>There</Location>
    </GroupItem>

    <GroupItem>
        <Group3>C</Group3>
        <Price>300</Price>
        <Location>Everywhere</Location>
    </GroupItem>

    <EVENTID>12345</EVENTID>
    <MATCHED>100</MATCHED>
</Item>';

/*
And this is the UPDATE
If necessary you might use .query() to get the nodes and save repeated XPath-navigation
Anyway: Much better was a 
<Item>
    <GroupItem group="A">
        <Group>A</Group>
        <Price>100</Price>
        ...
    <GroupItem group="B">
        <Group>A</Group>
        <Price>100</Price>
        ...
to avoid differint element names
*/

UPDATE dbo.GROUPTABLE
SET Group1A         = @XML.value('(/Item/GroupItem/*[local-name(.)="Group1"])[1]','varchar(max)')
   ,Group2A         = @XML.value('(/Item/GroupItem/*[local-name(.)="Group2"])[1]','varchar(max)')
   ,Group3A         = @XML.value('(/Item/GroupItem/*[local-name(.)="Group3"])[1]','varchar(max)')
   ,Group4A         = @XML.value('(/Item/GroupItem/*[local-name(.)="Group4"])[1]','varchar(max)')

   ,Group1B         = @XML.value('(/Item/GroupItem/*[local-name(.)="Group1"]/../Price)[1]','varchar(max)')
   ,Group2B         = @XML.value('(/Item/GroupItem/*[local-name(.)="Group2"]/../Price)[1]','varchar(max)')
   ,Group3B         = @XML.value('(/Item/GroupItem/*[local-name(.)="Group3"]/../Price)[1]','varchar(max)')
   ,Group4B         = @XML.value('(/Item/GroupItem/*[local-name(.)="Group4"]/../Price)[1]','varchar(max)')

   ,Group1_Matched  = @XML.value('(/Item/MATCHED)[1]','float')
   ,Group2_Matched  = @XML.value('(/Item/MATCHED)[1]','float')
   ,Group3_Matched  = @XML.value('(/Item/MATCHED)[1]','float')
   ,Group4_Matched  = @XML.value('(/Item/MATCHED)[1]','float')

   ,Group1_Location = @XML.value('(/Item/GroupItem/*[local-name(.)="Group1"]/../Location)[1]','varchar(max)')
   ,Group2_Location = @XML.value('(/Item/GroupItem/*[local-name(.)="Group2"]/../Location)[1]','varchar(max)')
   ,Group3_Location = @XML.value('(/Item/GroupItem/*[local-name(.)="Group3"]/../Location)[1]','varchar(max)')
   ,Group4_Location = @XML.value('(/Item/GroupItem/*[local-name(.)="Group4"]/../Location)[1]','varchar(max)')

WHERE EventID=@XML.value('(/Item/EVENTID)[1]','int');

--Here you see, that the item' value changed for EventID=12345
SELECT * FROM dbo.GROUPTABLE;

--Clean Up
--DROP TABLE dbo.GROUPTABLE

更新

通过此查询,您可以一次性获取所有数据

SELECT @XML.value('(/Item/EVENTID)[1]','int') AS EventId
      ,@XML.value('(/Item/MATCHED)[1]','int') AS Matched
      ,A.B.value('local-name(*[position()=1][1])','varchar(max)') AS GroupName
      ,A.B.value('*[position()=1][1]','varchar(max)') AS FirstNode
      ,A.B.value('Price[1]','decimal(12,4)') AS Price
      ,A.B.value('Location[1]','varchar(max)') AS Location
FROM @XML.nodes('/Item/GroupItem') AS A(B)  

结果

12345   100 Group1  A   100.0000    Here
12345   100 Group2  B   200.0000    There
12345   100 Group3  C   300.0000    Everywhere

上一页

实际上,我怀疑您给出的描述是否真的是您想要的:-),但这是实现我所理解的一种方法:

DECLARE @XML XML=
'<Item>
    <GroupItem>
        <Group1>A</Group1>
        <Price>100</Price>
        <Location>Here</Location>
    </GroupItem>

    <GroupItem>
        <Group2>B</Group2>
        <Price>200</Price>
        <Location>There</Location>
    </GroupItem>

    <GroupItem>
        <Group3>C</Group3>
        <Price>300</Price>
        <Location>Everywhere</Location>
    </GroupItem>

    <EVENTID>12345</EVENTID>
    <MATCHED>100</MATCHED>
</Item>';

声明一个表变量来填充测试数据

DECLARE @tbl TABLE(ID INT,Group1 VARCHAR(10),Group2 VARCHAR(10),Group3 VARCHAR(10));
INSERT INTO @tbl VALUES
 (3456,'Test1','Test2','Test3')
,(12345,'Test1','Test2','Test3');

SELECT * FROM @tbl;

结果

3456    Test1   Test2   Test3
12345   Test1   Test2   Test3

更改 ID=12345 的行

UPDATE @tbl SET Group1 = @XML.value('(/Item/GroupItem/*[local-name(.)="Group1"])[1]','varchar(max)')
               ,Group2 = @XML.value('(/Item/GroupItem/*[local-name(.)="Group2"])[1]','varchar(max)')
               ,Group3 = @XML.value('(/Item/GroupItem/*[local-name(.)="Group3"])[1]','varchar(max)')
WHERE ID=@XML.value('(/Item/EVENTID)[1]','int');

结果

SELECT * FROM @tbl;

3456    Test1   Test2   Test3
12345   A       B       C

【讨论】:

  • 哇——真快!
  • Shungo - 有了这个我可以向前迈出一大步,再次感谢你。
  • @user6167266,很高兴看到这个!我刚刚添加了一个查询,可以一次性获取所有数据。您可以使用SELECT col1,col2, ... INTO #tempTable FROM ... 指定INTO #tempTable 会将数据放入表中。从那里您可以使用JOIN 进行多行更新。或者将查询放入CTE...
  • @user6167266 可以改进结构的一件事是让元素的名称相同,像这样&lt;GroupItem id="1"&gt;&lt;GroupValue&gt;A&lt;/GroupValue&gt;&lt;Price&gt;... 携带相同信息的元素应该被称为相同。信息,即“第 2 组”或“第 1 组”最好作为元数据属性放置在父节点中......
  • @user6167266 和一条自私的评论:由于您刚刚超过了 15 个声誉点(在我这边稍加推动),如果您喜欢我的回答,请点击支持。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-06
  • 1970-01-01
  • 1970-01-01
  • 2019-08-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多