Loading data from an XML document (not a file) - sql-server

I have a lot of logfiles that I want to load into a SQL Server database via a Talend job so that I can preserve the logs without keeping the files in the file system (we generate over 3k log files every day). I do not want to change the jobs to write to the database directly as I don't want the jobs to be dependent on the DB server being available.
I have created a Talend job that can read a log file and convert it to an XML document which I can then send to a SQL Server (2016) stored procedure. The stored procedure is executed, however the contents of the log file are NOT being stored in the database.
I have ruled out the following possible causes:
connectivity/permissions - I have logged in to SSMS with the account used by the Talend job and executed the procedure (minus the XML header since I have not found a way to have SSMS allow UTF-8)
The stored procedure is:
ALTER procedure [myschema].[myProc]
#logXML as xml,
#logFile as varchar(max),
#result as varchar(max) OUT
as
begin
declare #myAction varchar(max);
begin try
begin transaction
set #myAction = 'inserting log file ' + #logFile;
insert into [myDB].[mySchema].[myTable]
(
JobName,
LogName,
RunDate,
LogLineNum,
LogLine
)
(select logs.value('JobName[1]', 'varchar(500)') as JobName,
logs.value('LogName[1]', 'varchar(500)') as LogName,
logs.value('runDate[1]', 'varchar(20)') as runDate,
lines.value('Number[1]', 'integer') as LogLineNum,
lines.value('Content[1]', 'varchar(max)') as LogLine
from #logXML.nodes('/LogFileContents') as l1(logs),
#logXML.nodes('/LogFileContents/LogLines/Line') as l2(lines)
);
commit transaction;
set #result = 'SUCCESS';
end try
begin catch
if ##TRANCOUNT > 0
begin
rollback
set #result = 'Error ' + #myAction + '. Error code: ' + ##ERROR;
end
end catch
end
The XML document generated by the Talend job looks like the following:
<?xml version="1.0" encoding="UTF-8"?> // I do not have control of this - I get this "free" from Talend
<LogFileContents>
<JobName>myTask</JobName>
<LogName>myLogFile</LogName>
<runDate>YYYYMMDDHHmiss</runDate>
<LogLines>
<Line>
<Number>1</Number>
<Content>1st Log Message</Content>
</Line>
<Line>
<Number>2</Number>
<Content>2nd Log Message</Content>
</Line>
...
<Line>
<Number>Last</Number>
<Content>Last Log Message</Content>
</Line>
</LogLines>
</LogFileContents>
In Talend I have tried passing the XML document to the tDBSP as a document (which results in a Talend Error). It is currently configured to pass the XML document as a String - I had to add the "sendStringParametersAsUnicode=false" to my connection string (additional parameters) to eliminate the "unable to switch encoding" error. When I check the result from the call to the stored proc I get "SUCCESS". I have even tried having the stored proc pass back a non-sense value for the result instead of "SUCCESS".
In the stored proc I have tried changing the input parameter to a varchar(max) and then converting that to an XML variable via
#logXML as varchar(max),
...
declare #myXML xml = convert(xml, #logXML)
...
from #myXML.nodes(...) as l1(logs)
#myXML.nodes(...) as l2(lines)
which also did not load the document into the database.
However if I execute the stored procedure via SSMS using the XML Document (only difference is the missing <?xml...> document header):
<LogFileContents>
<JobName>myTask</JobName>
<LogName>myLogFile</LogName>
<runDate>YYYYMMDDHHmiss</runDate>
<LogLines>
<Line>
<Number>1</Number>
<Content>1st Log Message</Content>
</Line>
<Line>
<Number>2</Number>
<Content>2nd Log Message</Content>
</Line>
...
<Line>
<Number>Last</Number>
<Content>Last Log Message</Content>
</Line>
</LogLines>
</LogFileContents>
The entire contents loads as expected (The log file I am testing with has 40 lines and all 40 show up in the database, exactly as I expect).
I have also reviewed the following links - but they are in regards to processing XML files, not XML strings.
Parsing XML Data Into SQL Server
Importing XML file into SQL Server 2000 using OPENROWSET
I feel like there's something not quite configured right in Talend but I'm not sure where that would be. Any input/guidance would be greatly appreciated.

