How to parse data from a CLOB in SQL Server? - sql

I would like to use OPENROWSET with the BULK command to load data into SQL Server as a CLOB, and as a second step to parse the CLOB and load read the data as a table.
E.g.:
SELECT BulkColumn
FROM OPENROWSET (BULK 'c:\somedir\somefile.txt', SINGLE_CLOB) TheFile
yields:
BulkColumn
Col1,Col2,Col3,1,2,3,1,2,3,1,2,3,1,2,3
I want to select this as:
Col1 Col2 Col3
1 2 3
1 2 3
1 2 3

Create a format file and use OPENROWSET or BULK INSERT to import data from text file.
Example format.xml:
<?xml version="1.0" ?>
<BCPFORMAT xmlns="http://schemas.microsoft.com/sqlserver/2004/bulkload/format" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RECORD>
<FIELD ID="1" xsi:type="CharTerm" TERMINATOR="," MAX_LENGTH="1" />
<FIELD ID="2" xsi:type="CharTerm" TERMINATOR="," MAX_LENGTH="1" />
<FIELD ID="3" xsi:type="CharTerm" TERMINATOR="," MAX_LENGTH="1" />
</RECORD>
<ROW>
<COLUMN SOURCE="1" NAME="Col1" xsi:type="SQLNVARCHAR" />
<COLUMN SOURCE="2" NAME="Col2" xsi:type="SQLNVARCHAR" />
<COLUMN SOURCE="3" NAME="Col3" xsi:type="SQLNVARCHAR" />
</ROW>
</BCPFORMAT>
This is the key line:
<FIELD ID="3" xsi:type="CharTerm" TERMINATOR="," MAX_LENGTH="1" />
where the terminator char is "," and not "\r\n", if the data is in a single line.
Example OPENROWSET:
INSERT INTO [your_table]
SELECT [text_file].[Col1],
[text_file].[Col2],
[text_file].[Col3]
FROM OPENROWSET(
BULK N'c:\somedir\somefile.txt',
FORMATFILE = N'c:\somedir\format.xml',
FIRSTROW = 1) AS [text_file]
Example BULK INSERT:
BULK INSERT [your_table]
FROM N'c:\somedir\somefile.txt'
WITH (FORMATFILE = N'c:\somedir\format.xml')

Don't import it as OPENROWSET..BULK
You can use BULK INSERT to import it as columns or OPENROWSET by itself

Related

Update 3rd level deep field value in an XML using xQuery

