I am currently writing a SQL script - takes a business term, and all related synonyms. What it does is creates multiple rows (because there are multiple synonyms (can have other columns that could be multiple values as well.
What I am trying to do is to create a single row for every business term, and concatenate values (, delimited) so that I get one line item for each business term only.
Currently my SQL script is:
SELECT dbo.TblBusinessTerm.BusinessTerm, dbo.TblBusinessTerm.BusinessTermLongDesc,
dbo.TblBusinessTerm.DomainCatID, dbo.TblSystem.SystemName,
dbo.TblDomainCat.DataSteward, dbo.TblDomainCat.DomainCatName,
dbo.TblField.GoldenSource, dbo.TblField.GTS_table,
dbo.TblTableOwner.TableOwnerName, dbo.TblBusinessSynonym.Synonym
FROM dbo.TblTableOwner INNER JOIN
dbo.TblBusinessTerm INNER JOIN
dbo.TblBusinessSynonym ON dbo.TblBusinessTerm.BusinessTermID = dbo.TblBusinessSynonym.BusinessTermID INNER JOIN
dbo.TblField ON dbo.TblBusinessTerm.BusinessTermID = dbo.TblField.BusinessTermID INNER JOIN
dbo.TblSystem INNER JOIN
dbo.TblTable ON dbo.TblSystem.SystemID = dbo.TblTable.SystemID ON dbo.TblField.TableID = dbo.TblTable.TableID INNER JOIN
dbo.TblDomainCat ON dbo.TblBusinessTerm.DomainCatID = dbo.TblDomainCat.DomainCatID ON dbo.TblTableOwner.TableOwnerID = dbo.TblDomainCat.DataSteward
Is there an easy way to do this that takes performance into consideration - am new to SQL.
Thank you
I have managed to create a with statement that now concatenates my rows:
With syn as (
select [BusinessTermID],
syns = STUFF((SELECT ', ' + dbo.TblBusinessSynonym.Synonym
FROM dbo.TblBusinessSynonym
WHERE [BusinessTermID] = x.[BusinessTermID]
AND dbo.TblBusinessSynonym.Synonym <> ''
FOR XML PATH ('')),1,2,'')
FROM dbo.TblBusinessSynonym AS x
GROUP BY [BusinessTermID]
)
select * from syn
But now how can I use it in the above query where everything links?
Would want to replace dbo.TblBusinessSynonym.Synonym with the results from syn
Any SQL 2014 developers that can assist?
Write your with statement at the very top, without the select.
Then write your upper query as it is and change
INNER JOIN dbo.TblBusinessSynonym ON dbo.TblBusinessTerm.BusinessTermID = dbo.TblBusinessSynonym.BusinessTermID
to
INNER JOIN syn ON syn.BusinessTermID = dbo.TblBusinessTerm.BusinessTermID
That's it
With syn as (
select [BusinessTermID],
syns = STUFF((SELECT ', ' + dbo.TblBusinessSynonym.Synonym
FROM dbo.TblBusinessSynonym
WHERE [BusinessTermID] = x.[BusinessTermID]
AND dbo.TblBusinessSynonym.Synonym <> ''
FOR XML PATH ('')),1,2,'')
FROM dbo.TblBusinessSynonym AS x
GROUP BY [BusinessTermID]
)
SELECT dbo.TblBusinessTerm.BusinessTerm,
dbo.TblBusinessTerm.BusinessTermLongDesc,
dbo.TblBusinessTerm.DomainCatID, dbo.TblSystem.SystemName,
dbo.TblDomainCat.DataSteward, dbo.TblDomainCat.DomainCatName,
dbo.TblField.GoldenSource, dbo.TblField.GTS_table,
dbo.TblTableOwner.TableOwnerName, syn.syns
FROM dbo.TblTableOwner INNER JOIN
dbo.TblBusinessTerm INNER JOIN
syn ON dbo.TblBusinessTerm.BusinessTermID = syn.BusinessTermID INNER JOIN
dbo.TblField ON dbo.TblBusinessTerm.BusinessTermID = dbo.TblField.BusinessTermID INNER JOIN
dbo.TblSystem INNER JOIN
dbo.TblTable ON dbo.TblSystem.SystemID = dbo.TblTable.SystemID ON dbo.TblField.TableID = dbo.TblTable.TableID INNER JOIN
dbo.TblDomainCat ON dbo.TblBusinessTerm.DomainCatID = dbo.TblDomainCat.DomainCatID ON dbo.TblTableOwner.TableOwnerID = dbo.TblDomainCat.DataSteward
Please use STRING_AGG function. It combines record items in field ans set them in one record separated with specified delimiter.
Details are here:
https://learn.microsoft.com/en-us/sql/t-sql/functions/string-agg-transact-sql?view=sql-server-2017
Your query is complicated, so I will just post here sample data and how to deal with it in a manner you want. The operation is string aggregation with concatenation, in latest version there's string_agg function, that does the work for us. But, as you can't use this function, here's workaround:
select * into #tt
from (values (1, '1'),(1, '2'),(2, '1'),(2, '2')) A(id, someStr)
select id, (select someStr + ',' from #tt where id = [t].id for xml path('')) [grouped]
from #tt [t] group by id
Above query groups by Id and concaenates all corresponding rows in someStr column.
Related
I'm trying to scan my codebase to find all select queries without a where clause using regex. The results will be fed into an IDE or a grep file output, but must contain the full matching queries only.
My biggest challenge is getting the entire statement without the WHERE. The caveats are:
some selects don't have a where but also don't have a FROM
some selects target a database view (always starts with a vw) which don't need a where clause
Here's a sample list of all queries fetched from one file:
'
DECLARE #RowsAffected INT = 0;
INSERT INTO tblInvoice (InvID, OcID, InvTimeStamp)
SELECT DISTINCT OcInvID, OcID, GETDATE() AS InvTimeStamp
FROM tblOrderCost OC WITH(NOLOCK)
INNER JOIN tblVendor WITH(NOLOCK) ON InvVendorID = VendorID AND VendorType = 1 -- 1 for supplier.
INNER JOIN #tmpOpID tmp WITH(NOLOCK) ON tmp.OpID = OcOpID
WHERE id = ' . quote($order_id, NUMERIC);
$sql = ' SELECT rphrpid,rphwho,rphdate,rphnotes,opid
FROM tblReplacementPartHistory (nolock)
INNER JOIN tblReplacementPart (nolock)
ON rphrpid = rpid
INNER JOIN tblOrderProduct (nolock)
ON rpopid = opid
WHERE oporid =' . quote($order_id, NUMERIC)
. 'ORDER BY rphrpid';
select * from table where id = 1;
'
select count()
';
DECLARE #RowsAffected INT = 0;
INSERT INTO tblInvoice (InvID, OcID, InvTimeStamp)
SELECT DISTINCT OcInvID, OcID, GETDATE() AS InvTimeStamp
FROM tblOrderCost OC WITH(NOLOCK)
INNER JOIN tblVendor WITH(NOLOCK) ON InvVendorID = VendorID AND VendorType = 1
INNER JOIN #tmpOpID tmp WITH(NOLOCK) ON tmp.OpID = OcOpID';
$sql = ' SELECT rphrpid,rphwho,rphdate,rphnotes,opid
FROM tblReplacementPartHistory (nolock)
INNER JOIN tblReplacementPart (nolock)
ON rphrpid = rpid
INNER JOIN tblOrderProduct (nolock)
ON rpopid = opid
ORDER BY rphrpid';
SELECT rphrpid,rphwho,rphdate,rphnotes,opid
FROM vwOrder';
select * from tbl;
I tried several variations of regex patterns and the closest I got was finding matches with the WHERE line stripped out. I would like to have the entire match made only if the query does not have a WHERE clause. I tried the following
SELECT(.*)(\s)*FROM(\s|.)+?((?!.*where))(?=(';|";|;))
SELECT\s*(?!.*\s*where|vw(\w)*).*\s*(';|";|;)
SELECT[^;\n]*(?:\n(?![^\n;]*where)[^;\n]*)*\n[\n]*
The work can also be tested in the regex101 sandbox: https://regex101.com/r/jvbLOE/1
What I expect to see, given the sample data, is only three matches
1. SELECT DISTINCT OcInvID, OcID, GETDATE() AS InvTimeStamp
FROM tblOrderCost OC WITH(NOLOCK)
INNER JOIN tblVendor WITH(NOLOCK) ON InvVendorID = VendorID AND VendorType = 1
INNER JOIN #tmpOpID tmp WITH(NOLOCK) ON tmp.OpID = OcOpID';
2. SELECT rphrpid,rphwho,rphdate,rphnotes,opid
FROM tblReplacementPartHistory (nolock)
INNER JOIN tblReplacementPart (nolock)
ON rphrpid = rpid
INNER JOIN tblOrderProduct (nolock)
ON rpopid = opid
ORDER BY rphrpid';
3. select * from tbl;
You can use following regex to match select queries not having a where clause in it based on your example.
/(?!.*where)select.*?;/gis
Regex 101 example:
https://regex101.com/r/XaGXp6/1
Need help figuring out how to do a cross-tabulated report within one query. There are 3-4 tables involved but the users table may not need to be included in the query since we just need a count.
I have put together a screenshot of the table schema and data as an example which can be seen below:
What I need it to return is a query result that looks like:
So I can make a report that looks like:
I've tried to do cursor loops as it's the only way I can do it with my basic knowledge, but it's way too slow.
One particular report I'm trying to generate contains 32 rows and 64 columns with about 70,000 answers, so it's all about the performance of getting it down to one query and fast as possible.
I understand this may depend on indexes and so on but if someone could help me figure out how I could get this done in 1 query (with multiple joins?), that would be awesome!
Thanks!
SELECT MIN(ro.OptionText) RowOptionText, MIN(co.OptionText) RowOptionText, COUNT(ca.AnswerID) AnswerCount
FROM tblQuestions rq
CROSS JOIN tblQuestions cq
JOIN tblOptions ro ON rq.QuestionID = ro.QuestionID
JOIN tblOptions co ON cq.QuestionID = co.QuestionID
LEFT JOIN tblAnswers ra ON ra.OptionID = ro.OptionID
LEFT JOIN tblAnswers ca ON ca.OptionID = co.OptionID AND ca.UserID = ra.UserID
WHERE rq.questionText = 'Gender'
AND cq.questionText = 'How happy are you?'
GROUP BY ro.OptionID, co.OptionID
ORDER BY ro.OptionID, co.OptionID
This should be at least close to what you asked for. Turning this into a pivot will require dynamic SQL as SQL Server requires you to specify the actual value that will be pivoted into a column.
We cross join the questions and limit the results from each of those question references to the single question for the row values and column values respectively. Then we join the option values to the respective question reference. We use LEFT JOIN for the answers in case the user didn't respond to all of the questions. And we join the answers by UserID so that we match the row question and column question for each user. The MIN on the option text is because we grouped and ordered by OptionID to match your sequencing shown.
EDIT: Here's a SQLFiddle
For what it's worth, your query is complicated because you are using the Entity-Attribute-Value design pattern. Quite a few SQL Server experts consider that pattern to be problematic and to be avoided if possible. For instance see https://www.simple-talk.com/sql/t-sql-programming/avoiding-the-eav-of-destruction/.
EDIT 2: Since you accepted my answer, here's the dynamic SQL pivot solution :) SQLFiddle
DECLARE #SqlCmd NVARCHAR(MAX)
SELECT #SqlCmd = N'SELECT RowOptionText, ' + STUFF(
(SELECT ', ' + QUOTENAME(o.OptionID) + ' AS ' + QUOTENAME(o.OptionText)
FROM tblOptions o
WHERE o.QuestionID = cq.QuestionID
FOR XML PATH ('')), 1, 2, '') + ', RowTotal AS [Row Total]
FROM (
SELECT ro.OptionID RowOptionID, ro.OptionText RowOptionText, co.OptionID ColOptionID,
ca.UserID, COUNT(ca.UserID) OVER (PARTITION BY ra.OptionID) AS RowTotal
FROM tblOptions ro
JOIN tblOptions co ON ro.QuestionID = ' + CAST(rq.QuestionID AS VARCHAR(10)) +
' AND co.QuestionID = ' + CAST(cq.QuestionID AS VARCHAR(10)) + '
LEFT JOIN tblAnswers ra ON ra.OptionID = ro.OptionID
LEFT JOIN tblAnswers ca ON ca.OptionID = co.OptionID AND ca.UserID = ra.UserID
UNION ALL
SELECT 999999, ''Column Total'' RowOptionText, co.OptionID ColOptionID,
ca.UserID, COUNT(ca.UserID) OVER () AS RowTotal
FROM tblOptions ro
JOIN tblOptions co ON ro.QuestionID = ' + CAST(rq.QuestionID AS VARCHAR(10)) +
' AND co.QuestionID = ' + CAST(cq.QuestionID AS VARCHAR(10)) + '
LEFT JOIN tblAnswers ra ON ra.OptionID = ro.OptionID
LEFT JOIN tblAnswers ca ON ca.OptionID = co.OptionID AND ca.UserID = ra.UserID
) t
PIVOT (COUNT(UserID) FOR ColOptionID IN (' + STUFF(
(SELECT ', ' + QUOTENAME(o.OptionID)
FROM tblOptions o
WHERE o.QuestionID = cq.QuestionID
FOR XML PATH ('')), 1, 2, '') + ')) p
ORDER BY RowOptionID'
FROM tblQuestions rq
CROSS JOIN tblQuestions cq
WHERE rq.questionText = 'Gender'
AND cq.questionText = 'How happy are you?'
EXEC sp_executesql #SqlCmd
I think I see the problem. I know you can't modify the schema, but you need a conceptual table for the crosstab information such as which questionID is the rowHeader and which is the colHeader. You can create it in an external data source and join with the existing source or simply hard-code the table values in your sql.
you need to have 2 instances of the question/option/answer relations, one for each rowHeader and colHeader for each crosstab. Those 2 relations are joined by the userID.
this version has your outer joins:
sqlFiddle
this version doesn't have the crossTab table, just the row and col questionIDs hard-coded:
sqlFiddleNoTbl
The following piece of mess works with no hard-coded values but fails to show the rows where the count is 0.
This might however still work for your report.
;with stepone as(
SELECT
RANK() OVER(PARTITION BY a.UserId ORDER BY o.QuestionID) AS [temprank]
, o.QuestionID AS [QID1]
, o.OptionID AS [OID1]
, same.QuestionID
, same.OptionID
, a.UserId AS [IDUser]
, same.UserId
FROM
tblAnswers a
INNER JOIN
tblOptions o
ON a.OptionID = o.OptionID
INNER JOIN
tblQuestions q
ON o.QuestionID = q.QuestionID
INNER JOIN
(
SELECT
a.AnswerID
, a.OptionID
, a.UserId
, o.QuestionID
FROM
tblAnswers a
INNER JOIN
tblOptions o
ON a.OptionID = o.OptionID
) same
ON a.UserId = same.UserId AND a.AnswerID <> same.AnswerID
)
, stepthree AS(
SELECT
t.QID1, t.OID1, t.QuestionID, t.OptionID
, COUNT(UserId) AS myCount
FROM
stepone t
WHERE t.temprank = 1
GROUP BY
t.QID1, t.OID1, t.QuestionID, t.OptionID
)
SELECT
o1.OptionText AS [RowTest]
, o2.OptionText AS [ColumnText]
, t.myCount AS [Count]
FROM
stepthree t
INNER JOIN tblOptions o1
ON t.OID1 = o1.OptionID
INNER JOIN tblOptions o2
ON t.OptionID = o2.OptionID
ORDER BY t.OID1
Hope it helps, I enjoyed trying to do it.
I have a pretty complex select statement that returns counted statistics from tables (think of it as an answer bank -- the complex select statement below) using inner join.
These answers are related to a table called Questions_Bank_AnswerChoices (which stores all the questions).
I am attempting to first pull the Questions (from the table Questions_Bank_AnswerChoices) then match them up with the statistics (complex statement below). The complex statement below pulls the statistics, but does not pull the questions unless they have been answered.
So, if no one answers question1, then question one will not show up in the statistics because it is not included in the Answers table (bc no one answered it).
How can I achieve this? I think that I need to outer join?
Complex Select Statement:
WITH tbl as (
SELECT
Questions_Bank.QuestionID, Questions_Bank.QuestionName,
REPLACE(Schools_Answers_Items.AnswerValue, '? ', ', ') as AnswerValue,
COUNT(Schools_Answers_Items.SchoolsAnswersItemID) AS CountAnswer,
Schools_Answers_Items.SchoolID
FROM Questions_Bank
INNER JOIN Schools_Answers_Items
ON Questions_Bank.QuestionID = Schools_Answers_Items.QuestionID
LEFT OUTER JOIN Schools_Answers
ON Schools_Answers_Items.SchoolsAnswerID = Schools_Answers.SchoolsAnswerID
WHERE (Questions_Bank.QuestionID = 1108)
AND (Schools_Answers.SchoolID = 103)
GROUP BY
Schools_Answers_Items.SchoolID,
Schools_Answers_Items.AnswerValue,
Questions_Bank.QuestionID,
Questions_Bank.QuestionName
)
SELECT
QuestionID, QuestionName, AnswerValue, CountAnswer,
SUM(CountAnswer) OVER () AS CountAllAnswers
FROM tbl
Try changing this
INNER JOIN Schools_Answers_Items
ON Questions_Bank.QuestionID = Schools_Answers_Items.QuestionID
to
LEFT OUTER JOIN Schools_Answers_Items
ON Questions_Bank.QuestionID = Schools_Answers_Items.QuestionID
and you might want to remove this
AND (Schools_Answers.SchoolID = 103)
or replace it with this
AND (Schools_Answers.SchoolID = 103 OR Schools_Answers.SchoolID IS NULL)
Try this:
SELECT
Questions_Bank.QuestionID, Questions_Bank.QuestionName,
REPLACE(Schools_Answers_Items.AnswerValue, '? ', ', ') as AnswerValue,
Schools_Answers_Items.SchoolID
FROM Questions_Bank
LEFT OUTER JOIN Schools_Answers_Items
ON Questions_Bank.QuestionID = Schools_Answers_Items.QuestionID
LEFT OUTER JOIN Schools_Answers
ON Schools_Answers_Items.SchoolsAnswerID = Schools_Answers.SchoolsAnswerID
WHERE Schools_Answers_Items.SchoolID
Similar to the question here:
http://forums.asp.net/t/1580379.aspx/1
I'm trying to merge common cells into a single comma-delimited cell, however across an inner join.
My SQL is:
SELECT DISTINCT tb_Order.OrderNumber, tb_Order.OrderId,
tb_Order.orderDate, tb_Order.OrderTotal,
tb_OrderStatus.OrderStatus, tb_Order.GroupOrderId,
tb_Venue.Title AS Venue
FROM tb_Order INNER JOIN tb_OrderItem ON tb_Order.OrderId = tb_OrderItem.OrderId
INNER JOIN tb_Show ON tb_OrderItem.ShowId = tb_Show.showId
INNER JOIN tb_OrderStatus ON tb_Order.OrderStatusId = tb_OrderStatus.OrderStatusID
INNER JOIN tb_Venue ON tb_Show.VenueId = tb_Venue.id
WHERE (tb_Order.OrderId = 705)
I need the [venue] to be comma-delimited like:
"Interactive Seating Chart Advanced, Interactive Seating Chart Mode Multi-Click"
If you have SQL Server 2017 (14.x) and later, you can use the STRING_AGG function.
SELECT tb_Order.OrderNumber, tb_Order.OrderId,
tb_Order.orderDate, tb_Order.OrderTotal,
tb_OrderStatus.OrderStatus, tb_Order.GroupOrderId,
STRING_AGG(tb_Venue.Title, ',') AS Venue
FROM tb_Order INNER JOIN tb_OrderItem ON tb_Order.OrderId = tb_OrderItem.OrderId
INNER JOIN tb_Show ON tb_OrderItem.ShowId = tb_Show.showId
INNER JOIN tb_OrderStatus ON tb_Order.OrderStatusId = tb_OrderStatus.OrderStatusID
INNER JOIN tb_Venue ON tb_Show.VenueId = tb_Venue.id
WHERE (tb_Order.OrderId = 705)
GROUP BY tb_Order.OrderNumber, tb_Order.OrderId,
tb_Order.orderDate, tb_Order.OrderTotal,
tb_OrderStatus.OrderStatus, tb_Order.GroupOrderId
One way to do this is by using a side effect of row processing order to populate a variable iteratively, like so. The downside of this is that it won't work in a simple query context and it's not the most efficient solution.
DECLARE #venues varchar(max)
SET #venues = ''
SELECT #venues =
CASE WHEN #venues = '' THEN v.Title
ELSE #venues + ',' + v.Title END
FROM tb_Venue v
SELECT #venues
A second way to do this is with STUFF and SQL Server XML extensions, like so:
SELECT DISTINCT v.Title,
(STUFF(
(SELECT ',' + v2.Title
FROM tb_Venue v2
-- uncomment this line if you are going
-- to aggregate only by something in the outer query
-- WHERE v2.GroupKey = v.GroupKey
ORDER BY v2.Title
FOR XML PATH(''), TYPE, ROOT
).value('root[1]','varchar(max)'),1,1,'')) as Aggregation
FROM tb_Venue v
A CLR-based solution is usually the most performant for this use case, and one of those is described here along with a boatload of other less ideal solutions...
Your problem is not one rooted in set logic so there isn't a clean SQL solution...
I have a SQL Server query that I need to convert to MySQL. I've never used SQL Server/T-SQL before, so I have no experience with FOR XML PATH. There's surprisingly little documentation on this sort of thing. If I remove the FOR XML PATH statement, MySQL returns the error "Operand should contain at least 1 column(s)."
It seems like the nested SELECT statements return strings containing raw XML data, but I don't have the original SQL Server database available to test that theory. I could emulate this effect easily if I knew the return schema.
The original query is below:
SELECT
har_autos.*, har_automodels.Model, har_automodels.MakeID, har_automakes.Make, har_autotypes.AutoType,
(SELECT har_notes.*, har_notelinks.Value
FROM har_notes
JOIN har_notelinks on (har_notes.ID = har_notelinks.NoteID)
WHERE har_autos.ID = har_notelinks.AutoID AND har_notes.NoteTypeID = 1)
AS 'UserNotes',
(SELECT har_notes.*, har_notelinks.Value
FROM har_notes
JOIN har_notelinks on (har_notes.ID = har_notelinks.NoteID)
WHERE har_autos.ID = har_notelinks.AutoID AND har_notes.NoteTypeID = 2)
AS 'EngineeringNotes'
FROM har_autos
LEFT JOIN har_automodels ON (har_autos.ModelID = har_automodels.ID)
LEFT JOIN har_automakes ON (har_automodels.MakeID = har_automakes.ID)
LEFT JOIN har_autotypes ON (har_autos.AutoTypeID = har_autotypes.ID)
UPDATE:
I rebuilt the query in its entirety and it now returns "Not unique table/alias: 'har_automakes'."
SELECT
har_autos.*,
har_automodels.Model,
har_automodels.MakeID,
har_automakes.Make,
har_autotypes.AutoType,
(SELECT
har_notes.ID,
har_notes.NoteTypeID,
har_notes.Text001,
har_notelinks.Value,
har_notelinks.AutoID,
har_autos.ID
FROM
har_notes
INNER JOIN har_notelinks ON (har_notes.ID = har_notelinks.NoteID),
har_autos
WHERE har_autos.ID = har_notelinks.AutoID AND har_notes.NoteTypeID = 1)
AS UserNotes,
(SELECT
har_notes.ID,
har_notes.NoteTypeID,
har_notes.Text001,
har_notelinks.Value,
har_notelinks.AutoID,
har_autos.ID
FROM
har_notes
INNER JOIN har_notelinks ON (har_notes.ID = har_notelinks.NoteID), har_autos
WHERE har_autos.ID = har_notelinks.AutoID AND har_notes.NoteTypeID = 2)
AS EngineeringNotes
FROM
har_autos
LEFT OUTER JOIN har_automodels ON (har_autos.ModelID = har_automodels.ID)
LEFT OUTER JOIN har_autotypes ON (har_autos.AutoTypeID = har_autotypes.ID),
har_automakes
LEFT OUTER JOIN har_automakes ON (har_automakes.MakeID = har_automakes.ID)
WHERE
ID = 1
This is the original T-SQL query (really sorry about all of these):
SELECT a.*, mo.Model, mo.MakeID, ma.Make, at.AutoType,
(SELECT n.*, nl.Value
FROM dbo.Notes n
JOIN dbo.NoteLinks nl on (n.ID = nl.NoteID)
WHERE a.ID = nl.AutoID AND n.NoteTypeID = 1
FOR XML PATH('Note'), TYPE
) AS 'UserNotes',
(SELECT n.*, nl.Value
FROM dbo.Notes n
JOIN dbo.NoteLinks nl on (n.ID = nl.NoteID)
WHERE a.ID = nl.AutoID AND n.NoteTypeID = 2
FOR XML PATH('Note'), TYPE
) AS 'EngineeringNotes'
FROM dbo.Autos a
LEFT JOIN dbo.AutoModels mo ON (a.ModelID = mo.ID)
LEFT JOIN dbo.AutoMakes ma ON (mo.MakeID = ma.ID)
LEFT JOIN dbo.AutoTypes at ON (a.AutoTypeID = at.ID)
Little Documentation:
Using PATH Mode
Basic Syntax of the FOR XML Clause
Examples: Using PATH Mode
Constructing XML Using FOR XML
All of the above are from the following search: http://social.technet.microsoft.com/Search/en-US/?Refinement=129&Query=for+xml+path.