Your XML shredding has no issues outside of performance.
Please see below.
So, it seems that the issue is some kind of environment related (Talend ?!).
SQL
DECLARE #logXML XML =
'<?xml version="1.0" encoding="UTF-8"?>
<LogFileContents>
<JobName>myTask</JobName>
<LogName>myLogFile</LogName>
<runDate>YYYYMMDDHHmiss</runDate>
<LogLines>
<Line>
<Number>1</Number>
<Content>1st Log Message</Content>
</Line>
<Line>
<Number>2</Number>
<Content>2nd Log Message</Content>
</Line>...
<Line>
<Number>10000</Number>
<Content>Last Log Message</Content>
</Line>
</LogLines>
</LogFileContents>';
SELECT logs.value('(JobName/text())[1]', 'varchar(500)') as JobName
, logs.value('(LogName/text())[1]', 'varchar(500)') as LogName
, logs.value('(runDate/text())[1]', 'varchar(20)') as runDate
, lines.value('(Number/text())[1]', 'integer') as LogLineNum
, lines.value('(Content/text())[1]', 'varchar(max)') as LogLine
FROM #logXML.nodes('/LogFileContents') as l1(logs)
, #logXML.nodes('/LogFileContents/LogLines/Line') as l2(lines);
Output
JobName
LogName
runDate
LogLineNum
LogLine
myTask
myLogFile
YYYYMMDDHHmiss
1
1st Log Message
myTask
myLogFile
YYYYMMDDHHmiss
2
2nd Log Message
myTask
myLogFile
YYYYMMDDHHmiss
10000
Last Log Message

So it seems that, even though I have a commit in the stored procedure, I still need an external (in Talend) commit (tDBCommit). From what I've been able to gather it has to do with the fact that I use a tDBConnection to establish the DB connection instead of configuring the tDBSP to make a connection to the DB.
Although I haven't tried it, I suspect that I could also set the "Auto Commit" property of the tDBConnection and that would work as well.

Related

loading xml File into SQL Server table is not working.

I have XML file that I am trying to load into SQL server but when I run the script, it is not displaying any rows.
<root>
<DeviceRecord xmlns="http://www.archer-tech.com/">
<IP>137.52</IP>
<FQDN>sdcww00</FQDN>
<NetBios_Name></NetBios_Name>
<Operating_System>Microsoft Windows Vista</Operating_System>
<Mac_Address></Mac_Address>
<Confidence_Level>65
</Confidence_Level>
</DeviceRecord>
<DeviceRecord xmlns="http://www.archer-tech.com/">
<IP>155.37.51</IP>
<FQDN>ww00048</FQDN>
<NetBios_Name></NetBios_Name>
<Operating_System>Microsoft Windows Vista</Operating_System>
<Mac_Address></Mac_Address>
<Confidence_Level>65
</Confidence_Level>
</DeviceRecord>
</root>
SQL Script
declare #xmldata as xml
set #xmldata= (SELECT CONVERT(XML, BulkColumn) AS BulkColumn
FROM OPENROWSET(BULK 'C:\Users\ag03536\Documents\New folder\updated.xml', SINGLE_BLOB)as X)
SELECT
x.Rec.query('./DeviceRecord').value('.','varchar(120)')
,x.Rec.query('./IP').value('.','varchar(20)')
,x.Rec.query('./FQDN').value('.','varchar(20)')
FROM #xmldata.nodes('./root') as x(rec)
First you have to check, whether the XML is read propperly. Use this after reading your XML into the variable:
SELECT #xmldata;
Secondly all your values live in a default namespace. You have to declare it:
WITH XMLNAMESPACES(DEFAULT 'http://www.archer-tech.com/')
Third, your query should read all nested <DeviceRecord> entries probably, you need .nodes() down to this level. The full query should be something like this:
WITH XMLNAMESPACES(DEFAULT 'http://www.archer-tech.com/')
SELECT
x.Rec.value('(IP/text())[1]','varchar(20)') AS DevRec_ID
,x.Rec.value('(FQDN/text())[1]','varchar(20)') AS DevRec_FQDN
--The rest should be the same approach...
FROM #xmldata.nodes('/*:root/DeviceRecord') as x(rec)
EDIT: Your node <root> is not part of the default namespace.
I used a wildcard (*:root)

