Saving data in table using OpenXML - sql

i want to save xml data into a table in sp,passed as string,here is my code
alter PROCEDURE usp_be_insertXML
-- Add the parameters for the stored procedure here
#xml varchar(1000)
AS
BEGIN
DECLARE #idoc int
DECLARE #doc varchar(1000)
SET NOCOUNT ON;
EXEC sp_xml_preparedocument #idoc OUTPUT, #xml
BEGIN TRY
INSERT INTO testing ([Name] ,[Fname] )
SELECT Column1,Column2
FROM OPENXML (#idoc, 'NewDataSet/Sheet1', 1)
WITH ([Column1] [nvarchar](50),
[Column2] [nvarchar](50))
END TRY
BEGIN CATCH
END CATCH
EXECUTE sp_xml_removedocument #idoc
END
This inserts NULL only in table,any help?
and here is XML
<NewDataSet>
<Sheet1>
<Column1>Name</Column1>
<Column2>Fname</Column2>
</Sheet1>
<Sheet1>
<Column1>khan</Column1>
<Column2>dd</Column2>
</Sheet1>
<Sheet1>
<Column1>mytest</Column1>
<Column2>ff</Column2>
</Sheet1>
</NewDataSet>

Problem is you're specifying to use an "attribute-centric" mapping (the "1" in the last parameter of OPENXML), but your data elements are actually elements. You can get your desired result one of two ways:
1) Change the parameter to "2"
2) Change your WITH clause to explicitly state the child element you're looking for:
WITH (
[Column1] [nvarchar](50) 'Column1'
, [Column2] [nvarchar](50) 'Column2'
)

Related

Problem with parsing XML with multiple namespace into SQL