I have the following sample XML and I am looking to Update:
AttendeeID to 7878 (will be a sql variable) where sequence = 1 (will be a sql variable)
Expected output is to see 7878 in the AttendeeID field's value. When I run any of the 2 options I tried, it does not yield the correct result. For Eg. Delete works but the element is not added. Replace value does not update the value.
Any inputs are highly appreciated. Thank you.
--------XML ---------------------------
DECLARE #cartXML XML =
'<OBJECT CLASS="Test1" ID="-1" FULL="FULL" VERSION="1">
<FIELD NAME="OrderDate">20220619</FIELD>
<FIELD NAME="OrderParty">Individual</FIELD>
<FIELD NAME="ShipToID">34567</FIELD>
<FIELD NAME="ShipToAddress1">123 Test Street</FIELD>
<FIELD NAME="ShipToCity">TestCity</FIELD>
<FIELD NAME="ShipToState">IL</FIELD>
<FIELD NAME="ShipTocountry">USA</FIELD>
<FIELD NAME="TaxNumber">444</FIELD>
<FIELD NAME="DiscountCode">Summer22</FIELD>
<SUBTYPE NAME="SubType1">
<OBJECT NAME="SubType111" ID="-1">
<FIELD NAME="TestID">-1</FIELD>
<FIELD NAME="Sequence">1</FIELD>
<FIELD NAME="ParentSequence">-1</FIELD>
<FIELD NAME="ExtID">-1</FIELD>
<FIELD NAME="ExtName">ABC</FIELD>
</OBJECT>
<OBJECT NAME="SubType111" ID="-1">
<FIELD NAME="TestID">-1</FIELD>
<FIELD NAME="Sequence">2</FIELD>
<FIELD NAME="ParentSequence">1</FIELD>
<FIELD NAME="ExtID">-1</FIELD>
<FIELD NAME="ExtName">DEF</FIELD>
<FIELD NAME="__ExtendedData"><OBJECT
CLASS="Meet123" ID="-1" FULL="FULL"
VERSION="1"><FIELD
NAME="OrderDetailID">-1</FIELD><FIELD
NAME="OrderID">-1</FIELD><FIELD
NAME="Sequence">0</FIELD><FIELD
NAME="AttendeeID">123</FIELD><FIELD NAME="AttendeeID_Name">Test, Mark/I
H 6</FIELD><FIELD
NAME="ShowList">1</FIELD><FIELD
NAME="BdgeName">Mark</FIELD><FIELD
NAME="BadgeCompanyName">I H 6</FIELD>
</OBJECT></FIELD>
</OBJECT>
<OBJECT NAME="SubType111" ID="-1">
<FIELD NAME="TestID">-1</FIELD>
<FIELD NAME="Sequence">3</FIELD>
<FIELD NAME="ParentSequence">1</FIELD>
<FIELD NAME="ExtID">-1</FIELD>
<FIELD NAME="ExtName">GHI</FIELD>
</OBJECT>
</SUBTYPE>
<SUBTYPE NAME="SubType2"/>
<SUBTYPE NAME="SubType3"/>
</OBJECT>';
-----------------------SQL -----------------------
select #cartXML as originalXML
DECLARE #ID as int ,#productID as int, #attendeeId as int = 7878,
#sequenceId as int, #orderLineXML as XML , #ExtendedAttrDetail as XML
SET #sequenceId = 2
select #orderlineXML = c.query('.'), #ExtendedAttrDetail = w.query('.') from
#cartXML.nodes('/OBJECT/SUBTYPE/OBJECT[FIELD[#NAME="Sequence"]/text()=sql:variable("#sequenceId")]') t1(c)
Cross APPLY (VALUES(TRY_CAST(c.query('FIELD[#NAME="__ExtendedData"]').value('.','NVARCHAR(MAX)') AS XML)))AS t2(w)
-----This works..But I am looking to alter #cartXML as it contains the entire XML
SET #ExtendedAttrDetail.modify('replace value of
(/OBJECT/FIELD[#NAME="AttendeeID"]/text())[1]
with sql:variable("#attendeeId")')
--select #ExtendedAttrDetail
------- Option 1( Preferred)---does not work--
SET #cartXML.modify ('replace value of
(/OBJECT/SUBTYPE/OBJECT[FIELD[#NAME="Sequence"]/text()=sql:variable("#sequenceId")]/FIELD[#NAME="__ExtendedData"]/OBJECT/FIELD[#NAME="AttendeeID"]/text())[1] with sql:variable("#attendeeId")')
select #cartXML as ModifiedDirectly
---Option 2 (Insert does not add correctly )
--SET #cartXML.modify('delete
--/OBJECT/SUBTYPE/OBJECT[FIELD[#NAME="Sequence"]/text()=sql:variable("#sequenceId")]
--/FIELD[#NAME="__ExtendedData"]');
--SET #cartXML.modify('insert sql:variable("#ExtendedAttrDetail") into
--(/OBJECT/SUBTYPE/OBJECT[FIELD[#NAME="Sequence"]/text()=sql:variable("#sequenceId")])
--[1]');
--SELECT #cartXML as UpdatedXL;
Please try the following solution.
The issue is that the XML fragment in question is encoded.
SQL
DECLARE #cartXML XML =
N'<OBJECT CLASS="Test1" ID="-1" FULL="FULL" VERSION="1">
<FIELD NAME="OrderDate">20220619</FIELD>
<FIELD NAME="OrderParty">Individual</FIELD>
<FIELD NAME="ShipToID">34567</FIELD>
<FIELD NAME="ShipToAddress1">123 Test Street</FIELD>
<FIELD NAME="ShipToCity">TestCity</FIELD>
<FIELD NAME="ShipToState">IL</FIELD>
<FIELD NAME="ShipTocountry">USA</FIELD>
<FIELD NAME="TaxNumber">444</FIELD>
<FIELD NAME="DiscountCode">Summer22</FIELD>
<SUBTYPE NAME="SubType1">
<OBJECT NAME="SubType111" ID="-1">
<FIELD NAME="TestID">-1</FIELD>
<FIELD NAME="Sequence">1</FIELD>
<FIELD NAME="ParentSequence">-1</FIELD>
<FIELD NAME="ExtID">-1</FIELD>
<FIELD NAME="ExtName">ABC</FIELD>
</OBJECT>
<OBJECT NAME="SubType111" ID="-1">
<FIELD NAME="TestID">-1</FIELD>
<FIELD NAME="Sequence">2</FIELD>
<FIELD NAME="ParentSequence">1</FIELD>
<FIELD NAME="ExtID">-1</FIELD>
<FIELD NAME="ExtName">DEF</FIELD>
<FIELD NAME="__ExtendedData"><OBJECT
CLASS="Meet123" ID="-1" FULL="FULL"
VERSION="1"><FIELD
NAME="OrderDetailID">-1</FIELD><FIELD
NAME="OrderID">-1</FIELD><FIELD
NAME="Sequence">0</FIELD><FIELD
NAME="AttendeeID">123</FIELD><FIELD NAME="AttendeeID_Name">Test, Mark/I
H 6</FIELD><FIELD
NAME="ShowList">1</FIELD><FIELD
NAME="BdgeName">Mark</FIELD><FIELD
NAME="BadgeCompanyName">I H 6</FIELD>
</OBJECT></FIELD>
</OBJECT>
<OBJECT NAME="SubType111" ID="-1">
<FIELD NAME="TestID">-1</FIELD>
<FIELD NAME="Sequence">3</FIELD>
<FIELD NAME="ParentSequence">1</FIELD>
<FIELD NAME="ExtID">-1</FIELD>
<FIELD NAME="ExtName">GHI</FIELD>
</OBJECT>
</SUBTYPE>
<SUBTYPE NAME="SubType2"/>
<SUBTYPE NAME="SubType3"/>
</OBJECT>';
DECLARE #ExtendedData XML
, #attendeeId INT = 770;;
-- Step #1: select XML fragment in question as real XML data type
SELECT #ExtendedData = w
FROM #cartxml.nodes('/OBJECT/SUBTYPE/OBJECT[#ID="-1"]') as t1(c)
CROSS APPLY (VALUES(TRY_CAST(c.query('FIELD[#NAME="__ExtendedData"]').value('.','NVARCHAR(MAX)') AS XML))) AS t2(w)
WHERE w.exist('/OBJECT[#CLASS="Meet123"]') = 1;
-- Step #2: remove encoded XML fragment
SET #cartXML.modify('replace value of (/OBJECT/SUBTYPE[#NAME="SubType1"]/OBJECT/FIELD[#NAME="__ExtendedData"]/text())[1]
with ""');
-- Step #3: modify AttendeeID
SET #ExtendedData.modify('replace value of
(/OBJECT/FIELD[#NAME="AttendeeID"]/text())[1]
with sql:variable("#attendeeId")');
-- Step #4: insert real XML fragment
SET #cartXML.modify('insert sql:variable("#ExtendedData") into
(/OBJECT/SUBTYPE[#NAME="SubType1"]/OBJECT/FIELD[#NAME="__ExtendedData"])[1]');
-- test
SELECT #cartXML;

Delimiters with bcp import

I am trying to import bulk data from text files. The statement that i use is below:
DECLARE #s as varchar(300)
SET #s='bcp [hc]..[QRYM_COMPANIES] in ' + char(34) + 'C:\SQL Files\health canada allfiles\comp.txt' + char(34) + ' -C ACP -c -t \", -r\n -e' + char(34) + 'C:\SQL Files\health canada allfiles\err\comp.err.txt' + char(34) + ' -b250 -m50 -SServer -Usa -P' + char(34) + 'mypassword' + char(34) + ' -h' + char(34) + 'TABLOCK' + char(34)
PRINT #s
EXEC master..xp_cmdshell #s
Now, normally I would have put -t, but my data contains commas in some of the data fields which results in the data being shifted. When I try to use -t \" I get the error "String data, right truncation", so that is why I am having to use the combination of -t ,\"
The problem here is that I get quotations in my transferred data. Below is a sample row of my data:
"20042","NSL95","4797","NU SKIN INTERNATIONAL, INC.","DIN OWNER","Y","N","N","N","","75 WEST CENTER STREET","PROVO","UTAH","UNITED STATES","84601",""
The table description is below. To avoid the "string truncation error" i have added a 1 to the left field size.
Can someone help me fix this problem?
Thanks
CREATE TABLE [health_canada].[dbo].[QRYM_COMPANIES] (
DRUG_CODE VARCHAR(18) NOT NULL, --NUMERIC(8) NOT NULL,
MFR_CODE VARCHAR(15),
COMPANY_CODE VARCHAR(16), --NUMERIC(6),
COMPANY_NAME VARCHAR(180),
COMPANY_TYPE VARCHAR(140),
ADDRESS_MAILING_FLAG VARCHAR(11),
ADDRESS_BILLING_FLAG VARCHAR(11),
ADDRESS_NOTIFICATION_FLAG VARCHAR(11),
ADDRESS_OTHER VARCHAR(11),
SUITE_NUMERIC VARCHAR(120),
STREET_NAME VARCHAR(180),
CITY_NAME VARCHAR(160),
PROVINCE VARCHAR(140),
COUNTRY VARCHAR(140),
POSTAL_CODE VARCHAR(120),
POST_OFFICE_BOX VARCHAR(115)
) ON [PRIMARY]
GO
Consider to use a format file with your bcp call. It is easy to configure, and you can fine tune it for your file. Just add -f and the path to use it: http://msdn.microsoft.com/en-us/library/ms162802.aspx
Steps
Add the format file to the disk (make sure that the SQL server can reach the path).
Update paths in query.
Run query.
I used this file:
This code imported your example data without quotations with the format file:
DECLARE #importTable VARCHAR(128) = 'hc.dbo.QRYM_COMPANIES';
DECLARE #importPath VARCHAR(8000) = '\\YOURPATH\comp.txt';
DECLARE #formatFilePath VARCHAR(8000) = '\\YOURPATH\formatFile.txt';
DECLARE #separator VARCHAR(10) = '';
DECLARE #export VARCHAR(8000) = 'bcp "' + #importTable + '" in "' + #importPath + '" -T -f "' + #formatFilePath + '" -C RAW -S ' + ##SERVERNAME;
PRINT(#export)
EXEC xp_cmdshell #export
Output:
SELECT * FROM hc.dbo.QRYM_COMPANIES:
Add this format file to your disk:
<?xml version="1.0"?>
<BCPFORMAT xmlns="http://schemas.microsoft.com/sqlserver/2004/bulkload/format" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RECORD>
<FIELD ID="0" xsi:type="CharTerm" TERMINATOR='"' MAX_LENGTH="1" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="1" xsi:type="CharTerm" TERMINATOR='","' MAX_LENGTH="18" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="2" xsi:type="CharTerm" TERMINATOR='","' MAX_LENGTH="15" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="3" xsi:type="CharTerm" TERMINATOR='","' MAX_LENGTH="16" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="4" xsi:type="CharTerm" TERMINATOR='","' MAX_LENGTH="180" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="5" xsi:type="CharTerm" TERMINATOR='","' MAX_LENGTH="140" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="6" xsi:type="CharTerm" TERMINATOR='","' MAX_LENGTH="11" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="7" xsi:type="CharTerm" TERMINATOR='","' MAX_LENGTH="11" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="8" xsi:type="CharTerm" TERMINATOR='","' MAX_LENGTH="11" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="9" xsi:type="CharTerm" TERMINATOR='","' MAX_LENGTH="11" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="10" xsi:type="CharTerm" TERMINATOR='","' MAX_LENGTH="120" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="11" xsi:type="CharTerm" TERMINATOR='","' MAX_LENGTH="180" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="12" xsi:type="CharTerm" TERMINATOR='","' MAX_LENGTH="160" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="13" xsi:type="CharTerm" TERMINATOR='","' MAX_LENGTH="140" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="14" xsi:type="CharTerm" TERMINATOR='","' MAX_LENGTH="140" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="15" xsi:type="CharTerm" TERMINATOR='","' MAX_LENGTH="120" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="16" xsi:type="CharTerm" TERMINATOR='"\r\n' MAX_LENGTH="115" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
</RECORD>
<ROW>
<COLUMN SOURCE="1" NAME="DRUG_CODE" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="2" NAME="MFR_CODE" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="3" NAME="COMPANY_CODE" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="4" NAME="COMPANY_NAME" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="5" NAME="COMPANY_TYPE" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="6" NAME="ADDRESS_MAILING_FLAG" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="7" NAME="ADDRESS_BILLING_FLAG" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="8" NAME="ADDRESS_NOTIFICATION_FLAG" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="9" NAME="ADDRESS_OTHER" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="10" NAME="SUITE_NUMERIC" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="11" NAME="STREET_NAME" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="12" NAME="CITY_NAME" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="13" NAME="PROVINCE" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="14" NAME="COUNTRY" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="15" NAME="POSTAL_CODE" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="16" NAME="POST_OFFICE_BOX" xsi:type="SQLVARYCHAR"/>
</ROW>
</BCPFORMAT>
You can auto generate new format files with bcp if you need it for other files/tables (no need to do this now if the format file works)
Important:
After format file export:
Replace: TERMINATOR="\"," to TERMINATOR='","'
Replace: TERMINATOR="\r\n" to TERMINATOR='"\r\n'*
Add to <record> (will remove first quotation): <FIELD ID="0" xsi:type="CharTerm" TERMINATOR='"' MAX_LENGTH="1" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
Auto generate query:
DECLARE #importTable VARCHAR(128) = 'hc.dbo.QRYM_COMPANIES';
DECLARE #formatFilePath VARCHAR(8000) = '\\YourFilePath\formatFile.txt';
DECLARE #bcpCall VARCHAR(8000);
SET #bcpCall = 'bcp "' + #importTable + '" format nul -c -t", -x -f "' + #formatFilePath + '" -T -S ' + ##SERVERNAME;
PRINT #bcpCall
EXEC xp_cmdshell #bcpCall

Extracting xmlsequence from another xmlsequance in SQL

I have small problem with xmlsequence. I am codding in PL-SQL (Oracle)
Let's say, my XML looks like this:
<Row name="Row1">
<Field name="Filed1">
<Value1>
</Value1>
</Field>
<Row name="Row2inRow1">
<Field name="Filed2">
<Value1>
</Value1>
</Field>
</Row>
<Row name="Row2inRow1">
<Field name="Filed2">
<Value1>
</Value1>
</Field>
</Row>
<Row name="Row1">
<Field name="Filed1">
<Value1>
</Value1>
</Field>
<Row name="Row2inRow1">
<Field name="Filed2">
<Value1>
</Value1>
</Field>
</Row>
<Row name="Row2inRow1">
<Field name="Filed2">
<Value1>
</Value1>
</Field>
</Row>
It has 2x same "Row1" which is multiplicated, what's more inside Row1 I have multiplicated "Row2inRow1".
The problem is, I would like to select values from Ro2InRow1 and from Row1, to concat them, the effect should be:
Value1 (from 1st Row1) || Value1 (from 1st Row2inRow1)
Value1(from 1st Row1) || Value1 (from 2nd Row2InRow1)
Value1 (from 2nd Row1) || Value1 (from 3rd Row2inRow1)
Value1(from 2nd Row1) || Value1 (from 4th Row2InRow1)
I've tried to code is somehow, but I can't force my query to work right:
declare
xml_data xmldata;
begin
for rec1 in(select extractvalue(value(x),'//Field[#name="Filed1"]/Value1') ValueOfField1,
from table(xmlsequence(extract(xml_data.data,'//Row[#name="Row1"]')))x )
loop
dbms_output.put_line('1 : '|| ValueOfField1);
for rec2 in(select extractvalue(value(x),'//Field[#name="Filed2"]/Value1') ValueOfField2,
from table(xmlsequence(extract(xml_data.data,'//Row[#name="Row2inRow1"]')))k ) --? What here!
loop
dbms_output.put_line('1 : '|| ValueOfField2);
end loop;
end loop;
end;
Any ideas ? :(

update xml attribute in xml returns error SQL

Im trying to update an attribute of an xml in SQL.
My XML is stored on a variable #tmpRespXML:
<Responses>
<x id="3" name="Good" val="0" seq="0" createsr="0" />
<x id="4" name="Fair" val="0" seq="0" createsr="0" />
<x id="5" name="Needs Repair" val="1" seq="0" createsr="0" />
<x id="6" name="Not Inspected" val="1" seq="0" createsr="0" />
<x id="7" name="N/A" val="1" seq="0" createsr="0" />
</Responses>
So what I did is to put the xml in a temp table.
DECLARE #tmpRespTBL TABLE(Responses XML)
INSERT #tmpRespTBL VALUES(#tmpRespXML)
and then update the table. I'm trying to set the attribute #createsr to 1 where my attribute #id is equal to #items
UPDATE #tmpRespTBL
SET Responses.modify('replace value of(/Responses/x[#id=("'+#items+'")]/#createsr)[1] with "1"')
This returns the ff error:
Msg 8172, Level 16, State 1, Line 30 The argument 1 of the xml data
type method "modify" must be a string literal.
What am I missing here?
Try with
SET Responses.modify('replace value of(/Responses/x[#id=("''+#items+''")]/#createsr)[1] with "1"')
That should fix your issue. What I did here is escape the '

How to get BCP to generate a Format File for importing fixed-width data into a SQL Server table?

The bcp command that I am using:
bcp TableName format nul -c -f c:\folder\TargetFile.xml -x -S ServerName -T -q
I think I just need the fields to have a type of xsi:type="CharFixed" rather then xsi:type="CharTerm".
The xml that it creates which doesn't work for me:
<?xml version="1.0"?>
<BCPFORMAT xmlns="http://schemas.microsoft.com/sqlserver/2004/bulkload/format" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RECORD>
<FIELD ID="1" xsi:type="CharTerm" TERMINATOR="\t" MAX_LENGTH="24" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="2" xsi:type="CharTerm" TERMINATOR="\t" MAX_LENGTH="150" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="3" xsi:type="CharTerm" TERMINATOR="\t" MAX_LENGTH="150" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="4" xsi:type="CharTerm" TERMINATOR="\t" MAX_LENGTH="20" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="5" xsi:type="CharTerm" TERMINATOR="\r\n" MAX_LENGTH="12" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
</RECORD>
<ROW>
<COLUMN SOURCE="1" NAME="UID" xsi:type="SQLNCHAR"/>
<COLUMN SOURCE="2" NAME="FNAME" xsi:type="SQLNCHAR"/>
<COLUMN SOURCE="3" NAME="LNAME" xsi:type="SQLNCHAR"/>
<COLUMN SOURCE="4" NAME="PHONE" xsi:type="SQLNCHAR"/>
<COLUMN SOURCE="5" NAME="Target" xsi:type="SQLNCHAR"/>
</ROW>
</BCPFORMAT>
What I actually need: (xsi:type="CharFixed")
<?xml version="1.0"?>
<BCPFORMAT xmlns="http://schemas.microsoft.com/sqlserver/2004/bulkload/format" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RECORD>
<FIELD ID="1" xsi:type="CharFixed" LENGTH="3"/>
<FIELD ID="2" xsi:type="CharFixed" LENGTH="3"/>
</RECORD>
<ROW>
<COLUMN SOURCE="1" NAME="Field1" xsi:type="SQLCHAR" LENGTH="3"/>
<COLUMN SOURCE="2" NAME="Field2" xsi:type="SQLCHAR" LENGTH="3"/>
</ROW>
</BCPFORMAT>
Here is the method I created to help me resolve my issue...
private XmlDocument CreateFormatFile()
{
const string xsiURI = "http://www.w3.org/2001/XMLSchema-instance";
var ff = new XmlDocument();
var dec = ff.CreateXmlDeclaration("1.0", null, null);
ff.AppendChild(dec);
var bcpFormat = ff.CreateElement("BCPFORMAT");
bcpFormat.SetAttribute("xmlns", "http://schemas.microsoft.com/sqlserver/2004/bulkload/format");
bcpFormat.SetAttribute("xmlns:xsi", xsiURI);
var record = ff.CreateElement("RECORD");
var row = ff.CreateElement("ROW");
for (var x = 0; x < Columns.Count; x++)
{
var col = Columns[x];
var id = (col.Index + 1).ToString();
var length = col.Length.ToString();
var column = ff.CreateElement("COLUMN");
column.SetAttribute("SOURCE", id);
column.SetAttribute("NAME", col.Name);
column.SetAttribute("type", xsiURI, "SQLCHAR");
column.SetAttribute("LENGTH", length);
var field = ff.CreateElement("FIELD");
field.SetAttribute("ID", id);
if (x != Columns.Count - 1)
{
field.SetAttribute("type", xsiURI, "CharFixed");
field.SetAttribute("LENGTH", length);
}
else
{
field.SetAttribute("type", xsiURI, "CharTerm");
field.SetAttribute("TERMINATOR", #"\r\n");
}
record.AppendChild(field);
row.AppendChild(column);
}
bcpFormat.AppendChild(record);
bcpFormat.AppendChild(row);
ff.AppendChild(bcpFormat);
return ff;
}
Try using the bcp Native Format Option:
How bcp Handles Data in Native Format
...
char or varchar data
At the beginning of each char or varchar field, bcp adds the prefix length.
You'd use the "-n" option instead of "-c":
bcp TableName format nul -n -f c:\folder\TargetFile.xml -x -S ServerName -T -q