An unexpected method call was made. Ensure that the XML is well formed. The stack trace of the method call was : Void WriteFullEndElement()

Using BizTalk I am trying to insert/update the table in the SQL Server database using the stored procedure. I have created a stored procedure and the Table Type like below
CREATE TYPE dbo.dept_TT AS TABLE
(
dept_name varchar(64),
jax_dept_id char(32)
)
GO
CREATE PROCEDURE [dbo].[uspInsertorUpdateDept]
#dept_TT dept_TT READONLY
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRANSACTION;
UPDATE dep
SET dep.dept_name = dtt.dept_name,
dep.jax_dept_id = dtt.jax_dept_id
FROM [afm].[jax_dept] dep
INNER JOIN #dept_TT dtt ON dep.jax_dept_id = dtt.jax_dept_id
INSERT INTO [afm].[jax_dept](dept_name, jax_dept_id )
SELECT dtt.dept_name, dtt.jax_dept_id
FROM #dept_TT dtt
WHERE NOT EXISTS (SELECT 1
FROM [afm].[jax_dept]
WHERE jax_dept_id = dtt.jax_dept_id)
COMMIT TRANSACTION;
END;
When I execute the stored produre in the SQL Server management studio it insert/updates the records as expected. I am consuming this storedprocedure in the biztalk application and tried to run the application it throws error like
The adapter failed to transmit message going to send port "WcfSendPort_SqlAdapterBinding_Procedures_dbo_Custom_Dep" with URL "mssql://". It will be retransmitted after the retry interval specified for this Send Port. Details:"Microsoft.ServiceModel.Channels.Common.XmlReaderParsingException: An unexpected method call was made. Ensure that the XML is well formed. The stack trace of the method call was : Void WriteFullEndElement().
I enabled the tracking and tried seeing the XML that is sent to the send port and it looks good like below.
<?xml version="1.0" encoding="utf-8"?>
<ns0:uspInsertorUpdateDept xmlns:ns0="http://schemas.microsoft.com/Sql/2008/05/Procedures/dbo" xmlns:ns4="http://schemas.datacontract.org/2004/07/System.Data" xmlns:ns3="http://schemas.microsoft.com/Sql/2008/05/Types/TableTypes/dbo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns0:dept_TT>
<ns3:dept_TT>
<ns3:dept_name>lab1</ns3:dept_name>
<ns3:jax_dept_id>RRI</ns3:jax_dept_id>
</ns3:dept_TT>
<ns3:dept_TT>
<ns3:dept_name>lab2</ns3:dept_name>
<ns3:jax_dept_id>RAFAC</ns3:jax_dept_id>
</ns3:dept_TT>
</ns0:dept_TT>
</ns0:uspInsertorUpdateDept>
Xml generated for the stored procedure in the VS
<ns0:uspInsertorUpdateDept xmlns:ns0="http://schemas.microsoft.com/Sql/2008/05/Procedures/dbo">
<ns0:dept_TT>
<ns1:dept_TT xmlns:ns1="http://schemas.microsoft.com/Sql/2008/05/Types/TableTypes/dbo">
<ns1:dept_name>dept_namedept_namedept_namedept_namedept_namedept_namedept_named</ns1:dept_name>
<ns1:jax_dept_id>jax_dept_idjax_dept_idjax_dept_i</ns1:jax_dept_id>
</ns1:dept_TT>
<ns1:dept_TT xmlns:ns1="http://schemas.microsoft.com/Sql/2008/05/Types/TableTypes/dbo">\
<ns1:dept_name>dept_namedept_namedept_namedept_namedept_namedept_namedept_named</ns1:dept_name>
<ns1:jax_dept_id>jax_dept_idjax_dept_idjax_dept_i</ns1:jax_dept_id>
</ns1:dept_TT>
<ns1:dept_TT xmlns:ns1="http://schemas.microsoft.com/Sql/2008/05/Types/TableTypes/dbo">
<ns1:dept_name>dept_namedept_namedept_namedept_namedept_namedept_namedept_named</ns1:dept_name>
<ns1:jax_dept_id>jax_dept_idjax_dept_idjax_dept_i</ns1:jax_dept_id>
</ns1:dept_TT>
</ns0:dept_TT>
</ns0:uspInsertorUpdateDept>
Not sure what am I missing here. Any help is greatly appreciated

