几个问题插入和过滤 XML 数据到 SQL
Few issues Inserting and filtering XML data to SQL
我在将数据从 XML 文件插入到 SQL 服务器数据库时遇到了一些问题。
如何动态获取文件名?该文件每次都以不同的编号放在该路径上,但始终以 Idoc 开头,并且它是一个 .xml 文件。我在 OPENROWSET
.
中设置变量时遇到问题
目前我只从一条路径 (ZPROD) 获取数据,但我希望能够从 EDI_DC40/DOCNUM 而不是 ZPROD/PLN_ORDER 插入数据,我会需要另一个 CROSS APPLY,但我无法让它工作。
我想忽略 QTY 中的 .000,我尝试将其设置为 int 但没有用,“无法转换为 int”。
有没有什么办法可以忽略LINENO的大部分,只获取最后两个字符?它设置为 varchar(2) 但显然是前两个字符,而不是最后一个。
下面是我的代码,希望一切都在规则之内并且可以理解:
谢谢。
<?xml version="1.0" encoding="UTF-8" ?>
<ZMPROD01>
<IDOC BEGIN="1">
<EDI_DC40 SEGMENT="1">
<TABNAM>EDI_DC40</TABNAM>
<DOCNUM>0000003899888135</DOCNUM>
<CREDAT>20220201</CREDAT>
<CRETIM>152041</CRETIM>
</EDI_DC40>
<ZPROD SEGMENT="1">
<WERKS>8285</WERKS>
<LGNUM>0</LGNUM>
<AUFNR>000915229446</AUFNR>
<LINENO>RM01PL01</LINENO>
<CHARG>0006186588</CHARG>
<START1>20220202</START1>
<START2>211609</START2>
<QTY>4166.000</QTY>
<END1>20220202</END1>
<END2>240000</END2>
<MAKTX>579 FUS5 75ML ULTRA SENST GEL</MAKTX>
<PLN_ORDER>6963701111</PLN_ORDER>
<Z1PRODI SEGMENT="1">
<POSNR>000010</POSNR>
<MATNR>000000000098920665</MATNR>
</Z1PRODI>
<Z1PRODI SEGMENT="1">
<POSNR>000040</POSNR>
<HRKFT>V010</HRKFT>
</Z1PRODI>
<Z1PRODI SEGMENT="1">
<POSNR>000050</POSNR>
<MATNR>000000000099396964</MATNR>
</Z1PRODI>
</ZPROD>
</IDOC>
</ZMPROD01>
CREATE TABLE XMLTESTTABLE
(
PONo int,
ASP int,
LOTNo varchar(11),
EntryDate date,
StartDate date,
EndDate date,
GAS int,
PlannedQty varchar(15),
LineNum varchar(2),
SAPDesc varchar(200),
StartTime date,
EndTime date
);
INSERT INTO XMLTESTTABLE(PONo, ASP, LOTNo, EntryDate, StartDate, EndDate, GAS, PlannedQty, LineNum, SAPDesc, StartTime, EndTime)
SELECT
MY_XML.ZPROD.query('AUFNR').value('.', 'VARCHAR(9)'),
MY_XML.ZPROD.query('CHARG').value('.', 'VARCHAR(8)'),
MY_XML.ZPROD.query('PLN_ORDER').value('.', 'VARCHAR(10)'),
MY_XML.ZPROD.query('START1').value('.', 'date'),
MY_XML.ZPROD.query('START1').value('.', 'date'),
MY_XML.ZPROD.query('END1').value('.', 'date'),
MY_XML.ZPROD.query('CHARG').value('.', 'VARCHAR(8)'),
MY_XML.ZPROD.query('QTY').value('.', 'VARCHAR(9)'),
MY_XML.ZPROD.query('LINENO').value('.', 'VARCHAR(2)'),
MY_XML.ZPROD.query('MAKTX').value('.', 'VARCHAR(200)'),
MY_XML.ZPROD.query('START2').value('.', 'time'),
MY_XML.ZPROD.query('END2').value('.', 'time')
FROM (SELECT CAST(MY_XML AS xml)
FROM OPENROWSET(BULK 'C:\Users\PC_user\Documents\Idoc3899888135.xml', SINGLE_BLOB) AS T(MY_XML)) AS T(MY_XML)
CROSS APPLY MY_XML.nodes('ZMPROD01/ZPROD') AS MY_XML (ZPROD);
请尝试以下解决方案。
- 无需使用
.query()
方法。
- ##3,4 已解决。
- 我冒昧地将无效的 240000 次处理为 23:59:59。
- 最后两列的数据类型是
time(0)
。
SQL
USE tempdb;
GO
DROP TABLE IF EXISTS XMLTESTTABLE;
CREATE TABLE XMLTESTTABLE (
PONo INT,
ASP int,
LOTNo varchar(11),
EntryDate date,
StartDate date,
EndDate date,
GAS int,
PlannedQty varchar(15),
LineNum varchar(2),
SAPDesc varchar(200),
StartTime time(0),
EndTime time(0)
);
INSERT INTO XMLTESTTABLE(PONo, ASP, LOTNo, EntryDate, StartDate, EndDate, GAS, PlannedQty, LineNum, SAPDesc, StartTime, EndTime)
SELECT ZPROD.value('(AUFNR/text())[1]', 'VARCHAR(9)')
, ZPROD.value('(CHARG/text())[1]', 'VARCHAR(8)')
, ZPROD.value('(PLN_ORDER/text())[1]', 'VARCHAR(10)')
, ZPROD.value('(START1/text())[1]', 'date')
, ZPROD.value('(START1/text())[1]', 'date')
, ZPROD.value('(END1/text())[1]', 'date')
, ZPROD.value('(CHARG/text())[1]', 'VARCHAR(8)')
, ZPROD.value('(QTY/text())[1]', 'DECIMAL(10,0)') AS [qty]
, RIGHT(ZPROD.value('(LINENO/text())[1]', 'VARCHAR(10)'), 2) AS [lineno]
, ZPROD.value('(MAKTX/text())[1]', 'VARCHAR(200)') AS MAKTX
, TRY_CAST(STUFF(STUFF(ZPROD.value('(START2/text())[1]', 'CHAR(6)'),3,0,':'),6,0,':') AS TIME)
, TRY_CAST(IIF(STUFF(STUFF(ZPROD.value('(END2/text())[1]', 'CHAR(6)'),3,0,':'),6,0,':')='24:00:00'
,'23:59:59',null) AS TIME)
FROM (SELECT TRY_CAST(MY_XML AS xml)
FROM OPENROWSET(BULK 'e:\Temp\Idoc3899888135.xml', SINGLE_BLOB) AS T(MY_XML)) AS T(MY_XML)
CROSS APPLY MY_XML.nodes('/ZMPROD01/IDOC/ZPROD') AS MY_XML(ZPROD);
-- test
SELECT * FROM dbo.XMLTESTTABLE;
我在将数据从 XML 文件插入到 SQL 服务器数据库时遇到了一些问题。
如何动态获取文件名?该文件每次都以不同的编号放在该路径上,但始终以 Idoc 开头,并且它是一个 .xml 文件。我在
中设置变量时遇到问题OPENROWSET
.目前我只从一条路径 (ZPROD) 获取数据,但我希望能够从 EDI_DC40/DOCNUM 而不是 ZPROD/PLN_ORDER 插入数据,我会需要另一个 CROSS APPLY,但我无法让它工作。
我想忽略 QTY 中的 .000,我尝试将其设置为 int 但没有用,“无法转换为 int”。
有没有什么办法可以忽略LINENO的大部分,只获取最后两个字符?它设置为 varchar(2) 但显然是前两个字符,而不是最后一个。
下面是我的代码,希望一切都在规则之内并且可以理解:
谢谢。
<?xml version="1.0" encoding="UTF-8" ?>
<ZMPROD01>
<IDOC BEGIN="1">
<EDI_DC40 SEGMENT="1">
<TABNAM>EDI_DC40</TABNAM>
<DOCNUM>0000003899888135</DOCNUM>
<CREDAT>20220201</CREDAT>
<CRETIM>152041</CRETIM>
</EDI_DC40>
<ZPROD SEGMENT="1">
<WERKS>8285</WERKS>
<LGNUM>0</LGNUM>
<AUFNR>000915229446</AUFNR>
<LINENO>RM01PL01</LINENO>
<CHARG>0006186588</CHARG>
<START1>20220202</START1>
<START2>211609</START2>
<QTY>4166.000</QTY>
<END1>20220202</END1>
<END2>240000</END2>
<MAKTX>579 FUS5 75ML ULTRA SENST GEL</MAKTX>
<PLN_ORDER>6963701111</PLN_ORDER>
<Z1PRODI SEGMENT="1">
<POSNR>000010</POSNR>
<MATNR>000000000098920665</MATNR>
</Z1PRODI>
<Z1PRODI SEGMENT="1">
<POSNR>000040</POSNR>
<HRKFT>V010</HRKFT>
</Z1PRODI>
<Z1PRODI SEGMENT="1">
<POSNR>000050</POSNR>
<MATNR>000000000099396964</MATNR>
</Z1PRODI>
</ZPROD>
</IDOC>
</ZMPROD01>
CREATE TABLE XMLTESTTABLE
(
PONo int,
ASP int,
LOTNo varchar(11),
EntryDate date,
StartDate date,
EndDate date,
GAS int,
PlannedQty varchar(15),
LineNum varchar(2),
SAPDesc varchar(200),
StartTime date,
EndTime date
);
INSERT INTO XMLTESTTABLE(PONo, ASP, LOTNo, EntryDate, StartDate, EndDate, GAS, PlannedQty, LineNum, SAPDesc, StartTime, EndTime)
SELECT
MY_XML.ZPROD.query('AUFNR').value('.', 'VARCHAR(9)'),
MY_XML.ZPROD.query('CHARG').value('.', 'VARCHAR(8)'),
MY_XML.ZPROD.query('PLN_ORDER').value('.', 'VARCHAR(10)'),
MY_XML.ZPROD.query('START1').value('.', 'date'),
MY_XML.ZPROD.query('START1').value('.', 'date'),
MY_XML.ZPROD.query('END1').value('.', 'date'),
MY_XML.ZPROD.query('CHARG').value('.', 'VARCHAR(8)'),
MY_XML.ZPROD.query('QTY').value('.', 'VARCHAR(9)'),
MY_XML.ZPROD.query('LINENO').value('.', 'VARCHAR(2)'),
MY_XML.ZPROD.query('MAKTX').value('.', 'VARCHAR(200)'),
MY_XML.ZPROD.query('START2').value('.', 'time'),
MY_XML.ZPROD.query('END2').value('.', 'time')
FROM (SELECT CAST(MY_XML AS xml)
FROM OPENROWSET(BULK 'C:\Users\PC_user\Documents\Idoc3899888135.xml', SINGLE_BLOB) AS T(MY_XML)) AS T(MY_XML)
CROSS APPLY MY_XML.nodes('ZMPROD01/ZPROD') AS MY_XML (ZPROD);
请尝试以下解决方案。
- 无需使用
.query()
方法。 - ##3,4 已解决。
- 我冒昧地将无效的 240000 次处理为 23:59:59。
- 最后两列的数据类型是
time(0)
。
SQL
USE tempdb;
GO
DROP TABLE IF EXISTS XMLTESTTABLE;
CREATE TABLE XMLTESTTABLE (
PONo INT,
ASP int,
LOTNo varchar(11),
EntryDate date,
StartDate date,
EndDate date,
GAS int,
PlannedQty varchar(15),
LineNum varchar(2),
SAPDesc varchar(200),
StartTime time(0),
EndTime time(0)
);
INSERT INTO XMLTESTTABLE(PONo, ASP, LOTNo, EntryDate, StartDate, EndDate, GAS, PlannedQty, LineNum, SAPDesc, StartTime, EndTime)
SELECT ZPROD.value('(AUFNR/text())[1]', 'VARCHAR(9)')
, ZPROD.value('(CHARG/text())[1]', 'VARCHAR(8)')
, ZPROD.value('(PLN_ORDER/text())[1]', 'VARCHAR(10)')
, ZPROD.value('(START1/text())[1]', 'date')
, ZPROD.value('(START1/text())[1]', 'date')
, ZPROD.value('(END1/text())[1]', 'date')
, ZPROD.value('(CHARG/text())[1]', 'VARCHAR(8)')
, ZPROD.value('(QTY/text())[1]', 'DECIMAL(10,0)') AS [qty]
, RIGHT(ZPROD.value('(LINENO/text())[1]', 'VARCHAR(10)'), 2) AS [lineno]
, ZPROD.value('(MAKTX/text())[1]', 'VARCHAR(200)') AS MAKTX
, TRY_CAST(STUFF(STUFF(ZPROD.value('(START2/text())[1]', 'CHAR(6)'),3,0,':'),6,0,':') AS TIME)
, TRY_CAST(IIF(STUFF(STUFF(ZPROD.value('(END2/text())[1]', 'CHAR(6)'),3,0,':'),6,0,':')='24:00:00'
,'23:59:59',null) AS TIME)
FROM (SELECT TRY_CAST(MY_XML AS xml)
FROM OPENROWSET(BULK 'e:\Temp\Idoc3899888135.xml', SINGLE_BLOB) AS T(MY_XML)) AS T(MY_XML)
CROSS APPLY MY_XML.nodes('/ZMPROD01/IDOC/ZPROD') AS MY_XML(ZPROD);
-- test
SELECT * FROM dbo.XMLTESTTABLE;