SQL Server: How to add count to nested select - sql

I have two tables, one containing a list of files and one containing a list of tags which are linked by a fileID.
Currently I select this as follows which works fine so far.
How do I have to amend this if I want to count the tags per file and show this in addition to the selected data ?
What I want to do is show how many tags are assigned to each file.
My SP:
SELECT C.fileTitle,
C.fileID,
(
SELECT T.fileTag
FROM Files_Tags T
WHERE T.fileID = C.fileID
ORDER BY T.fileTag
FOR XML PATH(''), ELEMENTS, TYPE
) AS tags
FROM Files C
ORDER BY C.fileTitle
FOR XML PATH('files'), ELEMENTS, TYPE, ROOT('root')
Many thanks for any help with this, Tim.

You can add a subquery:
SELECT C.fileTitle,
C.fileID,
(
SELECT COUNT(*)
FROM Files_Tags T
WHERE T.fileID = C.fileID
) AS NumTags,
(
SELECT T.fileTag
FROM Files_Tags T
WHERE T.fileID = C.fileID
ORDER BY T.fileTag
FOR XML PATH(''), ELEMENTS, TYPE
) AS tags
You could also put in a join and aggregation in the outer query. But, your query already has to use a nested select for the concatenation, so you might as well use the same structure for the count.

Can't you just do this?:
SELECT C.fileTitle,
C.fileID,
(
SELECT T.fileTag
FROM Files_Tags T
WHERE T.fileID = C.fileID
ORDER BY T.fileTag
FOR XML PATH(''), ELEMENTS, TYPE
) AS tags,
(
SELECT
COUNT(*)
FROM
Files_Tags T
WHERE
T.fileID = C.fileID
) AS NumberOfTages
FROM Files C
ORDER BY C.fileTitle
FOR XML PATH('files'), ELEMENTS, TYPE, ROOT('root')
Anding a sub query for the count

Related

How to simplify correlated subquery in sql server 2008?

I have query in sql server which I want to simplify so that it can be Hive compatible.
This is the query written in SQL format
SELECT session_id,
Substring ((SELECT ( ';' + tag_name )
FROM session_tag st2
WHERE st2.session_id = st.session_id
FOR xml path ( '' )), 2, 1000) AS tags
FROM session_tag
GROUP BY session_id;
This is the result of this query
Once again I don't want to pass select query inside the substring function.
So I tried to simplify these query to get the same result the first query shows nothing and second one throws an error that subquery returned more than one result.
SELECT SUBSTRING(';'+tag_name,2,1000) as tag from session_tag st1
where st1.session_id = (select st2.session_id from session_tag st2 where st1.session_id = st2.session_id for xml path (''))
and
SELECT SUBSTRING(';'+tag_name,2,1000) as tag from session_tag st1
where st1.session_id = (select st2.session_id from session_tag st2 where st1.session_id = st2.session_id) for xml path('')
Finally I got the solution. The simplified version of this query is
SELECT session_id, Substring(d.tagList,2,1000) as tag from (
select distinct session_id from session_tag) a
cross apply
(
select ';'+tag_name from session_tag as b
where a.session_id = b.session_id for xml path ('')
) d (tagList)

SQL: Filter XML retrieving using xpath

