I have setup the example below to demonstrate
- Use of an APPLY operator with FOR XML PATH. I have used an OUTER APPLY as there is a User with no access to objects.
- In the first query below I avoid "XML entities" in the result. Note the object names contain characters that XML needs to form XML. The second query below then displays what happens if TYPE and .value(... are omitted.
SQL Fiddle
MS SQL Server 2014 Schema Setup:
CREATE TABLE Users
([Code] varchar(1), [UserName] varchar(4))
;
INSERT INTO Users
([Code], [UserName])
VALUES
('A', 'Aaaa'),
('B', 'Bbbb'),
('C', 'Cccc'),
('D', 'Dddd'),
('E', 'Eeee')
;
CREATE TABLE Objects
([Code] varchar(7), [Name] varchar(23))
;
INSERT INTO Objects
([Code], [Name])
VALUES
('ObjectA', 'Fred & Ginger Whizzbang'),
('ObjectB', 'The diamond<> cutter'),
('ObjectC', 'Whatever'),
('ObjectD', 'Blah de Blah')
;
CREATE TABLE ObjectAccess
([ID] int, [ObjectCode] varchar(7), [UserCode] varchar(1))
;
INSERT INTO ObjectAccess
([ID], [ObjectCode], [UserCode])
VALUES
(1, 'ObjectA', 'A'),
(2, 'ObjectA', 'B'),
(3, 'ObjectA', 'C'),
(4, 'ObjectB', 'D'),
(5, 'ObjectB', 'A'),
(6, 'ObjectB', 'B'),
(7, 'ObjectB', 'C'),
(8, 'ObjectC', 'B'),
(9, 'ObjectC', 'C'),
(10, 'ObjectC', 'D'),
(11, 'ObjectD', 'C'),
(12, 'ObjectD', 'D'),
(13, 'ObjectE', 'A'),
(14, 'ObjectF', 'D')
;
Query 1:
SELECT
Users.code
, Users.UserName
, oa.ObjectList
FROM Users
OUTER APPLY (
SELECT
STUFF
((
SELECT /* DISTINCT -- can be used here if required */
',' + Objects.Name
FROM ObjectAccess
INNER JOIN Objects ON ObjectAccess.ObjectCode = Objects.Code
WHERE ObjectAccess.UserCode = Users.Code
ORDER BY Objects.Name
FOR XML PATH (''), TYPE --<< nb!!
)
.value('.', 'varchar(max)') --<< nb!!
, 1, 1, '')
) AS oa (ObjectList)
Results:
| code | UserName | ObjectList |
|------|----------|--------------------------------------------------------------------|
| A | Aaaa | Fred & Ginger Whizzbang,The diamond<> cutter |
| B | Bbbb | Fred & Ginger Whizzbang,The diamond<> cutter,Whatever |
| C | Cccc | Blah de Blah,Fred & Ginger Whizzbang,The diamond<> cutter,Whatever |
| D | Dddd | Blah de Blah,The diamond<> cutter,Whatever |
| E | Eeee | (null) |
Query 2:
SELECT
Users.code
, Users.UserName
, oa.ObjectList
FROM Users
OUTER APPLY (
SELECT
STUFF
((
SELECT /* DISTINCT -- can be used here if required */
',' + Objects.Name
FROM ObjectAccess
INNER JOIN Objects ON ObjectAccess.ObjectCode = Objects.Code
WHERE ObjectAccess.UserCode = Users.Code
ORDER BY Objects.Name
FOR XML PATH ('')
)
, 1, 1, '')
) AS oa (ObjectList)
Results:
| code | UserName | ObjectList |
|------|----------|------------------------------------------------------------------------------|
| A | Aaaa | Fred & Ginger Whizzbang,The diamond<> cutter |
| B | Bbbb | Fred & Ginger Whizzbang,The diamond<> cutter,Whatever |
| C | Cccc | Blah de Blah,Fred & Ginger Whizzbang,The diamond<> cutter,Whatever |
| D | Dddd | Blah de Blah,The diamond<> cutter,Whatever |
| E | Eeee | (null) |