TSQL select from XML - sql-server

I have a stored procedure that looks like the following:
SELECT
ParamValues.x1.value('likeID[1]', 'VARCHAR(60)'),
COUNT(B.[userID]) AS totalLikes
FROM
#likeXML.nodes('/likes/like') AS ParamValues(x1)
JOIN
apsLikes AS B ON B.[likeID] = ParamValues.x1.value('likeID[1]', 'VARCHAR(60)')
FOR XML PATH ('likeData'), TYPE, ELEMENTS, ROOT ('root');
However this returns an error
Column 'ParamValues.x1' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
When I try and add it to the group by it says XML cannot be used in the group by clause.
What would be the correct way to format this?

Have you tried maybe using a CTE? Give the first column an alias, and remove the COUNT... like this:
; WITH XmlResults AS (
SELECT
ParamValues.x1.value('likeID[1]', 'VARCHAR(60)') AS likeId,
B.[userID] AS totalLikes
FROM
#likeXML.nodes('/likes/like') AS ParamValues(x1)
JOIN
apsLikes AS B ON B.[likeID] = ParamValues.x1.value('likeID[1]', 'VARCHAR(60)')
FOR XML PATH ('likeData'), TYPE, ELEMENTS, ROOT ('root')
)
SELECT likeId, COUNT(totalLikes)
FROM XmlResults
GROUP BY likeId

One of the ways is to do a nested select, like this:
SELECT LikeId, COUNT(Userid) FROM (
SELECT ParamValues.x1.value('likeID[1]', 'VARCHAR(60)') LikeId,
B.[userID] Userid
FROM #likeXML.nodes('/likes/like') AS ParamValues(x1)
JOIN apsLikes AS B
ON B.[likeID] = ParamValues.x1.value('likeID[1]', 'VARCHAR(60)')
FOR XML PATH ('likeData'), TYPE, ELEMENTS, ROOT ('root');
) tmp
Group By LikeId

Making a subquery and then grouping and XML'it should work :
select x1, count(Likes) from
(
SELECT
ParamValues.x1.value('likeID[1]', 'VARCHAR(60)') AS X1,
B.[userID] AS Likes
FROM
#likeXML.nodes('/likes/like') AS ParamValues(x1)
JOIN
apsLikes AS B ON B.[likeID] = ParamValues.x1.value('likeID[1]', 'VARCHAR(60)')
) t
group by X1
FOR XML PATH ('likeData'), TYPE, ELEMENTS, ROOT ('root');

Related

Recursive query SQL Server not working as expected

thanks in advance for you help. I'm still quite new to MS SQL db but I was wondering why my recursive query for MSSQL below does not return the value i'm expecting. I've done my research and at the bottom is the code I came up with. Lets say I have the following table...
CategoryID ParentID SomeName
1 0 hmm
2 0 err
3 0 woo
4 3 ppp
5 4 ttt
I'm expecting the query below to return 3 4 5. I basically wanted to get the list of category id's heirarchy below it self inclusive based on the category id I pass in the recursive query. Thanks for you assistance.
GO
WITH RecursiveQuery (CategoryID)
AS
(
-- Anchor member definition
SELECT a.CategoryID
FROM [SomeDB].[dbo].[SomeTable] AS a
WHERE a.ParentID = CategoryID
UNION ALL
-- Recursive member definition
SELECT b.CategoryID
FROM [SomeDB].[dbo].[SomeTable] AS b
INNER JOIN RecursiveQuery AS d
ON d.CategoryID = b.ParentID
)
-- Statement that executes the CTE
SELECT o.CategoryID
FROM [SomeDB].[dbo].[SomeTable] AS o
INNER JOIN RecursiveQuery AS d
ON d.CategoryID = 3
GO
If you want tree from specific root:
DECLARE #rootCatID int = 3
;WITH LessonsTree (CatID)
AS
(
SELECT a.CategoryID
FROM [EducationDatabase].[dbo].[LessonCategory] AS a
WHERE a.CategoryID = #rootCatID ---<<<
UNION ALL
SELECT b.CategoryID
FROM LessonsTree as t
INNER JOIN [EducationDatabase].[dbo].[LessonCategory] AS b
ON b.ParentID = t.CatID
)
SELECT o.*
FROM LessonsTree t
INNER JOIN [EducationDatabase].[dbo].[LessonCategory] AS o
ON o.CategoryID = t.CatID
As stated in the comments, the anchor isn't restricted. Easiest solution is to add the criterium in the anchor
with RecursiveQuery (theID)
AS
(
SELECT a.ParentID --root id=parentid to include it and to prevent an extra trip to LessonCategory afterwards
FROM [LessonCategory] AS a
WHERE a.ParentID = 3 --restriction here
UNION ALL
SELECT b.CategoryID
FROM [LessonCategory] AS b
INNER JOIN RecursiveQuery AS d
ON d.theID = b.ParentID
)
SELECT* from RecursiveQuery
Another option is to have the recursive query be general (no restricted anchor) and have it keep the rootid as well. Then the query on the cte can restrict on the rootid (the first option is probably better, this second one is mainly suitable if you are created some sort of root-view)
with RecursiveQuery
AS
(
SELECT a.ParentID theID, a.ParentID RootID
FROM [LessonCategory] AS a
UNION ALL
SELECT b.CategoryID, d.RootID
FROM [LessonCategory] AS b
INNER JOIN RecursiveQuery AS d
ON d.theID = b.ParentID
)
SELECT theID from RecursiveQuery where RootID = 3