The execution of a SP in SSIS returns nothing

Until now I've been looking for a possible solution to the execution of a sp from SSIS, but anything seems to work. I´ve got a sp:
CREATE PROCEDURE [DBO].[SPIDENTIFIERS] #IDENT NVARCHAR(MAX) OUTPUT
What I need is to save the result in a variable that I've created in SSIS.
This is the configuration that I used to try to do it.
In the parameter set section I have also used the Direction as Output or ReturnValue but I received a error message. Just to try I put a Script Task to chek the value, but as you can see this is empty.
With the Direction Ouput or ReturnValue I've got this:
[Execute SQL Task] Error: Executing the query "EXECUTE spIdentifiers ? OUTPUT;" failed with the following error:
"El valor no está dentro del intervalo esperado.".
Possible failure reasons: Problems with the query, "ResultSet" property not set correctly,
parameters not set correctly, or connection not established correctly.
What am I missing in the configuration of the task?.
I looked for an answer in this post. But nothing seems to work
How do you call a Stored Procedure in SSIS?
SSIS Stored Procedure Call
Thanks in advance.
Your parameter should not be named, as #gerald Davis has indicated. For a connection manager of OLEDB type, it should be ordinal based, thus 0
Here's my sample package and you can see that my variable #[User::MyVariables] is populated with a lot of Xs
Here's my proc definition
IF NOT EXISTS
(
SELECT
*
FROM
sys.procedures AS P
WHERE
P.name = N'SPIDENTIFIERS'
)
BEGIN
EXECUTE sys.sp_executesql N'CREATE PROC dbo.spidentifiers AS SELECT ''stub version, to be replaced''';
END
GO
ALTER PROCEDURE [DBO].[SPIDENTIFIERS]
(
#IDENT NVARCHAR(MAX) OUTPUT
)
AS
BEGIN
SET NOCOUNT ON;
SET #IDENT = REPLICATE(CAST(N'X' AS nvarchar(MAX)), 4001);
-- Uncomment this to watch the fireworks
--SET #IDENT = REPLICATE(CAST(N'X' AS nvarchar(MAX)), 4001);
END
Biml
I'm a big fan of using Biml, the Business Intelligence Markup Language, to describe my solutions as it allows the reader to recreate exactly the solution I describe without all those pesky mouse clicks.
Download BIDS Helper and install or unzip
Add a new biml file to your SSIS project
Fix the third line's ConnectionString to point to a valid server and database. Mine references localhost\dev2014 and tempdb
Right click on the saved biml file and generate package
Take your well deserved Biml break
Biml code follows
<Biml xmlns="http://schemas.varigence.com/biml.xsd">
<Connections>
<OleDbConnection Name="tempdb" ConnectionString="Provider=SQLNCLI11.1;Server=localhost\dev2014;Initial Catalog=tempdb;Integrated Security=SSPI;" />
</Connections>
<Packages>
<Package Name="so_30460630" ConstraintMode="Linear">
<Variables>
<Variable DataType="String" Name="MyVariables">0</Variable>
</Variables>
<Tasks>
<ExecuteSQL
ConnectionName="tempdb"
Name="SQL Ensure Objects Exist">
<DirectInput>
<![CDATA[IF NOT EXISTS
(
SELECT
*
FROM
sys.procedures AS P
WHERE
P.name = N'SPIDENTIFIERS'
)
BEGIN
EXECUTE sys.sp_executesql N'CREATE PROC dbo.spidentifiers AS SELECT ''stub version, to be replaced''';
END
GO
ALTER PROCEDURE [DBO].[SPIDENTIFIERS]
(
#IDENT NVARCHAR(MAX) OUTPUT
)
AS
BEGIN
SET NOCOUNT ON;
SET #IDENT = REPLICATE(CAST(N'X' AS nvarchar(MAX)), 4001);
END
]]>
</DirectInput>
</ExecuteSQL>
<ExecuteSQL
ConnectionName="tempdb"
Name="SQL Using an OUTPUT parameter">
<DirectInput>EXECUTE dbo.SPIDENTIFIERS ? OUTPUT;</DirectInput>
<Parameters>
<Parameter DataType="String" VariableName="User.MyVariables" Name="0" Direction="Output" Length="-1" />
</Parameters>
</ExecuteSQL>
<ExecuteSQL
ConnectionName="tempdb"
Name="SQL Breakpoint">
<DirectInput>SELECT NULL AS nothing;</DirectInput>
</ExecuteSQL>
</Tasks>
</Package>
</Packages>
</Biml>
Your stored procedure parameter is OUTPUT but your SSIS package defines it as INPUT. Depending on the application, RETURNVALUE could also be used but from the syntax of your SP it is using an Output Parameter not a Return Value.
Verify the User:Id variable has the correct datatype. Try executing the SP in SSMS manually to verify that it runs without error and returns the expected result.
Also I think you are mixing OLEDB and ADO.NET syntax.
If using an OLEDB Data connection then you use the ? parameters in the query and the Parameter names must be "Parameter0 (and Parameter1, etc if more than 1)". Note: parameter names are zero indexed. In SP with more than 1 parameter the correct order is required.
If using an ADO.NET DataConnection then the query is just the named of the stored procedure, IsStoredProcedure=True, and the Parameter names matches the name of the parameter in the SP.
From your screenshots you currently are using named parameters and OLDEDB ? syntax. I don't believe that is ever valid. It is one or the other depending on the connection type.
UserID needs to be in the readwritevariable section, not the read section, so that you allow the task to write into the variable.
parameter direction should be "output" since you are passing it out of your task not into it.
You need to keep the sql statement as "EXEC SPIDENTIFIERS ? OUTPUT**
direction of variable should be Output in parameter mapping tab and "Parameter Name" should be exactly same as of input parameter defined in stored procedure or you can just use 0 instead of giving the actual name.

