How to query for rows along with their xml representation? - sql-server

I need something like
select * from tb_listings for xml auto
But I need every row to be separate, and not one big xml document.
I have tried something like the following:
select id, (select * from tb_listings a where a.id=id for xml auto) as xmldata from tb_listings
Expected output is like:
id xmldata
------------------------------------------------------------
1 <listing><name>ABC</name><xyz>123</xyz></listing>
But it doesn't seem to do what I want and it also takes a very long time to run.
Any ideas would be appreciated. :)
Edit: Figured it out:
select id, (select top 1 * from tb_listings a where a.id=b.id for xml auto) from tb_listings b
Closing.

try something like this:
DECLARE #YourTable table (PK1 int, c1 int, c2 varchar(5), c3 datetime)
INSERT INTO #YourTable VALUES (1,2,'abcde','1/1/2009')
INSERT INTO #YourTable VALUES (100,200,'zzz','12/31/2009 23:59:59')
--list all columns in xml format
SELECT
t2.PK1 --optional, can remove this column from the result set and just get the XML
,(SELECT
*
FROM #YourTable t1
WHERE t1.PK1= t2.PK1
FOR XML PATH('YourTable'), TYPE
) as Row
FROM #YourTable t2
OUTPUT:
PK1 Row
----------- ------------------------------------------------------------------------------------------
1 <YourTable><PK1>1</PK1><c1>2</c1><c2>abcde</c2><c3>2009-01-01T00:00:00</c3></YourTable>
100 <YourTable><PK1>100</PK1><c1>200</c1><c2>zzz</c2><c3>2009-12-31T23:59:59</c3></YourTable>
(2 row(s) affected)

Related

Multiple XML tag value into single column with comma separator