I have documents table, each row has a XML column Document:
<Document>
<Good GroupId="..."/>
<Good GroupId="..."/>
...
</Document>
I also have temp table with subset of GroupId values:
DECLARE #Groups TABLE (groupId VARCHAR(MAX));
Next, I wrote a select query to documents table, goal - retrieve XML from Document:
SELECT
(SELECT CAST(Document.data as XML)).query('/Document/Good') AS Goods
FROM
Documents as Document
JOIN
#Numbers n ON n.number = Document.number
WHERE
Document.type = #type
--FOR XML AUTO, ROOT('Documents')
As a result, in column Goods I got all Good items for each Document
Task:
In step 3, I need filter Good elements by GroupId attribute (using #Groups) - I need all Good for which GroupId value is not contained in #Groups
Thanks!
Do CROSS APPLY to extract the attribute values from the XML
Need to use LEFT JOIN to find Goods in XML but not in #Goods table.
Here is the SQL Fiddle: http://www.sqlfiddle.com/#!3/a6b9e/5
SELECT G.value('#GroupId', 'varchar(max)') FROM
(
SELECT
CAST(Document.data as XML) AS Goods
FROM
Documents as Document
WHERE type = 1
) T
CROSS APPLY T.Goods.nodes('Document/Good') D(G)
LEFT JOIN #Groups GS
ON G.value('#GroupId', 'varchar(max)') = GS.groupId
WHERE GS.groupId IS NULL

How to concatenate distinct columns of otherwise duplicate rows into one row without using FOR XML PATH('')?

I have this query:
SELECT DISTINCT
f1.CourseEventKey,
STUFF
(
(
SELECT '; ' + Title
FROM (
SELECT DISTINCT
ces.CourseEventKey,
f.Title
FROM CourseEventSchedule ces
INNER JOIN Facility f ON f.FacilityKey = ces.FacilityKey
WHERE ces.CourseEventKey IN
(
SELECT CourseEventKey
FROM #CourseEvents
)
) f2
WHERE f2.CourseEventKey = f1.CourseEventKey
FOR XML PATH('')
), 1, 2, ''
)
FROM (
SELECT DISTINCT
ces.CourseEventKey,
f.Title
FROM CourseEventSchedule ces
INNER JOIN Facility f ON f.FacilityKey = ces.FacilityKey
WHERE ces.CourseEventKey IN
(
SELECT CourseEventKey
FROM #CourseEvents
)
) f1
It produces this result set:
CourseEventKey Titles
-------------- ----------------------------------
29 Test Facility 1
30 Memphis Training Room
32 Drury Inn & Suites Creve Coeur
The data is accurate, but I can't have FOR XML PATH('') because it escapes certain special characters.
To be clear, I'm using FOR XML PATH('') because it is possible for records with the same CourseEventKey to have multiple Facility titles associated with them.
How can I retain the data returned by this query without using FOR XML PATH('')?
Change the "for xml path('') )" section to "for xml path(''), root('root'), type).query('root').value ('.', 'varchar(max)')" this will unescape the characters correctly.
Sorry for the poor formatting but not at my computer right now. I can give a full example later if you need.

SQL select join on xml field with xpath expression

I have a following query that can return a result from an xml:
declare #xml xml
select #xml = data from files where id = 1234
select
children.p.value('./speed[1]','float')
from #xml.nodes('root/children') as children(p)
where
children.p.value('./name[1]','nvarchar(max)') = 'something'
This in my case returns a single value, for example 3141
However, I'd like to do multiple selects like this from multiple XMLs.
I can select the xml data as
select id, cast(data as xml) as xml
from files
where id in (1005,51,968,991,992,993,969,970) --for example
I imagine there must be some kind of JOIN that will apply my expression and return a single item for each xml variable in the table, but I am not sure how.
Use apply:
select
f.id, children.p.value('./speed[1]','float')
from files as f
outer apply (select cast(f.data as xml) as xml) as x
outer apply x.xml.nodes('root/children') as children(p)
where
f.id in (1005,51,968,991,992,993,969,970) and
children.p.value('./name[1]','nvarchar(max)') = 'something'

carriage return in sql server 2012

Hey I am using the following query to display the problem list separated by commas.
SELECT tt.VrNo, STUFF((select ','+ Er1.ErrorDesc
from ( select * from CallRegErrors )as Main
left join ErrorMaster ER1 on Main.ErrorCode=ER1.ErrorCode
WHERE (main.VrNo = tt.VrNo)
FOR XML PATH('')) ,1,1,'') AS Problemlist
query is giving the output like a,b,c,d etc
But my actual requirement is I want to display each error description in a new line like,
a
b
c
d
etc
I tried the following query for it:
SELECT tt.VrNo, STUFF((select char(13)+char(10)+ Er1.ErrorDesc
from ( select * from CallRegErrors )as Main
left join ErrorMaster ER1 on Main.ErrorCode=ER1.ErrorCode
WHERE (main.VrNo = tt.VrNo)
FOR XML PATH('')) ,1,1,'') AS Problemlist
and also i have used
SELECT tt.VrNo,Replace(STUFF((select ','+ Er1.ErrorDesc as [text()] from ( select * from CallRegErrors )as Main left join ErrorMaster ER1 on Main.ErrorCode=ER1.ErrorCode
WHERE (main.VrNo = tt.VrNo)
FOR XML PATH('')),1,1,''),',',char(13)+char(10)) AS Problemlist
from (select main.VrNo, Er1.ErrorDesc from ( select * from CallRegErrors )as Main left join ErrorMaster ER1 on Main.ErrorCode=ER1.ErrorCode )as tt
group by tt.VrNo
but now get the problem list seperated by spaces instead of commas after using the above query
but its does not give the output that i want.
please help..
Thanks in advance
I think we need more information before we can help you.
I think you are trying to format the information at the child level in a parent child relationship into a list. You probably saw something like this blog on the web.
However, your query is not correctly formatted.
Is the ErrorMaster (Production.ProductCategory) the parent and CallRegErrors (SUB.ProductCategoryID) the child?
If so just change the query to those table name field names for it to work.
I used the REPLACE function on the overall result to change COMMAS to CR + LF.
-- Sample database
USE AdventureWorks2012
GO
-- Change SQL from www.sqlandme.com for this users problem
SELECT
CAT.Name AS [Category],
REPLACE(STUFF((
SELECT ',' + SUB.Name AS [text()]
FROM Production.ProductSubcategory SUB
WHERE SUB.ProductCategoryID = CAT.ProductCategoryID
FOR XML PATH('')
), 1, 1, '' ), ',', CHAR(13) + CHAR(10))
AS [Sub Categories]
FROM Production.ProductCategory CAT
You can only see carriage returns in the output window when the type is set to TEXT in SSMS.
I hope this solves your problem. If not, please write back with more information!!