CRM Auto Pre-filter doesn't pass a query

I've created a simple SSRS report using Visual Studio 2012,
I'm using CRMAF_ prefix to use CRM's auto filtering, and achieve a context-based report.
I'm using two datasets to achieve this; dsFiltered for the filtered data, and dsApprovalSummary for my report.
This is the query dsFiltered uses :
declare #sql as nVarchar(max)
set #sql = 'SELECT vrp_investdocumentid
FROM (' + #CRM_Filteredvrp_investdocument + ') as CRMAF_vrp_investdocument'
exec(#sql)
This is the query dsApprovalSummary uses :
select doc.vrp_name as 'Yatırım Dosyası',
act.vrp_actioncode as 'Aksiyon Kodu',
cfg.vrp_description as 'Aksiyon Açıklaması',
act.OwnerIdName as 'Aksiyon Sorumlusu',
act.ModifiedOn as 'Son Değiştirme Tarihi'
from vrp_action act
inner join vrp_investdocument as doc on act.RegardingObjectId=doc.vrp_investdocumentId
inner join vrp_actionconfig as cfg on act.vrp_actioncode = cfg.vrp_actioncode
where cfg.vrp_reporttask=1 and act.RegardingObjectId = #documentId
order by act.ModifiedOn
The parameters are :
#CRM_Filteredvrp_investdocument - The parameter CRM should have been populated with a query, defaults to null
#CRM_vrp_investdocumentId - Comes from dsFiltered (CRMAF_vrp_investdocument.vrp_investdocumentid); allows null.
The report works perfectly on the development server. However, when i deploy the report into the production server, it does not ask me to select a filter, or does not have a default filter; tries to run directly and then gives an rsProcessingAborted. I've checked the logs, and saw it said SYNTAX ERROR NEAR )-.
This is from the report server logs :
processing!ReportServer_0-20!13ec!11/11/2014-13:45:04:: w WARN: Data source 'srcApprovalSummary': Report processing has been aborted.
processing!ReportServer_0-20!13ec!11/11/2014-13:45:04:: e ERROR: Throwing Microsoft.ReportingServices.ReportProcessing.ProcessingAbortedException: ,
Microsoft.ReportingServices.ReportProcessing.ProcessingAbortedException: An error has occurred during report processing.
---> Microsoft.ReportingServices.ReportProcessing.ReportProcessingException: Query execution failed for dataset 'dsFiltered'.
---> System.Data.SqlClient.SqlException: Incorrect syntax near ')'
UPDATE : On the development server, we have everything installed on the same machine; CRM Frontend, Services, SQL Server, Report Server etc. But on the production environment, each one of these servers are different machines. Could this be the source of error?
UPDATE 2 : Running the profiler gave me that #CRM_Filteredvrp_investdocument comes in NULL. See the query below from the profiler :
exec sp_executesql N'declare #sql as nVarchar(max)
set #sql = ''SELECT vrp_investdocumentid
FROM ('' + #CRM_Filteredvrp_investdocument + '') as CRMAF_vrp_investdocument''
exec(#sql)',N'#CRM_Filteredvrp_investdocument nvarchar(4000)',#CRM_Filteredvrp_investdocument=NULL
It turns out to be a collation problem, i've been trying to use a custom data source with this connection string :
Data Source=myprodsqlserver; Initial Catalog=myorganization_MSCRM;
I've rewritten it lowercase, and replaced the data source with localhost the problem is magically gone.
data source=localhost; initial catalog=myorganization_MSCRM;
In the report editor, try rebuilding the datasource used by each of your datasets using the connection string builder (don't type it manually). Build them so they point to your Prod CRM database and then test the report completely in the report editor. This will determine if the problem is lies with the report or CRM.

extract xml element from database using sql query

Hello I have the following xml structure within a database table column :
DECLARE #Response XML =
'<star:ShowInfo xmlns="http://www.starstandard.org/STAR/5"
xmlns:ns2="http://www.openapplications.org/oagis/9"
xmlns:star="http://www.starstandard.org/STAR/5"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" releaseID="5.1.5"
xsi:noNamespaceSchemaLocation="">
<ShowDataArea>
<ServiceInfo>
<SVPlanInfo>
<AKStatus>
<Code>Error</Code>
<STText xsi:type="ns2:TextType">E12143 - Please fetch me from this xml </STText>
</AKStatus>
</SVPlanInfo>
</ServiceInfo>
</ShowDataArea></star:ShowInfo>'
In the above xml I need to fetch the STText value which is
E12143 - Please fetch me from this xml . Can anyone point me on how I can do it ?
I tried the following but it doesnt seem to work :
;WITH XMLNAMESPACES ('http://www.w3.org/2001/XMLSchema' as xsd,
'http://www.w3.org/2001/XMLSchema-instance' as xsi)
SELECT #Response.value('(/xsd:Response)[1]','nvarchar(500)') as ExceptionMessage
What a pain.
remove:
xmlns="http://www.starstandard.org/STAR/5"
It is not a sql issue, but rather namespace-getting-confused issue.
Its heplful totake SQL out the equation sometimes, by testing some place like
http://xpath.online-toolz.com/tools/xpath-editor.php.

Resources