SELECT
CASE WHEN D.DocumentCode='SA' THEN D.Name END AS 'IDProofofsigningauthority',
CASE WHEN D.DocumentCode='GSTIN' THEN D.Name END AS 'GSTINRegistrationCopy',
CASE WHEN D.DocumentCode='SA_T' OR D.DocumentCode='SA_E' THEN D.Name END AS 'IDProofofsigningauthority',
CASE WHEN D.DocumentCode='PAN_T' THEN D.Name END AS 'PANCard',
CONCAT ('https://abc/xyz/',"Filename") AS KYCDocumentUrl,
CASE WHEN D.DocumentCode='GSTIN' THEN BPD.DocumentNumber END AS 'GSTINRegistrationCopyDocumentNumber',
CASE WHEN D.DocumentCode='PAN_T' THEN BPD.DocumentNumber END AS 'PANCardDocumentNumber'
FROM
[dbo].[Documents] D
INNER JOIN
[dbo].[BusinessPartyDcoument] BPD WITH (NOLOCK) ON D.Id = BPD.DocumentId
FOR XML PATH('Document')
This is my current output:
<Document>
<GSTINRegistrationCopy>GSTIN Number</GSTINRegistrationCopy>
<KYCDocumentUrl>https://abc/xyz/R1NUSU5fMTEy.pdf</KYCDocumentUrl>
<GSTINRegistrationCopyNumber>1111</GSTINRegistrationCopyNumber>
</Document>
<Document>
<PANCard>PAN Card</PANCard>
<KYCDocumentUrl>https://abc/xyz/UEFOX1RfNjFfOC8yLzIwMTkgN.pdf</KYCDocumentUrl>
<PANCardDocumentNumber>BBBBB1111V</PANCardDocumentNumber>
</Document>
<Document>
<IDProofauthority>ID Proof of signing authority</IDProofauthority>
<KYCDocumentUrl>https://abc/xyz/U0FfNjFfOC8yLzIwMTkgNjo1.pdf</KYCDocumentUrl>
</Document>
This is my desired output:
<GSTINRegistrationCopy>
<DocumentName>GSTIN Number</DocumentName>
<KYCDocumentUrl>https://abc/xyz/R1NUSU5fMTEy.pdf</KYCDocumentUrl>
<DocumentNumber>1111</DocumentNumber>
</GSTINRegistrationCopy>
<PANCard>
<DocumentName>PAN Card</DocumentName>
<KYCDocumentUrl>https://abc/xyz/UEFOX1RfNjFfOC8yLzIwMTkgN.pdf</KYCDocumentUrl>
<DocumentNumber>BBBBB1111V</DocumentNumber>
</PANCard>
<IDProofauthority>
<DocumentName>ID Proof of signing authority</DocumentName>
<KYCDocumentUrl>https://abc/xyz/U0FfNjFfOC8yLzIwMTkgNjo1.pdf</KYCDocumentUrl>
</IDProofauthority>
I need to get document name instead of <Document> tag as shown in the output using SQL Server query. I need to get expected XML output using my query.
Please suggest how to get this done.
Actually, you want nested xml for each "case" in you "case when".
You can use "for xml path" and "for xml path, type" in nested queries.
But this solution has obvious problems with performance, you can't use it for big amounts of data
declare #Document table
(
DocumentCode varchar(10),
Name varchar(100),
filename varchar(100),
DocumentNumber varchar(20)
)
insert into #document values
('PAN_T','PAN Card','UEFOX1RfNjFfOC8yLzIwMTkgN.pdf','BBBBB1111V'),
('GSTIN','GSTIN Number','R1NUSU5fMTEy.pdf','1111'),
('SA','D Proof of signing authority','U0FfNjFfOC8yLzIwMTkgNjo1.pdf',NULL);
SELECT
CASE WHEN D.DocumentCode='GSTIN' THEN
(
select D.Name 'DocumentName',
'https://abc/xyz/'+d.Filename 'KYCDocumentUrl',
D.DocumentNumber 'DocumentNumber'
for xml path('') ,type
) END GSTINRegistrationCopy
,CASE WHEN D.DocumentCode='PAN_T' THEN
(
select D.Name 'PANCard',
'https://abc/xyz/'+d.Filename 'KYCDocumentUrl',
D.DocumentNumber 'DocumentNumber'
for xml path('') ,type
) END PANCard
,CASE WHEN D.DocumentCode='SA' THEN
(
select D.Name 'DocumentName',
'https://abc/xyz/'+d.Filename 'KYCDocumentUrl'
for xml path('') ,type
) END IDProofauthority
FROM
#Document D
FOR XML PATH('')
(Similar to vitalygolub's answer...)
Given source data structured like the OPs:
if object_id('[dbo].[Documents]') is not null drop table [dbo].[Documents];
if object_id('[dbo].[BusinessPartyDcoument]') is not null drop table [dbo].[BusinessPartyDcoument];
select * into [dbo].[Documents]
from (values
(1, 'GSTIN', 'GSTIN Number'),
(2, 'PAN_T', 'PAN Card'),
(3, 'SA', 'ID Proof of signing authority')
) Src ([Id], [DocumentCode], [Name]);
select * into [dbo].[BusinessPartyDcoument]
from (values
(1, 'R1NUSU5fMTEy.pdf', '1111'),
(2, 'UEFOX1RfNjFfOC8yLzIwMTkgN.pdf', 'BBBBB1111V'),
(3, 'U0FfNjFfOC8yLzIwMTkgNjo1.pdf', null)
) Src ([DocumentId], [Filename], [DocumentNumber]);
The following SQL:
SELECT
(
SELECT
D.Name AS 'DocumentName',
DocumentUrl AS 'KYCDocumentUrl',
BPD.DocumentNumber AS 'DocumentNumber'
WHERE D.DocumentCode='GSTIN'
FOR XML PATH('GSTINRegistrationCopy'), TYPE
),
(
SELECT
D.Name AS 'DocumentName',
DocumentUrl AS 'KYCDocumentUrl',
BPD.DocumentNumber AS 'DocumentNumber'
WHERE D.DocumentCode='PAN_T'
FOR XML PATH('PANCard'), TYPE
),
(
SELECT
D.Name AS 'DocumentName',
DocumentUrl AS 'KYCDocumentUrl'
WHERE D.DocumentCode='SA'
FOR XML PATH('IDProofofsigningauthority'), TYPE
)
FROM
[dbo].[Documents] D
INNER JOIN
[dbo].[BusinessPartyDcoument] BPD WITH (NOLOCK) ON D.Id = BPD.DocumentId
OUTER APPLY (
SELECT DocumentUrl = CONCAT('https://abc/xyz/', "Filename")
) DU
FOR XML PATH('');
Outputs the following XML:
<GSTINRegistrationCopy>
<DocumentName>GSTIN Number</DocumentName>
<KYCDocumentUrl>https://abc/xyz/R1NUSU5fMTEy.pdf</KYCDocumentUrl>
<DocumentNumber>1111</DocumentNumber>
</GSTINRegistrationCopy>
<PANCard>
<DocumentName>PAN Card</DocumentName>
<KYCDocumentUrl>https://abc/xyz/UEFOX1RfNjFfOC8yLzIwMTkgN.pdf</KYCDocumentUrl>
<DocumentNumber>BBBBB1111V</DocumentNumber>
</PANCard>
<IDProofofsigningauthority>
<DocumentName>ID Proof of signing authority</DocumentName>
<KYCDocumentUrl>https://abc/xyz/U0FfNjFfOC8yLzIwMTkgNjo1.pdf</KYCDocumentUrl>
</IDProofofsigningauthority>
Related
Lets say I have table T with one column A.
What I would like to achieve as result is xml like this :
<not>
<mes>not important what include</mes>
<A>1</A>
<A>2</A>
<A>3</A>
<A>4</A>
...
</not>
Was trying something similar to :
SELECT
'important' AS [mes],
(select A as [A] from T)- of course that part is incorrect but don't know how to handle it
FROM T2
FOR XML PATH ('not');
Please advice.
Updated QUERY
SET #SQL = '
WITH XMLNAMESPACES (''https://something..'' as ns)
SELECT
Q.DocumentType AS [#type],
Q.ReferenceNo AS [#ref],
Q.Id AS [#id],
D.DocId AS [#docId],
N.NotId AS [#notId],
CONVERT(char(10), N.CreationDate, 126) AS [#notdate],
''mes'' AS [mes/#content],
#mes2 AS [mes/content],
[mes] = ''important'' ,
(select A from '+ Cast(#TableName as VARCHAR(60))+' FOR XML PATH (''''), type)
FROM
[DB].[dbo].[tab1] AS Q
LEFT JOIN [DB].[dbo].[tab2] AS D ON Q.ID=D.ID
LEFT JOIN [DB].[dbo].[tab3] AS N ON D.ID=N.DocId
WHERE
Q.ID='+ Cast(#Id as varchar(15))+'
FOR XML PATH (''not'')';
execute (#SQL);
Perhaps this will help
-- Just a DEMONSTRATIVE Table Variable
--------------------------------------------
Declare #YourTable Table ([A] varchar(50))
Insert Into #YourTable Values
(1)
,(2)
,(3)
,(4)
SELECT [mes] = 'important'
,( Select A from #YourTable For XML Path(''),type )
FOR XML PATH ('not');
Results
<not>
<mes>important</mes>
<A>1</A>
<A>2</A>
<A>3</A>
<A>4</A>
</not>
I try to join a list of ids from a xml stored in a column with ids from a column in another table. How can I extract them to get the matching rows.
I cant change the table. The schema can be reduced as:
CREATE TABLE abc([Data] [ntext] NOT NULL, [Group] varchar(3));
INSERT INTO abc
([Data], [Group])
VALUES
('<div>
<test name="Test1" enabled="True"/>
<ul>
<i><a id="t.foo"/></i>
<i><a id="t.bar"/></i>
</ul>
</div>', 'ADG')
;
GO
CREATE TABLE ForgeRock
([productName] varchar(13), [description] varchar(57), [Group] varchar(3))
INSERT INTO ForgeRock ([productName], [description], [Group])
VALUES
('foo', 'Platform for building enterprise provisioning solutions', 'ADG'),
('bar', 'Full-featured access management', 'ADG'),
('taz', 'Robust LDAP server for Java', 'ADG')
;
And here is the query I wrote:
SELECT
[productName]
, [description]
FROM ForgeRock
INNER JOIN abc on ForgeRock.[Group] = abc.[Group]
WHERE cast(abc.[Data] as xml).exist('//div/test[#name="Test1" and #enabled="True"]') = 1
AND ('t.' + productName) LIKE ('%' + cast(abc.[Data] as xml).value('(//ul/i/a/#id)[1]', 'varchar(50)') + '%')
I know that the problem come from the last line, but I am not sure how to tackle the problem.
The actual output is:
productName description
foo Platform for building enterprise provisioning solutions
But the expected output should be:
productName description
foo Platform for building enterprise provisioning solutions
bar Full-featured access management
I tried two solutions from SO (no they are not duplicated as far as I tried):
XQuery [value()]: 'value()' requires a singleton (or empty sequence), found operand of type 'xdt:untypedAtomic *'
Extracting Attributes from XML Fields in SQL Server 2008 Table
Try it Online
I would personally use STUFF to remove the 2 leading characters, and then compare, rather than a LIKE. I also, for my tests, have changed the data type of the column Data to xml as it is storing XML data, and ntext has been deprecated for 15~ years:
SELECT *
FROM dbo.ForgeRock FR
WHERE EXISTS (SELECT 1
FROM dbo.abc a
CROSS APPLY a.[Data].nodes('/div/ul/i/a') i(a)
WHERE STUFF(i.a.value('#id','varchar(15)'),1,2,'') = FR.productName);
db<>fiddle
Please try the following solution.
I used NVARCHAR(MAX) data type instead of NTEXT. You may need to adjust the finalSELECT clause columns to accommodate your needs. I picked all of them just to show the all column values.
SQL
DECLARE #abc TABLE (xmldata NVARCHAR(MAX) NOT NULL, [Group] CHAR(3));
INSERT INTO #abc (xmldata, [Group]) VALUES
(N'<div>
<test name="Test1" enabled="True"/>
<ul>
<i>
<a id="t.foo"/>
</i>
<i>
<a id="t.bar"/>
</i>
</ul>
</div>', 'ADG');
DECLARE #ForgeRock TABLE ([productName] VARCHAR(13), [description] VARCHAR(57), [Group] char(3));
INSERT INTO #ForgeRock ([productName], [description], [Group]) VALUES
('foo', 'Platform for building enterprise provisioning solutions', 'ADG'),
('bar', 'Full-featured access management', 'ADG'),
('taz', 'Robust LDAP server for Java', 'ADG');
;WITH rs AS
(
SELECT [Group], TRY_CAST(xmldata AS XML) AS xmldata
FROM #abc
)
SELECT rs.[Group], c.value('.', 'VARCHAR(30)') AS id
, f.*
FROM rs
CROSS APPLY xmldata.nodes('div[test[#name="Test1" and #enabled="True"]]/ul/i/a/#id') AS t(c)
INNER JOIN #ForgeRock AS f ON rs.[Group] = f.[Group]
AND SUBSTRING(c.value('.', 'VARCHAR(30)'), 3, 100) = f.productName;
Here is a pretty straightforward approach:
DECLARE #abc table ( [Data] [ntext] NOT NULL, [Group] varchar(3) );
INSERT INTO #abc ( [Data], [Group] ) VALUES
( '<div><test name="Test1" enabled="True"/><ul><i><a id="t.foo"/></i><i><a id="t.bar"/></i></ul></div>', 'ADG' );
DECLARE #ForgeRock table ( [productName] varchar(13), [description] varchar(57), [Group] varchar(3) );
INSERT INTO #ForgeRock ( [productName], [description], [Group] ) VALUES
('foo', 'Platform for building enterprise provisioning solutions', 'ADG'),
('bar', 'Full-featured access management', 'ADG'),
('taz', 'Robust LDAP server for Java', 'ADG');
SELECT
[productName], [description], x.f.value( '#id', 'VARCHAR(13)' ) AS id
FROM #ForgeRock ForgeRock
INNER JOIN #abc abc
ON ForgeRock.[Group] = abc.[Group]
CROSS APPLY ( SELECT CAST( abc.[data] AS xml ) AS x ) cx
CROSS APPLY cx.x.nodes( 'div[test[#name="Test1" and #enabled="True"]]/ul/i/a' ) x(f)
WHERE
x.f.value( '#id', 'VARCHAR(13)' ) LIKE '%' + productName + '%';
Returns
+-------------+---------------------------------------------------------+-------+
| productName | description | id |
+-------------+---------------------------------------------------------+-------+
| foo | Platform for building enterprise provisioning solutions | t.foo |
| bar | Full-featured access management | t.bar |
+-------------+---------------------------------------------------------+-------+
Optionally, you can pass your #name value in as a SQL variable:
DECLARE #name varchar(50) = 'Test1';
SELECT
[productName], [description], x.f.value( '#id', 'VARCHAR(13)' ) AS id
FROM #ForgeRock ForgeRock
INNER JOIN #abc abc
ON ForgeRock.[Group] = abc.[Group]
CROSS APPLY ( SELECT CAST( abc.[data] AS xml ) AS x ) cx
CROSS APPLY cx.x.nodes( 'div[test[#name=sql:variable("#name") and #enabled="True"]]/ul/i/a' ) x(f)
WHERE
x.f.value( '#id', 'VARCHAR(13)' ) LIKE '%' + productName + '%';
Table Name : sample
Column Name : id,name
Every Row Create Separate tag with inside.
Show the Xml value like this
<Details>
<id>1</id>
<name>na</name>
<Details>
<id>2</id>
<name>aa</name>
</Details>
</Details>
I tried like this but its not working
select
id 'Details\id'
,name 'Details\name'
from sample
How do get that xml output?
It is hardcoded but should work:
DECLARE #x xml
SELECT #x = (
SELECT x+''
FROM (
SELECT '%details?%id?'+CAST(id as nvarchar(max))+'%/id?%name?'+name+'%/name?' x
FROM [sample] s
UNION ALL
SELECT '%/details?'
FROM [sample] s
) as t
FOR XML PATH('')
)
SELECT CAST(REPLACE(REPLACE((CAST(#x as nvarchar(max))),'%','<'),'?','>') as xml)
In [sample] table I got:
(1,'na'),
(2,'aa'),
(3,'sd')
Output:
<details>
<id>1</id>
<name>na</name>
<details>
<id>2</id>
<name>aa</name>
<details>
<id>3</id>
<name>sd</name>
</details>
</details>
</details>
EDIT
Also it could be done with recursive CTE:
DECLARE #x xml
;WITH rec AS (
SELECT CAST((
SELECT TOP 1 id,
[name]
FROM [sample]
ORDER BY id DESC
FOR XML PATH('details')
) as xml) as d,
1 as [Level]
UNION ALL
SELECT CAST((
SELECT id,
[name],
cast(r.d as xml)
FROM [sample]
WHERE s.id = id
FOR XML PATH('details')
) as xml) as d,
r.[Level]+1
FROM [sample] s
INNER JOIN rec r
ON s.id = CAST(r.d.query('/details/id/text()') as nvarchar(max))-1
)
SELECT TOP 1 WITH TIES d
FROM rec
ORDER BY [Level] desc
Same output.
You can use query like this:
SELECT
*,
(SELECT
*
FROM #details
WHERE id = 2
FOR xml PATH ('Details'), TYPE)
FROM #details
WHERE id = 1
FOR xml PATH ('Details')
For inner loop you can use CTE
Table creation scripts :
CREATE TABLE #details (
id int,
name varchar(10)
)
INSERT INTO #details (id, name)
VALUES (1, 'test'), (2, 'test2')
I am trying to create a structure xml document from my temp table .The temp table is in the following format .
CREATE TABLE #Temp1 ( Name Char( 30 ), seqid integer, salary int );
INSERT INTO #Temp1 VALUES('DEAL' ,123,6)
INSERT INTO #Temp1 VALUES('DEAL' ,56,6)
INSERT INTO #Temp1 VALUES('TRACNHE' ,1253,56)
INSERT INTO #Temp1 VALUES('TRACNHE' ,5,65)
INSERT INTO #Temp1 VALUES('ASSET' ,56,23)
I am trying to create an xml format in the following form :
<Response>
<Deal>
<seqid="123" salary="6" />
<seqid="56" salary="6" />
<Deal>
<TRACNHE>
<seqid="1253" salary="56"/>
<seqid="5" salary="65"/>
</TRACNHE>
<ASSET>
<seqid="56" salary="23"/>
</ASSET>
</Response>
SELECT Name, (SELECT SEQID FROM #TEMP1 T WHERE T.Name = T1.Name)
FROM (SELECT DISTINCT NAME FROM #TEMP1 ) T1
FOR XML PATH('rEPONSE')
DROP TABLE #Temp1
DROP TABLE #Temp1
I tried the above query but says that subquery returned more than 1 value
Could you let me know as to what i am missing in this query .
Is there a better way to handle this scenario.
Thanks in advance
based on your requirement, i'm seeing there are 2 types of complexities
You are trying to get the xml with grouped items.
For each group trying to create an xml element with two attributes
without any proper name
<seqid="1253" salary="56"/>
instead of
<ss seqid="1253" salary="56"/>
just look into this below query, it may help
SELECT
(SELECT
seqid 'ss/#seqid'
, salary 'ss/#salary'
FROM Temp1 as t where t.Name = 'Deal'
FOR XML PATH('Deal') , TYPE
) ,
(SELECT
seqid 'ss/#seqid'
, salary 'ss/#salary'
FROM Temp1 as t where t.Name = 'TRACNHE'
FOR XML PATH('TRACNHE') , TYPE
) ,
(SELECT
seqid 'ss/#seqid'
, salary 'ss/#salary'
FROM Temp1 as t where t.Name = 'ASSET'
FOR XML PATH('ASSET') , TYPE
)
FOR XML PATH(''), ROOT('Response');
I am using SSMS 2008 with the following query:
DECLARE #TestData TABLE
(
address_desc NVARCHAR(100) NULL
,people_id UNIQUEIDENTIFIER NULL
);
INSERT #TestData
SELECT a.address_desc, a.people_id
FROM dbo.address_view a
SELECT a.people_id,
(SELECT SUBSTRING(
(SELECT ';'+b.address_desc
FROM #TestData b
WHERE a.people_id = b.people_id
FOR XML PATH(''))
,2
,4000)
) GROUP_CONCATENATE
FROM #TestData a
GROUP BY a.people_id
This query works, but I want to make this into a view or function so that I can call it from different stored procs. How can I do this? From what I understand, variables cannot be declared in VIEW statements.
Hong, here is my updated query based on your advice which gives me errors:
DECLARE #TestData TABLE
(
address_desc NVARCHAR(100) NULL
,people_id UNIQUEIDENTIFIER NULL
);
INSERT #TestData
SELECT a.address_desc, a.people_id FROM dbo.address_view a
SELECT a.people_id,
(SELECT address_desc, people_id FROM dbo.address_view),
(SELECT SUBSTRING(
(SELECT ';'+b.address_desc
FROM #TestData b
WHERE a.people_id = b.people_id
FOR XML PATH(''))
,2
,4000)
) GROUP_CONCATENATE
FROM #TestData a
GROUP BY a.people_id
In your last select query replace #TestData with subquery (SELECT address_desc, people_id FROM dbo.address_view), and then get rid of temp table #TestData.
Try this:
Create View YourView As
SELECT a.people_id,
(SELECT SUBSTRING(
(SELECT ';'+b.address_desc
FROM (SELECT address_desc, people_id FROM dbo.address_view) b
WHERE a.people_id = b.people_id
FOR XML PATH(''))
,2
,4000)
) GROUP_CONCATENATE
FROM (SELECT address_desc, people_id FROM dbo.address_view) a
GROUP BY a.people_id