What Is Wrong With This FOR XML PATH - sql

I can't seem to figure out why this won't work in MS SQL Server. It seems to not group the lines. Specifically I see:
1036 SC
1036 S1
1094 VO
1094 V1
1094 V2
When I expect to see:
1036 SC,S1
1094 VO,V1,V2
Can someone see something wrong with the syntax?
SELECT DISTINCT oa.acct_cd AS [Account],
STUFF((SELECT ',' + CASE WHEN o.trans_type like 'BUY%' then 'buy of ' else 'sell of ' end + s.ticker AS [text()]
FROM [dbo].[synCRtblTS_ORDER] o INNER JOIN [dbo].[synCRtblCSM_SECURITY] s
ON o.SEC_ID = s.SEC_ID
WHERE o.ORDER_ID = oa.ORDER_ID AND o.status IN ('OPEN','WORK','PENDING')
FOR XML PATH('')), 1, 1, '') [buy/sell]
FROM [dbo].[synCRtblTS_ORDER_ALLOC] oa INNER JOIN tblPortfolio p
ON oa.ACCT_CD = p.Account INNER JOIN tblInvestmentObjective io
ON io.Code = p.InvestmentObjective
WHERE p.AsOfDate = (SELECT AsOfDate FROM tblDateAsOf) and io.CashMgmtStrategy IN ('SC','VO')
GROUP BY oa.ORDER_ID, oa.acct_cd
order by 1

The Information you give is not enough... Within your STUFF you create (and concatenate) string which should contain "buy of" or "sell of". You are missing this information in your output.
It's guessing that your SC, S1, VO values are CashMgmtStrategy entries. You are not concatenating them...
Without deeper knowledge of your tables I cannot solve your problem, but here you'll find a working example of concatenation via FOR XML and STUFF
This code will list all table's names and their columns in a comma delimited list.
SELECT DISTINCT tbls.name AS TableName,
STUFF(
(
SELECT ', ' + cols.name
FROM sys.columns AS cols
WHERE cols.object_id = tbls.object_id
FOR XML PATH('')
), 1, 2, '') AS ColumnList
FROM sys.tables AS tbls

Related

Azure Cognitive Search: How to get collection of strings from a view

I have an index definition on the Azure Cognitive Search and inside this index definition, there is a field called CustomerNames which of type collection (Collection(Edm.String)). Basically, this means my collection result will look like this: CustomerNames: ["Homer Simpson", "Henry Griffin", "Jane Doe"]
Here is the snapshot of the index definition:
Now I have a view that will act as a data source in this cognitive search and this view is:
CREATE VIEW [dbo].[vCog_CustomerActivityAttachmentSearchDocuments]
AS
SELECT
caa.Id,
caa.CustomerActivityId,
caa.AmsAttachmentId,
caa.OriginalFileName,
caa.[FileName],
caa.FileExtension,
caa.ContentType,
caa.[Description],
caa.DocumentTypeId,
caa.AdditionalInfo,
caa.Comments,
ca.CustomerId,
GuidCustomerId = ca.CustomerId,
CustomerNames =
(
SELECT
STRING_AGG(CONVERT(nvarchar(max),cp.FirstName + ' ' + cp.LastName), ', ')
FROM dbo.CustomerPersons AS cp with (nolock)
WHERE cp.CustomerId = c.Id AND cp.LegalEntityName IS NULL
),
CustomerPersons =
(
Select
cp.Id
, cp.CustomerId
, cp.NamePrefix
, cp.FirstName
, cp.MiddleName
, cp.LastName
, cp.DateOfBirth
, cp.HomePhone
, cp.WorkPhone
, cp.CellPhone
, cp.FaxPhone
, cp.Email
, cp.Email2
, cp.LegalEntityName
from
CustomerPersons cp with (nolock)
where
cp.CustomerId = c.Id FOR JSON AUTO
),
c.FirmName,
ca.PolicyId,
PolicyNumber = p.TrimmedPolicyNumber,
caa.CreatedAtUtc,
caa.[RowVersion]
FROM dbo.CustomerActivityAttachments caa with (nolock)
JOIN dbo.CustomerActivities ca with (nolock) on ca.Id = caa.CustomerActivityId
JOIN dbo.Customers c with (nolock) on c.Id = ca.CustomerId
LEFT JOIN dbo.Policies p with (nolock) on p.Id = ca.PolicyId
where IsNull(caa.UpdatedAtUtc, caa.CreatedAtUtc) > GetDate() - 1200
GO
So when I run the indexer on the cognitive search, it is unable to recognize the CustomerNames and throwing the following error:
The data field 'CustomerNames' in the document with key 'XXXXXXXX' has an invalid value of type 'Edm.String' (String maps to Edm.String). The expected type was 'Collection(Edm.String)'.
So my question is how do I change my query in a way that I am getting a JSON array of strings and making it recognizable by the search function?
What I have tried so far: I have tried using this query inside the customerNames:
SELECT
JSON_QUERY('[' + STUFF(( SELECT ',' + '"' + STRING_AGG(CONVERT(nvarchar(max),cp.FirstName + ' ' + cp.LastName), ', ') + '"'
FROM dbo.CustomerPersons AS cp with (nolock)
WHERE cp.CustomerId = c.Id AND cp.LegalEntityName IS NULL
FOR XML PATH('')),1,1,'') + ']') as [CustomerNames]
FOR JSON PATH , WITHOUT_ARRAY_WRAPPER
But this is not solving the problem. Any ideas will be greatly appreciated. Thanks in advance.
you can use Field mapping function - jsonArrayToStringCollection to convert the json array to Index collection
So let your query generate a column with name CustomerNamesJArray and map it to CustomerNames and have a jsonArrayToStringCollection mapping function.
https://learn.microsoft.com/en-us/azure/search/search-indexer-field-mappings#field-mapping-functions