how to using distinct in XML SQL using stored procedure

SELECT DISTINCT
CD.CASE_NO AS CaseNumber ,
CE.PROCEEDING_ID AS ProceedingId,
PR.AC_STATE_CD AS ForeclosureStatecode,
0 AS STATUS,
GETDATE() AS CreatedDate,
1 AS CreatedBy,
GETDATE() AS ModifiedDate,
1 AS ModifiedBy,
(
select * from TBL_PROPERTY FOR XML PATH('T')
)
from TBL_CASE_DETAIL CD WITH(NOLOCK)
INNER JOIN TBL_AUCTION_DETAIL AD WITH(NOLOCK) ON AD.CASE_DETAIL_ID = CD.CASE_DETAIL_ID
LEFT JOIN TBL_AUCTION_PROPERTY_MAPPING TAPM WITH(NOLOCK) ON TAPM.AUCTION_ID = AD.AUCTION_ID
LEFT JOIN TBL_PROPERTY PR WITH(NOLOCK) ON PR.PROPERTY_ID = TAPM.PROPERTY_ID
LEFT JOIN TBL_AUCTION_PROCEEDING_MAPPING APM WITH(NOLOCK) ON APM.AUCTION_ID = AD.AUCTION_ID
FOR XML PATH('Foreclosure')
Hi Guys, This is my modified code to get a distinct result. but now property part cannot display properly..
This is the result I get it. suppose open another tab for property lets say have 3 property.. so in 1 tab of foreclosure,inside foreclosure have 3 property data, then close foreclose tab..
https://gyazo.com/8a54690c88df3e9bb0dd7ff916c6f86c
Thank You.
If I get this right, the only thing you have to add is ,TYPE. Otherwise your inner SELECT ... FOR XML PATH() is filled i as text with all forbidden characters escaped...
Try:
(
select * from TBL_PROPERTY FOR XML PATH('T'),TYPE
)

verify that xml node has a child node with a given value tsql

I have the following tables
A (ID, relatedID, typeId )
B (ID, leftID, leftTypeId)
I want to join the two tables like this
select * from A
inner join B on A.TypeId=B.LeftTypeId and {condition}
where condition should verify id the leftID would match a value from relatedID, where relatedId is a xml column. Eg. relatedID=<Id>1</Id>
Is there a optimal way to do this?
UPDATE
relatedID can contain several Ids. Eg Eg. relatedID=<Id>1</Id><Id>2</Id>
You may use
... and A.relatedID.value('(/Id[1]/text())[1]', 'int') = B.leftID
or
... and A.relatedID.exist('(/Id[1]/text())[1] = sql:column("B.leftID")') = 1
Though exist is recommended over value for predicates, depending on whether the XML column is xml-indexed or not and what type of indexes it has, one of the two above may perform better.
upd. for the case when relatedID can contain set of Ids you may try
select ...
from A
cross apply A.relatedID.nodes('/Id') r(id)
inner join B on A.TypeId=B.LeftTypeId
and r.id.value('text()[1]', 'int') = B.leftID
or
select ...
from A
cross apply A.relatedID.nodes('/Id') r(id)
inner join B on A.TypeId=B.LeftTypeId
and r.id.exist('text()[1]=sql:column("B.leftID")') = 1
or even
select ...
from A
inner join B on A.TypeId=B.LeftTypeId
and A.relatedID.exist('/Id[text()[1]=sql:column("B.leftID")]') = 1

LEFT JOIN with FOR XML AUTO, ELEMENTS