I've got problem with parsing informations from XML into SQL with double namespace.
Have a look at this code:
DECLARE #Handle AS INT; -- The handle of the XML data, passed to sp_xml_preparedocument
DECLARE #Xml AS NVARCHAR(1000); -- The XML document for this example
SET #Xml = N'
<SiBikNet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://www.ws.bik.pl/ws/ki/2v2/types">
<BIK_REQUEST>
<siBikNetResponse>
<consentDate>2018-07-29</consentDate>
<citizenshipStatus>citizen</citizenshipStatus>
<nationality>PL</nationality>
<pesel>123</pesel>
</siBikNetResponse>
</BIK_REQUEST>
</SiBikNet>';
EXEC sys.sp_xml_preparedocument #Handle OUTPUT , #Xml, N'<SiBikNet xmlns:t="https://www.ws.bik.pl/ws/ki/2v2/types"/>'; --Prepare a parsed document
SELECT *
FROM
OPENXML(#Handle,'/t:SiBikNet/t:BIK_REQUEST/t:siBikNetResponse', 2)
WITH ( nationality NVARCHAR(10) 't:nationality',
pesel NVARCHAR(10) 't:pesel '
);
EXEC sys.sp_xml_removedocument #Handle;
Which gives me proper output in forms of table with 2 columns.
But when I will add one row with double namespace: then I cannot parse this informations :
DECLARE #Handle AS INT; -- The handle of the XML data, passed to sp_xml_preparedocument
DECLARE #Xml AS NVARCHAR(1000); -- The XML document for this example
SET #Xml = N'
<SiBikNet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://www.ws.bik.pl/ws/ki/2v2/types">
<BIK_REQUEST xmlns="">
<siBikNetResponse>
<consentDate>2018-07-29</consentDate>
<citizenshipStatus>citizen</citizenshipStatus>
<nationality>PL</nationality>
<pesel>123</pesel>
</siBikNetResponse>
</BIK_REQUEST>
</SiBikNet>';
EXEC sys.sp_xml_preparedocument #Handle OUTPUT , #Xml, N'<SiBikNet xmlns:t="https://www.ws.bik.pl/ws/ki/2v2/types"/>'; --Prepare a parsed document
SELECT *
FROM
OPENXML(#Handle,'/t:SiBikNet/t:BIK_REQUEST/t:siBikNetResponse', 2)
WITH ( nationality NVARCHAR(10) 't:nationality',
pesel NVARCHAR(10) 't:pesel '
);
EXEC sys.sp_xml_removedocument #Handle;
Can anyone help ?
When I get stuck with anonymous namespaces or oddball namespace combinations, the simplest way is to just use the XPath function local-name(). Like this:
DECLARE #Handle AS INT; -- The handle of the XML data, passed to sp_xml_preparedocument
DECLARE #Xml AS NVARCHAR(1000); -- The XML document for this example
SET #Xml = N'
<SiBikNet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://www.ws.bik.pl/ws/ki/2v2/types">
<BIK_REQUEST xmlns="">
<siBikNetResponse>
<consentDate>2018-07-29</consentDate>
<citizenshipStatus>citizen</citizenshipStatus>
<nationality>PL</nationality>
<pesel>98070902702</pesel>
</siBikNetResponse>
</BIK_REQUEST>
</SiBikNet>';
EXEC sys.sp_xml_preparedocument #Handle OUTPUT , #Xml, N'<SiBikNet xmlns:t="https://www.ws.bik.pl/ws/ki/2v2/types"/>'; --Prepare a parsed document
SELECT *
FROM
OPENXML(#Handle,'/*[local-name()="SiBikNet"]/*[local-name()="BIK_REQUEST"]/*[local-name()="siBikNetResponse"]', 2)
WITH ( nationality NVARCHAR(10) ,--'t:nationality',
pesel NVARCHAR(10) --'t:pesel '
);
EXEC sys.sp_xml_removedocument #Handle;

SQL Server : XML value returns Scalar and seems I need to convert it twice

I have this line of SQL:
DECLARE #temp_Id UNIQUEIDENTIFIER = #data.value('/metaData[1]/item[#key="Id"][1]/#value', 'uniqueidentifier')
So, #data is a parameter to my stored procedure. #data XML
I want to pass a value out of the XML into another stored procedure, as you can see it's the Id field in the xml.
#data.value('/metaData[1]/item[#key="Id"][1]/#value', 'uniqueidentifier')
This pulls out and converts the Id value to a Uniqueidentifier however when I assign this to a variable and pass it to the stored procedure:
EXEC my_sproc #Id = #temp_Id
I get an error
Msg 137, Level 15, State 2, Procedure Some_Sproc, Line __
Must declare the scalar variable "#tempId".
Looking around, people are suggesting to wrap the #data.value(... in a CONVERT( DATA_TYPE, VALUE ) which seems slightly absurd.
-- EDIT --
I reckon there could also be a chance of my SQL Server Management Studio intellisense being out of sync....
-- CODE --
CREATE PROCEDURE [dbo].[Sproc_CB8PutNotification]
#message_type NVARCHAR(250),
#utc_timestamp DATETIME2,
#data XML
AS
BEGIN TRY
DECLARE #temp_Id UNIQUEIDENTIFIER = #data.value('/metaData[1]/item[#key="Id"][1]/#value', 'uniqueidentifier')
EXEC dbo.SaveNotification #Id = #tempId;
END TRY
BEGIN CATCH
-- some catch code
END CATCH
It should work:
CREATE PROCEDURE my_proc
#id UNIQUEIDENTIFIER
AS
SELECT #id;
GO
DECLARE #data XML =
'<metaData><item key="Id" value="903e9859-f8fd-4163-9303-b43f89fe977f"/>
</metaData>';
DECLARE #temp_Id UNIQUEIDENTIFIER
= #data.value('/metaData[1]/item[#key="Id"][1]/#value', 'uniqueidentifier');
EXEC my_proc #id = #temp_id;
LiveDemo
I suspect you have GO betweens calls and variable is not visible between batches like:
DECLARE #data XML =
'<metaData>
<item key="Id" value="903e9859-f8fd-4163-9303-b43f89fe977f"/>
</metaData>';
DECLARE #temp_Id UNIQUEIDENTIFIER
= #data.value('/metaData[1]/item[#key="Id"][1]/#value', 'uniqueidentifier');
GO
EXEC my_proc #id = #temp_id;
Error(s), warning(s):
Must declare the scalar variable "#temp_id".
LiveDemo2
Or you have nested calls and variable is out of scope.
EDIT:
Typo #temp_id <> #tempId:
DECLARE #temp_Id UNIQUEIDENTIFIER =
#data.value('/metaData[1]/item[#key="Id"][1]/#value', 'uniqueidentifier')
EXEC dbo.SaveNotification #Id = #tempId;
Working code
You've mixed two naming conventions. The key point is to be consistent. It can save a lot of headaches.

Must declare the scalar variable "#tempattend" in sql procedure?

I am getting an error stating that I Must declare the table variable "#tempattend".
Please help me. How can I pass #tempattend table to #tempTableSelect variable?
ALTER PROCEDURE [dbo].[Rl_LM_AHS]
#SupEmpID nvarchar(10),
#SectorName nvarchar(300),
#dateList nvarchar(300),
#Month nvarchar(5),
#Year nvarchar(5),
#SearchType nvarchar(10)
AS
BEGIN
SET NOCOUNT ON;
declare #tempTableSelect nvarchar(2000)
DECLARE #tempattend Table
(
[Emp.ID] nvarchar(10),
[Name] nvarchar(60),
[1] nvarchar(3) null,
[2] nvarchar(3) null,
[3] nvarchar(3) null
upto ..............
[31] nvarchar(3) null
)
IF (#SearchType = 1)
BEGIN
--INSERT TEAM LIST TO #tempattend TABLE
insert into #tempattend([Emp.ID],[Name]) (Select EMP.empID as [Emp.ID],CONCAT(EMP.emp_fname,' ',COALESCE(nullif(EMP.emp_Mname,'') +' ',''),COALESCE(nullif(EMP.emp_Lname,'') +' ','')) as [Name] from EShiftHistory)
set #tempTableSelect = 'select [Emp.ID],Name,' + #dateList +' from #tempattend'
EXEC (#tempTableSelect)
END
END
You should write
set #tempTableSelect = 'select [Emp.ID],Name,' + #dateList +' from #tempattend'
#tempattend is a temporary table variable. It holds a table, not some value like #datelist.
But why do you EXEC instead of just selecting directly from the table?
Come to think of it: It may not be possible to use memory temp tables in EXEC statements. Try turning this
DECLARE #tempattend Table
into
CREATE TABLE #tempattend
and change every occurance of #tempattend to #tempattend.
Following up on Thorsten Dittmar's answer, why not something like this?
select empID,
CONCAT(emp_fname,' ',
COALESCE(emp_Mname,''),
COALESCE(nullif(emp_Lname,''))) as [Name]
from EShiftHistory
I realize you're trying to do some dynamic selection with the #dateList variable, but that's a strong signal that you should either normalize your tables or just let your client code pick out which columns it wants. (Not everything needs to be done in raw SQL.)
Numbers as column names? Definitely problematic.

Table variable not working in dynamic SQL

My trigger is as below ,
Alter TRIGGER [dbo].[LogTable_InsertTrigger] on [dbo].[std_table] AFTER INSERT
as
DECLARE #ColName varchar(50), #QueryText nvarchar(max)
declare #inserted TABLE(
[CountryID] [int] NOT NULL,
[Country] [nvarchar](255) NOT NULL,
[RegionId] [int] NULL
)
insert into #inserted
select * from inserted
DECLARE objCursor CURSOR FAST_FORWARD FOR
select ColName from dbo.getColumnNames('std_table')
OPEN objCursor
FETCH NEXT FROM objCursor INTO #ColName
WHILE ##FETCH_STATUS = 0
BEGIN
set #QueryText= '
insert into dbo.LogTable
(StandardType,Attribute,Action,NEwValue,UserId,ModifiedDate)
select ''Country'','''+#ColName+''',''Insert'','+#ColName+',1,getdate()
from #inserted'
EXEC sp_executesql #QueryText
FETCH NEXT FROM objCursor INTO #ColName
END
CLOSE objCursor
DEALLOCATE objCursor
When I try to insert to table std_table in DA Layer I get the exception Must declare the table variable "#inserted".
I couldn't use the inserted table directly because I am writing a dynamic query, inside which magic tables wont work. So I am trying to dump the data in inserted table to a temp table and to access from that.
I tried with
select *
into #inserted
from inserted
This works, but since my application is accessed by many users over network this will cause data issues. So I can't use this.
Several things wrong here.
That is a table variable, not a user defined table type.
If #temp tables work, why do you think that will cause data issues for multiple users? Each user will get their own version of the #temp table.
If you know there are exactly three columns and you can hard-code the table variable declaration, why do you need to then generate the three sets of inserts dynamically? Aren't the column names CountryID,Country,RegionID?
If you really need to do this dynamically then it seems like you could do this an easier way without an explicit cursor - not that this is necessarily a bad thing or that it will perform any worse than the below, but the cursor is just much more verbose and ugly code:
ALTER TRIGGER [dbo].[LogTable_InsertTrigger]
ON [dbo].[std_table]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
SELECT * INTO #t FROM inserted;
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'';
SELECT #sql = #sql + CHAR(13) + CHAR(10) + N'INSERT INTO dbo.LogTable
(StandardType,Attribute,Action,NewValue,UserId,ModifiedDate)
SELECT ''Country'','''+ColName+''',''Insert'','+ColName+',1,GETDATE()
FROM #t;'
FROM dbo.GetColumnNames('std_table');
EXEC sp_executesql #sql;
END
GO

OPENXML - SQL Server

My Sp reading XML file data with help of OPENXML in SQL Server.
There is slight problem in this. Here is xml file part
<Name_Address>
<name>JCB SALES PVT</name>
<address>24, SALAROURIA ARENA ADUGODI</address>
<address>HOSUR MAIN ROAD, Honolulu</address>
<country>N</country>
</Name_Address>
and my SQL query is
SELECT
#address = CONVERT(VARCHAR(150), [TEXT])
FROM OPENXML(#idoc,'/Name_Address/address', 0)
WHERE [text] IS NOT NULL
In #address I am getting last address tag value i.e
HOSUR MAIN ROAD, Honolulu
But it should be
24, SALAROURIA ARENA ADUGODI, HOSUR MAIN ROAD, Honolulu
How can I achieve this ?
Help me, guide me to do this.
regards
Your problem isn't specifically to do to with OPENXML.
Your query...
SELECT CONVERT(VARCHAR(150), [TEXT])
FROM OPENXML(#idoc,'/Name_Address/address', 0)
WHERE [text] IS NOT NULL
...returns multiple rows. So when you assign to a variable, it just takes the last of the returned rows.
I've set up an example which uses a cursor to iterate through this. It includes your example document. You can paste this directly in Query Analyser (2000)/Management Studio (2005+) and it will run. all you have to do is add in your commas and spaces (I've just used a space).
DECLARE #hdoc int
DECLARE #doc varchar(1000)
DECLARE #address varchar(150)
DECLARE #thisaddress varchar(150)
set #address = ''
SET #doc ='
<Name_Address>
<name>JCB SALES PVT</name>
<address>24, SALAROURIA ARENA ADUGODI</address>
<address>HOSUR MAIN ROAD, Honolulu</address>
<country>N</country>
</Name_Address>'
EXEC sp_xml_preparedocument #hdoc OUTPUT, #doc
DECLARE addr_cursor CURSOR
FOR SELECT CONVERT(VARCHAR(150), [TEXT])
FROM OPENXML(#hdoc,'/Name_Address/address', 0)
WHERE [text] IS NOT NULL
--select ##FETCH_STATUS
OPEN addr_cursor
FETCH NEXT FROM addr_cursor INTO #thisaddress
WHILE ##FETCH_STATUS = 0
BEGIN
set #address = #address+ #thisaddress + ' '
FETCH NEXT FROM addr_cursor INTO #thisaddress
END
select #address
CLOSE addr_cursor
DEALLOCATE addr_cursor
exec sp_xml_removedocument #hdoc