JOIN to change string in column cells

I am working on a query that gets 2 columns from different tables based on JOIN associations:
SELECT DISTINCT co.item_name
,SUBSTRING((
SELECT ',' + ca.attr_val AS [text()]
FROM [CONTRACT_ATTR] CA
WHERE CA.Item_Id = CO.Item_Id
AND ca.field_id = 239
ORDER BY co.item_name
FOR XML PATH('')
), 2, 1000) GM_PROG
FROM [dbo].[CONTRACT] CO;
The 2nd column has numbers and those numbers are keys on a lookup table.
I am trying to figure out how to change the numbers into the correct item_name.
I believe it has to do with the query inside the substring:
SELECT ','+ca.attr_val AS [text()]
FROM [CONTRACT_ATTR] ca
JOIN GM_PROGRAM gm
ON ta.GM_PROG = gm.item_id
WHERE CA.Item_Id = CO.Item_Id
AND ca.field_id = 239
ORDER BY co.item_name
FOR XML PATH ('') ta
), 2, 1000) GM_PROG
This is where I'm at. I doesn't run and I think this is because its trying to reference.
What am I doing wrong and how do I fix it?
You are close, you just need to change ca.attr_val to gm.item_name, your join referenced ta instead of ca (typo I would guess), and probably sort on gm.item_name instead of co.item_name in the subquery:
SELECT DISTINCT co.item_name
,SUBSTRING((
SELECT ',' + gm.item_name AS [text()]
FROM [CONTRACT_ATTR] CA
inner join GM_PROGRAM gm
ON ca.attr_val = gm.item_id
WHERE CA.Item_Id = CO.Item_Id
AND ca.field_id = 239
ORDER BY gm.item_name
FOR XML PATH('')
), 2, 1000) GM_PROG
FROM [dbo].[CONTRACT] CO;

SQL server Stuff on multiple columns

I want to concatenate the value of multiple columns for the same ID.
I managed to concatenate for the first column, but when trying the same syntax for the second I'm having an error "The multi-part identifier EnqAct.[ActionID] could not be bound."
Example_Data_Result
Here I managed to group several MachineName together, as seen in "Column1" but I can't manage to group both the MachineName and Description in their own column
My working Query :
SELECT Enq.[EnquiryID],
Enq.[CustomerName],
DetPrio.[Description],
Stuff((SELECT ', ' + Mach.[MachineName]
FROM [dbo].[Machine] Mach
INNER JOIN [dbo].[MachineEnquiry] MachEnq
ON Mach.[MachineID] = MachEnq.[MachineID]
WHERE Enq.[EnquiryID] = MachEnq.[EnquiryID]
FOR XML PATH('')), 1, 2, ''),
DetAct.[Description]
FROM [dbo].[Enquiry] Enq
INNER JOIN [dbo].[EnquiryAction] EnqAct
ON EnqAct.[EnquiryID] = Enq.[EnquiryID]
INNER JOIN [dbo].[DetailsAction] DetAct
ON DetAct.[ActionID] = EnqAct.[ActionID]
INNER JOIN [dbo].[DetailsPriority] DetPrio
ON DetPrio.[PriorityID] = Enq.[Priority]
GROUP BY Enq.[EnquiryID],
Enq.[CustomerName],
DetPrio.[Description],
DetAct.[Description]
My non working Query :
SELECT Enq.[EnquiryID],
Enq.[CustomerName],
DetPrio.[Description],
Stuff((SELECT ', ' + Mach.[MachineName]
FROM [dbo].[Machine] Mach
INNER JOIN [dbo].[MachineEnquiry] MachEnq
ON Mach.[MachineID] = MachEnq.[MachineID]
WHERE Enq.[EnquiryID] = MachEnq.[EnquiryID]
FOR XML PATH('')), 1, 2, ''),
Stuff((SELECT ', ' + DetAct.[Description]
FROM [dbo].[DetailsAction] DetAct
INNER JOIN [dbo].[EnquiryAction] EnqAct
ON EnqAct.[ActionID] = DetAtc.[ActionID]
WHERE Enq.[EnquiryID] = EnqAct.[EnquiryID]
FOR XML PATH('')), 1, 2, '')
FROM [dbo].[Enquiry] Enq
INNER JOIN [dbo].[DetailsPriority] DetPrio
ON DetPrio.[PriorityID] = Enq.[Priority]
GROUP BY Enq.[EnquiryID],
Enq.[CustomerName],
DetPrio.[Description]
Both work the same way, I have a table Enquiry which will have an EnquiryID.
then in my table EnquiryAction or MachineEnquiry I will have entitys with an EnquiryID and an Action/Machine ID
Then in my DetailsAction/Machine Table I will have the Action/Machine ID, and the string I want to get and concatenate.
Why am I having an error and is it possible to achieve what I'm trying to do ?