I have 3 tables
Master {MasterID, Desc},
Detail {MasterID, DetailID, ItemID},
Items {ItemID, ItemDesc})
I want to select Master, Detail (as SubElement in Master), Item (in same element of Detail)
SELECT Master.MasterID, Master.Desc, Detail.DetailID, Detail.ItemID, Items.ItemDesc
FROM Master
LEFT JOIN Detail
LEFT JOIN Items
ON Detail.ItemID = Items.ItemID
ON Master.MasterID = Detail.MasterID
FOR XML AUTO, ELEMENTS
it gives result below:
<Master>
<MasterID>1</MasterID>
<Desc>Master1</Desc>
<Detail>
<DetailID>1</DetailID>
<ItemID>1</ItemID>
<Items><ItemDesc>ItemDesc1</ItemDesc></Items>
</Detail>
</Master>
But my target is
<Master>
<MasterID>1</MasterID>
<Desc>Master1</Desc>
<Detail>
<DetailID>1</DetailID>
<ItemID>1</ItemID>
<ItemDesc>ItemDesc1</ItemDesc>
</Detail>
</Master>'
How can I do that with best practice way?
Make the detail and item description come back from a single query, like so:
SELECT
Master.MasterID,
Master.Desc,
Detail.DetailID,
Detail.ItemID,
Detail.ItemDesc
FROM
Master
LEFT JOIN (
select
d.MasterID,
d.DetailID,
d.ItemID,
i.ItemDesc
from
Detail d
left join items i on
d.itemid = i.itemid
) Detail ON
Master.MasterID = Detail.MasterID
FOR XML AUTO, ELEMENTS
You can use for xml path like this.
select m.MasterID,
m.[Desc],
(select d.DetailID,
d.ItemID,
i.ItemDesc
from Detail as d
inner join Items as i
on d.ItemID = i.ItemID
where d.MasterID = m.MasterID
for xml path('Detail'), type)
from Master as m
for xml path('Master')

SQL Subquery Select Table based on Outer Query

I have a general query that looks like this:
SELECT DISTINCT pb.id, pb.last, pb.first, pb.middle, pb.sex, pb.phone, pb.type,
specialties = substring(
SELECT ('|' + cs.specialty )
FROM CertSpecialty AS cs
INNER JOIN CertSpecialtyIndex AS csi on cs.specialty = csi.specialty
WHERE cs.id = pb.id
ORDER BY cs.sequence_no
FOR XML path(''),2,500)
FROM table AS pb
WHERE etc etc etc
The issue is this:
The "type" column that I'm selecting is an integer - types 1-4.
In the subquery, see where I am querying from the table CertSpecialty right now.
What I actually need to do is, if the type field comes back as a 1 or a 3, that's the table I need to query. But if the row's result is a type 2 or 4 (i.e., an ELSE), I need to be querying the same column in the table CertSpecialtyOther.
So it'd need to look something like this (though this obv doesn't work):
SELECT DISTINCT pb.id, pb.last, pb.first, pb.middle, pb.sex, pb.phone, pb.type,
specialties =
IF type in (1,3)
substring((SELECT ('|' + cs.specialty )
FROM CertSpecialty AS cs
INNER JOIN CertSpecialtyIndex AS csi on cs.specialty = csi.specialty
WHERE cs.id = pb.id
ORDER BY cs.sequence_no
FOR XML path(''),2,500)
ELSE
substring((SELECT ('|' + cs.specialty )
FROM CertSpecialtyOther AS cs
INNER JOIN CertSpecialtyIndex AS csi on cs.specialty = csi.specialty
WHERE cs.id = pb.id
ORDER BY cs.sequence_no
FOR XML path(''),2,500)
end
FROM table AS pb
WHERE etc etc etc
Is this possible? If so, what is the correct syntax? Is there a simpler way to write it where I'm switching which table I query without completely duplicating the subquery?
Also, does anyone have a good resource they could link me for this sort of thing to learn more besides?
Thanks in advance.
Use a CTE.
;WITH cs AS
(
SELECT 'A' SpecialtyCategory, phy_key, specialty
FROM CertSpecialty
UNION ALL
SELECT 'B' SpecialtyCategory, phy_key, specialty
FROM CertSpecialtyOther
)
SELECT csi.id, cs.specialty
FROM cs
INNER JOIN CertSpecialtyIndex AS csi on cs.specialty = csi.specialty
WHERE cs.phy_key = pb.phy_key
AND cs.SpecialtyCategory = (CASE WHEN type in (1,3) THEN 'A' ELSE 'B' END)

Resources