I have an XML where the XML have multiple similar tag and I want this value need to show in one column with comma separator and insert into table.
For example:
<test xmlns="http://www.google.com">
<code>a</code>
<code>b</code>
<code>c</code>
</test>
Since XML is too large and I am using OPENXML to perform operation and insert that value into particular table.
I am performing like
insert into table A
(
code
)
select Code from OPENXML(sometag)
with (
code varchar(100) 'tagvalue'
)
for XQUERY I am using something like this: 'for $i in x:Code return concat($i/text()[1], ";")' and I want same with OPENXML.
Output: I want code tag value into one column like a,b,c or a/b/c.
Since you're on SQL Server 2017 you could use STRING_AGG (Transact-SQL) to concatenate your code values, e.g.:
create table dbo.Test (
someTag xml
);
insert dbo.Test (someTag) values
('<test><code>a</code><code>b</code><code>c</code></test>'),
('<test><code>d</code><code>e</code><code>f</code></test>');
select [Code], [someTag]
from dbo.Test
outer apply (
select [Code] = string_agg([value], N',')
from (
select n1.c1.value('.', 'nvarchar(100)')
from someTag.nodes(N'/test/code') n1(c1)
) src (value)
) a1;
Which yields...
Code someTag
a,b,c <test><code>a</code><code>b</code><code>c</code></test>
d,e,f <test><code>d</code><code>e</code><code>f</code></test>
Just a small tweak to AlwaysLearning (+1)
Example
Declare #YourTable table (ID int,XMLData xml)
insert Into #YourTable values
(1,'<test><code>a</code><code>b</code><code>c</code></test>')
Select A.ID
,B.*
From #YourTable A
Cross Apply (
Select DelimString = string_agg(xAttr.value('.','varchar(max)'),',')
From A.XMLData.nodes('/test/*') xNode(xAttr)
) B
Returns
ID DelimString
1 a,b,c
And just for completeness, here is method #3 via pure XQuery and FLWOR expression.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, xmldata xml);
INSERT #tbl (xmldata) VALUES
('<test xmlns="http://www.google.com"><code>a</code><code>b</code><code>c</code></test>'),
('<test xmlns="http://www.google.com"><code>d</code><code>e</code><code>f</code></test>');
-- DDL and sample data population, end
DECLARE #separator CHAR(1) = ',';
-- Method #3
-- SQL Server 2005 onwards
;WITH XMLNAMESPACES (DEFAULT 'http://www.google.com')
SELECT ID
, xmldata.query('for $i in /test/code
return if ($i is (/test/code[last()])[1]) then string($i)
else concat($i, sql:variable("#separator"))')
.value('.', 'NVARCHAR(MAX)') AS [Comma_separated_list]
FROM #tbl;
Output
+----+----------------------+
| ID | Comma_separated_list |
+----+----------------------+
| 1 | a, b, c |
| 2 | d, e, f |
+----+----------------------+

How to get an xml attribute value from a table's column in a select list

DECLARE #xml AS XML
SET #xml = CONVERT(xml,'<data><UserType userID="123">employee</UserType></data>')
SELECT (SELECT d.value('#userID', 'int')
FROM #xml.nodes('//data/UserType') T(d))
I have a table where the column is like the XML above. Is it possible to get the #userID value in a select statement?
In my Users table, the column 'XmlData' is of type XML.
SELECT
userID -- u.XmlData
FROM Users u
How can I grab the userID attribute from the xml in a select statement? I know how to parse it once, but not in a select.
You knit those together with APPLY. Something like:
SELECT
u.*,
SELECT T.d.value('#userID', 'int') userID
FROM Users u
CROSS APPLY u.XmlData.nodes('/data/UserType') T(d)
Same idea like John Cappelletti, just with CTE for conversion to XML.
SQL
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, XMLData NVARCHAR(MAX));
INSERT INTO #tbl (XMLData)
VALUES
(N'<data><UserType userID="123">employee</UserType></data>');
;WITH rs AS
(
SELECT *, TRY_CAST(XMLData AS XML) AS xml_data FROM #tbl
)
SELECT ID
, col.value('#userID','INT') AS userID
FROM rs
CROSS APPLY rs.[xml_Data].nodes('/data/UserType') AS tab(col);
Output
+----+--------+
| ID | userID |
+----+--------+
| 1 | 123 |
+----+--------+
With a little twist.
Example
Declare #YourTable table (ID int,XMLData nvarchar(max))
Insert Into #YourTable values
(1,'<data><UserType userID="123">employee</UserType></data>')
Select A.ID
,C.*
From #YourTable A
Cross Apply ( values (convert(XML,XMLData) )) B(XData)
Cross Apply ( Select UserID = d.value('#userID', 'int')
From XData.nodes('/data/UserType') T(d)
) C
Returns
ID UserID
1 123
Update If only ONE User ID in the XML
Declare #YourTable table (ID int,XMLData nvarchar(max))
Insert Into #YourTable values
(1,'<data><UserType userID="123">employee</UserType></data>')
Select A.ID
,UserID = convert(XML,XMLData).value('/data[1]/UserType[1]/#userID', 'int')
From #YourTable A

Joining with Temp table outside XML element

I am new to XML+SQL module and I have a code that selects a regular column and a whole bunch of XML data.
Below is my sample code:
create table #temp(cid int, val int)
insert into #temp values
(1,11),
(2,12),
(3,12)
select
t1.cid,
xml =
(
select t2.cid,t2.val
from #temp t2
join #temp t1 on t2.cid = t1.cid
for xml Path(''), type)
from #temp t1
drop table #temp
desired output is:
Rexter link: http://rextester.com/HLZS59752
Any help ??
If I understand your question.
Example
select
t1.cid,
xml = (Select t1.* for xml path('') )
from #temp t1
Returns
cid xml
1 <cid>1</cid><val>11</val>
2 <cid>2</cid><val>12</val>
3 <cid>3</cid><val>12</val> -- Last record in #temp is (3,12)
Thanks #John Cappelletti for that answer. That helped. One mroe solution I found was:
select
t1.cid,
xml =
(
select t2.cid,t2.val
from #temp t2
where t1.cid = t2.cid
for xml Path(''), type)
from #temp t1
Instead of join, I added the condition in Where clause and it worked.
Updated Rexter link: http://rextester.com/MGXDC39580

PATINDEX all values of a column

I'm making a query that will delete all rows from table1 that has its column table1.id = table2.id
table1.id column is in nvarchar(max) with an xml format like this:
<customer><name>Paulo</name><gender>Male</gender><id>12345</id></customer>
EDIT:
The id column is just a part of a huge XML so the ending tag may not match the starting tag.
I've tried using name.nodes but it only applies to xml columns and changing the column datatype is not a choice, So far this is the my code using PATINDEX
DELETE t1
FROM table1 t1
WHERE PATINDEX('%12345%',id) != 0
But what I need is to search for all values from table2.id which contains like this:
12345
67890
10000
20000
30000
Any approach would be nice like sp_executesql and/or while loop, or is there a better approach than using patindex? thanks!
Select *
--Delete A
From Table1 A
Join Table2 B on CharIndex('id>'+SomeField+'<',ID)>0
I don't know the name of the field in Table2. I am also assuming it is a varchar. If not, cast(SomeField as varchar(25))
EDIT - This is what I tested. It should work
Declare #Table1 table (id varchar(max))
Insert Into #Table1 values
('<customer><name>Paulo</name><gender>Male</gender><id>12345</id></customer>'),
('<customer><name>Jane</name><gender>Femail</gender><id>7895</id></customer>')
Declare #Table2 table (SomeField varchar(25))
Insert into #Table2 values
('12345'),
('67890'),
('10000'),
('20000'),
('30000')
Select *
--Delete A
From #Table1 A
Join #Table2 B on CharIndex('id>'+SomeField+'<',ID)>0
;with cteBase as (
Select *,XMLData=cast(id as xml) From Table1
)
Select *
From cteBase
Where XMLData.value('(customer/id)[1]','int') in (12345,67890,10000,20000,30000)
If you are satisfied with the results, change the final Select * to Delete

how to remove duplicate rows from a table in SQL Server [duplicate]

This question already has answers here:
How can I remove duplicate rows?
(43 answers)
Closed 9 years ago.
I have a table called table1 which has duplicate values. It looks like this:
new
pen
book
pen
like
book
book
pen
but I want to remove the duplicated rows from that table and insert them into another table called table2.
table2 should look like this:
new
pen
book
like
How can I do this in SQL Server?
Let's assume the field was named name:
INSERT INTO table2 (name)
SELECT name FROM table1 GROUP BY name
that query would get you all the unique names.
You could even put them into a table variable if you wanted:
DECLARE #Table2 TABLE (name VARCHAR(50))
INSERT INTO #Table2 (name)
SELECT name FROM table1 GROUP BY name
or you could use a temp table:
CREATE TABLE #Table2 (name VARCHAR(50))
INSERT INTO #Table2 (name)
SELECT name FROM table1 GROUP BY name
You can do this easily with a INSERT that SELECTs from a CTE where you use ROW_NUMBER(), like:
DECLARE #YourTable table (YourColumn varchar(10))
DECLARE #YourTable2 table (YourColumn varchar(10))
INSERT INTO #YourTable VALUES ('new')
INSERT INTO #YourTable VALUES ('pen')
INSERT INTO #YourTable VALUES ('book')
INSERT INTO #YourTable VALUES ('pen')
INSERT INTO #YourTable VALUES ('like')
INSERT INTO #YourTable VALUES ('book')
INSERT INTO #YourTable VALUES ('book')
INSERT INTO #YourTable VALUES ('pen')
;WITH OrderedResults AS
(
SELECT
YourColumn, ROW_NUMBER() OVER (PARTITION BY YourColumn ORDER BY YourColumn) AS RowNumber
FROM #YourTable
)
INSERT INTO #YourTable2
(YourColumn)
SELECT YourColumn FROM OrderedResults
WHERE RowNumber=1
SELECT * FROM #YourTable2
OUTPUT:
YourColumn
----------
book
like
new
pen
(4 row(s) affected)
You can do this easily with a DELETE on a CTE where you use ROW_NUMBER(), like:
--this will just remove them from your original table
DECLARE #YourTable table (YourColumn varchar(10))
INSERT INTO #YourTable VALUES ('new')
INSERT INTO #YourTable VALUES ('pen')
INSERT INTO #YourTable VALUES ('book')
INSERT INTO #YourTable VALUES ('pen')
INSERT INTO #YourTable VALUES ('like')
INSERT INTO #YourTable VALUES ('book')
INSERT INTO #YourTable VALUES ('book')
INSERT INTO #YourTable VALUES ('pen')
;WITH OrderedResults AS
(
SELECT
YourColumn, ROW_NUMBER() OVER (PARTITION BY YourColumn ORDER BY YourColumn) AS RowNumber
FROM #YourTable
)
DELETE OrderedResults
WHERE RowNumber!=1
SELECT * FROM #YourTable
OUTPUT:
YourColumn
----------
new
pen
book
like
(4 row(s) affected)
I posted something on deleting duplicates a couple of weeks ago by using DELETE TOP X. Only for a single set of duplicates obviously. However in the comments I was given this little jewel by Joshua Patchak.
;WITH cte(rowNumber) AS
(SELECT ROW_NUMBER() OVER (PARTITION BY [List of Natural Key Fields]
ORDER BY [List of Order By Fields])
FROM dbo.TableName)
DELETE FROM cte WHERE rowNumber>1
This will get rid of all of the duplicates in the table.
Here is the original post if you want to read the discussion. Duplicate rows in a table.

Resources