SQL Concatenation using XML Path - multiple rows with multiple table references

I am trying to use the XML Path to run SQL Concatenation but I am running into a bit of a problem. I have one table that is being used as a reference table for values I want to concatenate.I have 3 columns in the reference table (M.PROD, S.PROD, & REF NUMB).
M.PROD=====>S.PROD======>Ref Numb
1===========>_===========>981024583
2===========>_===========>981024719
3===========>A===========>981024605
3===========>B===========>981024669
4===========>A===========>981024688
4===========>B===========>981024706
4===========>C===========>981024723
5===========>_===========>981024742
6===========>_===========>981024742
I have the main tables where the m.prod and s.prod are used to match the reference table for Ref Numb values. What I want to do is concatenate the Ref Numb values based on what is being selected in main tables. The out put I am looking for is this:
M.Prod======>Ref Numb
1===========>981024583
2===========>981024719
3===========>981024605, 981024669
4===========>981024688, 981024706, 981024723
5===========>981024742
6===========>981024742
I am using the following query:
SELECT DISTINCT P.PRODUCT,
(STUFF((SELECT DISTINCT ',' + P1.REFNUMB AS [text()]
FROM PRODUCT P1
WHERE P1.PRODUCT = P.PRODUCT
FOR XML PATH('')), 1, 1, ''))
FROM PRODUCT P
This gives me the output of:
M.Prod======>Ref Numb
1===========>981024583
2===========>981024719
3===========>981024605, 981024669
4===========>981024688, 981024706, 981024723
5===========>981024742
6===========>981024742
However, there are times where all the s.prod are not in the main tables. So for this I use this query:
SELECT DISTINCT P.PRODUCT,
(STUFF((SELECT DISTINCT ',' + P1.REFNUMB AS [text()]
FROM PRODUCT P1
WHERE P1.PRODUCT = P.PRODUCT AND P1.SUBID = P.SUBID
FOR XML PATH('')), 1, 1, ''))
FROM PRODUCT P
This query produces following output for me:
M.Prod======>Ref Numb
1===========>NULL
2===========>NULL
3===========>981024605
3===========>981024669
4===========>981024688
4===========>981024723
5===========>NULL
6===========>NULL
The output I need in these cases is:
M.Prod======>Ref Numb
1===========>981024583
2===========>981024719
3===========>981024605, 981024669
4===========>981024688, 981024723
5===========>981024742
6===========>981024742
Any solution for this will be greatly appreciated, Thank you.
I'm not sure if I understood your question correctly, but try this:
SELECT DISTINCT P.PRODUCT,
(STUFF((SELECT DISTINCT ',' + P1.REFNUMB AS [text()]
FROM PRODUCT P1
WHERE P1.PRODUCT = P.PRODUCT
AND (P1.SUBID = P.SUBID OR P1.SUBID IS NULL AND P.SUBID IS NULL)
FOR XML PATH('')), 1, 1, ''))
FROM PRODUCT P

Parsing error when creating view

I have a view which takes multiple rows and Comma Separated Values (CSV) from table columns with data.
It was working well and I got the results that I needed. Now the view has some parsing error like:
Error in WHERE clause near '('. Unable to parse query text.
Can someone help? Here is my code:
SELECT dbo.table1.title,
Stuff((SELECT ', ' + CONVERT(NVARCHAR(4000), dbo.table3.uid) AS [text()]
FROM dbo.table2
INNER JOIN dbo.table3
ON dbo.table3.uid = dbo.table2.FK_Group
WHERE dbo.table3.uid = dbo.table2.FK_Group
AND dbo.table3.company = dbo.main.company
AND dbo.table2.FK_Version = dbo.table1.fk_Version
AND dbo.main_version.uid = dbo.table1.fk_Version
FOR XML PATH('')), 1, 1, '') AS groupName
FROM dbo.main_version
INNER JOIN dbo.[main]
ON dbo.version.fk_main = dbo.[main].uid
INNER JOIN dbo.main_schema
ON dbo.[main].fk_SCHEMA = dbo.main_schema.uid
INNER JOIN dbo.table1
ON dbo.version.uid = dbo.table1.fk_Version
WHERE ( dbo.main_version.active = 1 )