I am trying to the get the value of the x:String node (L1.0.0.0) in XML below shown code sample. The XML in the sample is generated by the TFS 2010 when we queue the builds. The XML has two major nodes and Dictionary and x:String and I have tried the query similar to the other stack overflow thread and I have included that under additional research. Any one got any suggestions why my XQuery is not working?
DECLARE #XML XML;
SET #XML = '<Dictionary x:TypeArguments="x:String, x:Object"
xmlns="clr-namespace:System.Collections.Generic;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:String x:Key="GetVersion">L1.0.0.0</x:String>
</Dictionary>'
;WITH XMLNAMESPACES(
'clr-namespace:System.Collections.Generic;assembly=mscorlib' AS a,
'http://schemas.microsoft.com/winfx/2006/xaml' AS x)
SELECT #XML.value('(/Dictionary/x:String)[1]', varchar(100)) AS BuildLabel
Additional Research
Stack Overflow
T-SQL, XQuery Invalid Column
How to work with multiple namespaces
In your query you need to prefix Dictionary with a since clr-namespace:System.Collections.Generic;assembly=mscorlib is the default namespace and Dictionary belongs to that.
;WITH XMLNAMESPACES(
'clr-namespace:System.Collections.Generic;assembly=mscorlib' AS a,
'http://schemas.microsoft.com/winfx/2006/xaml' AS x)
SELECT #XML.value('(/a:Dictionary/x:String)[1]', 'varchar(100)') AS BuildLabel
Or you can specify the namespace as default in the query.
;WITH XMLNAMESPACES('http://schemas.microsoft.com/winfx/2006/xaml' as x,
DEFAULT 'clr-namespace:System.Collections.Generic;assembly=mscorlib')
SELECT #XML.value('(/Dictionary/x:String)[1]', 'varchar(100)') AS BuildLabel
Related
I'm playing around with the FOR JSON features in SQL Server 2019, and I'm struggling with how to use that feature to create a JSON list without keys... so like just a straight-up list of values.
For example, say I have this SQL:
declare #years table (year int)
insert into #years values (2022),(2021),(2020)
SELECT year
FROM #years
FOR JSON AUTO
This creates output like so:
[{"year":2022},{"year":2021},{"year":2020}]
But how would I get it to create output like THIS instead:
[2022,2021,2020]
And I'm looking to do this without messy nested string replaces... but maybe that's the only way? Thanks a lot for any help!
Please try the following solution.
It will work starting from SQL Server 2017 onwards.
SQL
DECLARE #tbl TABLE ([year] int);
INSERT INTO #tbl VALUES (2022),(2021),(2020);
SELECT json = QUOTENAME(STRING_AGG([year], ','))
FROM #tbl;
Output
json
[2022,2021,2020]
When using the below code the VS 2019 crashed without fail. Though it was originally working, possibly prior to a recent update (or upgrade to VS 2019 from VS 2017)
The error message implied a too long identifier and related to a specific file. I temp resolved this by accessing my project via Team Explorer as opposed to startup window. It resurfaced as soon as I edited the file. So I went line-by-line to find the culprit, the code below is the culprit. I cannot understand why it causes the crash.
DECLARE #Characteristics nvarchar(4000) = (SELECT * FROM OPENJSON(#Details)
WITH ([Firstname] nvarchar(256) N'$.firstname',[Lastname] nvarchar(256) N'$.lastname') FOR JSON PATH, WITHOUT_ARRAY_WRAPPER);
It's a legitimate command and SQL accepts including deployments. For my purposes and because I control the WITH clause, "SELECT *", is an acceptable deviation from my practice of stating the columns in the SELECT clause.
VS no longer crashes now that I declare each expected column in the SELECT clause. If somebody has an alternative resolution to solving this problem I would appreciate it.
You do not show enough - at least for me - to understand your issue completely...
What I get:
You want to use SELECT *
You are controlling the WITH clause (I assume: You build it dynamically in your application)
You did not show the actual error message (please do this the next time), but I get, that the error depends on the difference of
SELECT * FROM ...
SELECT Firstname, Lastname FROM ...
I cannot reproduce your issue, but I guess, that there are more sources involved in your actual statement and that * might include more than you tell us.
Did you try to use a table alias after the WITH?
DECLARE #Details NVARCHAR(MAX)=N'[{"a":"a1", "b":"b1"},{"a":"a2","b":"b2"}]';
SELECT
(
SELECT tbl.* --<-- Using "tbl.*" instead of "*"
FROM OPENJSON(#Details)
WITH(a NVARCHAR(100)
,b NVARCHAR(100)) tbl --<-- table alias "tbl"
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
);
We have a requirement of generating SSRS reports from where we need to convert multi-valued string and integer parameters to datatable and pass it to stored procedure. The stored procedure contains multiple table type parameters. Earlier we used varchar(8000) but it was also crossing the datatype limit. Then we thought to introducing datatable concept. But we were not aware of how to pass values from SSRS.
We found a solution from GruffCode on Using Table-Valued Parameters With SQL Server Reporting Services.
The solution solved my problem, and we're able to generate reports. However, sometimes SSRS returns the two following errors:
An error has occurred during report processing.
Query execution failed for dataset 'DSOutput'.
String or binary data would be truncated. The statement has been terminated.
And
An unexpected error occurred in Report Processing.
Exception of type 'System.OutOfMemoryException' was thrown.
I'm not sure when and where it's causing the issue.
The approach outlined in that blog post relies on building an enormous string in memory in order to load all of the selected parameter values into the table-valued parameter instance. If you are selecting a very large number of values to pass into the query I could see it potentially causing the 'System.OutOfMemoryException' while trying to build the string containing the insert statements that will load the parameter.
As for the 'string or binary data would be truncated' error that sounds like it's originating within the query or stored procedure that the report is using to gather its data. Without seeing what that t-sql looks like I couldn't say why that's happening, but I'd guess that it's also somehow related to selecting a very large number of parameter values.
Unfortunately I'm not sure that there's a workaround for this, other than trying to see if you could figure out a way to select fewer parameter values. Here's a couple of rough ideas:
If you have a situation where users might select a handful of parameter values or all parameter values then you could have the query simply take a very simple boolean value indicating that all values were selected rather than making the report send all of the values in through a parameter.
You could also consider "zooming out" of your parameter values a bit and grouping them together somehow if they lend themselves to that. That way users would be selecting from a smaller number of parameter values that represent a group of the individual values all rolled up.
I'm not a fan of using a Text parameter and EXEC in the SQL statement like the article you referenced describes as doing so is subject to SQL injection. The default SSRS behavior with a Multi-value parameter substitutes a comma-separated list of the values directly in place of the parameter when the query is sent to the SQL server. That works great for simple IN queries, but can be undesirable elsewhere. This behavior can be bypassed by setting the Parameter Value on the DataSet to an expression of =Join(Parameters!CustomerIDs.Value, ", "). Once you have done that you can get a table variable loaded by using the following SQL:
DECLARE #CustomerIDsTable TABLE (CustomerID int NOT NULL PRIMARY KEY)
INSERT INTO #CustomerIDsTable (CustomerID)
SELECT DISTINCT TextNodes.Node.value(N'.', N'int') AS CustomerID
FROM (
SELECT CONVERT(XML, N'<A>' + COALESCE(N'<e>' + REPLACE(#CustomerIDs, N',', N'</e><e>') + N'</e>', '') + N'</A>') AS pNode
) AS xmlDocs
CROSS APPLY pNode.nodes(N'/A/e') AS TextNodes(Node)
-- Do whatever with the resulting table variable, i.e.,
EXEC rpt_CustomerTransactionSummary #StartDate, #EndDate, #CustomerIDsTable
If using text instead of integers then a couple of lines get changed like so:
DECLARE #CustomerIDsTable TABLE (CustomerID nvarchar(MAX) NOT NULL PRIMARY KEY)
INSERT INTO #CustomerIDsTable (CustomerID)
SELECT DISTINCT TextNodes.Node.value(N'.', N'nvarchar(MAX)') AS CustomerID
FROM (
SELECT CONVERT(XML, N'<A>' + COALESCE(N'<e>' + REPLACE(#CustomerIDs, N',', N'</e><e>') + N'</e>', '') + N'</A>') AS pNode
) AS xmlDocs
CROSS APPLY pNode.nodes(N'/A/e') AS TextNodes(Node)
-- Do whatever with the resulting table variable, i.e.,
EXEC rpt_CustomerTransactionSummary #StartDate, #EndDate, #CustomerIDsTable
This approach also works well for handling user-entered strings of comma-separated items.
I am trying to get ancestor tags name using open xml in sql server 2008. Here is what i have tried so far:
SELECT * FROM OPENXML(#idoc, '/Envelope/Body/*/TagParent/Tag')
WITH (
[Name] varchar(max) '../#mp:parentLocalName'
)
I need to get the name of the 3rd tag,*. I can successfully run parentlocalname and localname, but nothing works for parent's parent.
I have tried many varients of above, it just errors out saying namespace mp is not defined. Is it even possible to fetch that name.
This is a little hacky, but should work, where ../../. is the path to whichever parent you're looking for.
SELECT Name.value('local-name((*)[1])','nvarchar(100)')
FROM OPENXML(#idoc, '/Envelope/Body/*/TagParent/Tag')
WITH (
[Name] xml '../../.'
)
Working example.
This query works fine in the query window of SQL Server 2005, but throws error when I run it in Execute SQL Task in the ssis package.
declare #VarExpiredDays int
Select #VarExpiredDays= Value1 From dbo.Configuration(nolock) where Type=11
DECLARE #VarENDDateTime datetime,#VarStartDateTime datetime
SET #VarStartDateTime= GETDATE()- #VarExpiredDays
SET #VarENDDateTime=GETDATE();
select #VarStartDateTime
select #VarENDDateTime
SELECT * FROM
(SELECT CONVERT(Varchar(11),#VarStartDateTime,106) AS VarStartDateTime) A,
(SELECT CONVERT(Varchar(11),#VarENDDateTime,106) AS VarENDDateTime) B
What is the issue here?
Your intention is to retrieve the values of start and end and assign those into SSIS variables.
As #Diego noted above, those two SELECTS are going to cause trouble. With the Execute SQL task, your resultset options are None, Single Row, Full resultset and XML. Discarding the XML option because I don't want to deal with it and None because we want rows back, our options are Single or Full. We could use Full, but then we'd need to return values of the same data type and then the processing gets much more complicated.
By process of elimination, that leads us to using a resultset of Single Row.
Query aka SQLStatement
I corrected the supplied query by simply removing the two aforementioned SELECTS. The final select can be simplified to the following (no need to put them into derived tables)
SELECT
CONVERT(Varchar(11),#VarStartDateTime,106) AS VarStartDateTime
, CONVERT(Varchar(11),#VarENDDateTime,106) AS VarENDDateTime
Full query used below
declare #VarExpiredDays int
-- I HARDCODED THIS
Select #VarExpiredDays= 10
DECLARE #VarENDDateTime datetime,#VarStartDateTime datetime
SET #VarStartDateTime= GETDATE()- #VarExpiredDays
SET #VarENDDateTime=GETDATE();
/*
select #VarStartDateTime
select #VarENDDateTime
*/
SELECT * FROM
(SELECT CONVERT(Varchar(11),#VarStartDateTime,106) AS VarStartDateTime) A,
(SELECT CONVERT(Varchar(11),#VarENDDateTime,106) AS VarENDDateTime) B
Verify the Execute SQL Task runs as expected. At this point, it simply becomes a matter of wiring up the outputs to SSIS variables. As you can see in the results window below, I created two package level variables StartDateText and EndDateText of type String with default values of an empty string. You can see in the Locals window they have values assigned that correspond to #VarExpiredDays = 10 in the supplied source query
Getting there is simply a matter of configuring the Result Set tab of the Execute SQL Task. The hardest part of this is ensuring you have a correct mapping between source system type and SSIS type. With an OLE DB connection, the Result Name has no bearing on what the column is called in the query. It is simply a matter of referencing columns by their ordinal position (0 based counting).
Final thought, I find it better to keep things in their base type, like a datetime data type and let the interface format it into a pretty, localized value.
you have more that one output type. You have two variables and one query.
You need to select only one on the "resultset" propertie
are you mapping these to the output parameters?
select #VarStartDateTime
select #VarENDDateTime