Maximum 2 semi join sub-selects are allowed (Salesforce) - salesforce

Fairly new to APEX (Salesforce development) and i found an issue with one of SOQL statements...
This is the code that is creating the problem.. i did some research and i found that i need to create a set of id's instead of using another select statement for OpportunityId and then just reference it on the query...
String sumAvgQuery = 'SELECT StageName, COUNT(ID) opps, SUM(Amount) total, AVG(SVC_Svc0StageAge__c) Svc0, AVG(SVC_Svc1StageAge__c) Svc1, ' +
'AVG(SVC_Svc2StageAge__c) Svc2, AVG(SVC_Svc3StageAge__c) Svc3, AVG(SVC_Svc4StageAge__c) Svc4, ' +
'AVG(SVC_Svc5StageAge__c) Svc5, AVG(SVC_Svc6StageAge__c) Svc6, AVG(SVC_Svc7StageAge__c) Svc7, ' +
'AVG(SVC_Svc8StageAge__c) Svc8, AVG(SVC_Svc9StageAge__c) Svc9 ' +
'FROM Opportunity ' +
'WHERE StageName in (' + BTG_Utility.OPPORTUNITY_STAGES + ') ' +
'AND ID in (SELECT OpportunityId FROM OpportunityTeamMember WHERE UserId = \'' + String.escapeSingleQuotes(userId) + '\') ' +
((cluster != null && cluster != '') ? 'AND SVC_AccountCluster__c = \'' + String.escapeSingleQuotes(cluster) + '\' ' : '') +
((region != null && region != '') ? 'AND SVC_AccountRegion__c = \'' + String.escapeSingleQuotes(region) + '\' ' : '') +
((country != null && country != '') ? 'AND CARE_AccountCountry__c = \'' + String.escapeSingleQuotes(country) + '\' ' : '') +
((product != null && product != '') ? ' AND Id in (SELECT OpportunityId FROM OpportunityLineItem Where Product2.Name = \'' + String.escapeSingleQuotes(product) + '\' and Opportunity.IsClosed = FALSE) ' : '') +
'GROUP BY StageName)';
Can you please help me on how to do this ? Really appreciate the help !

If you want to use a collection like a Set in Apex you need to populate the set first, then you can use the variable name in your SOQL query with a : in front of it.
So for example:
// First populate the Set with ID's using SOQL
set<Account> inputSet = new set<Account>([SELECT Id FROM Account LIMIT 5]);
//Alternatively manually populate the set
// set<String> inputSet = new set<String>();
// List<Account> accounts = new List<Account>([SELECT custom_id__c FROM Account LIMIT 5]);
// for (Account acc : accounts) {
// inputSet.add(acc.custom_id__c);
// }
System.debug('inputSet: ' + inputSet);
// Use the set with the data
List<Contact> contacts = [SELECT id FROM Contact where custom_id__c in :inputSet];
System.debug('contacts: ' + contacts);
Hope that helps.
Mohamed Imran

Related

Equivalent of LINQ let clause in SQL Server

I have the following code in linq:
(from emp in db.EMPLOYEES
from tab in db.CATEGORY.Where(o => o.Id == 19).DefaultIfEmpty()
on emp.Id = tab.EMP_ID
let url = (!tab.PAGE.StartsWith("/") && !tab.PAGE.StartsWith("#"))
? tab.PAGE + "(" + emp.EMP_VALUE + ")"
: tab.PAGE.Contains("?")
? tab.PAGE + "&Id=" + emp.EMP_VALUE + "&fromSSR=" + BooleanStr.True
: tab.PAGE + "?Id=" + emp.EMP_VALUE + "&fromSSR=" + BooleanStr.True
select new EmployyeModel
{
Id = emp.Id,
RedirectURL = tab.NOT_CH_APPROVAL == BooleanStr.True ? url + "&userCanApprove=1" : url,
}
I need to write the above query in sql server and need help concerning the "let url" part.
How do I translate let in sql server and use it in the select?
Thanks for any help.
Create a user-defined function:
CREATE FUNCTION fnBuildUrl (
#page varchar(100),
#emp_value varchar(100)
)
RETURNS VARCHAR(1000)
AS
BEGIN
DECLARE #url varchar(1000)
SELECT #url = CASE WHEN LEFT(#page, 1) = '/' THEN
#page + '(' + #emp_value + ')'
ELSE
CASE WHEN CHARINDEX('?', #page) > 0 THEN
#page + '&Id=' + #emp_value + '&fromSSR=T'
ELSE #page + '?Id=' + #emp_value + '&fromSSR=T' END
END
RETURN #url
END
GO
Then call it in your SELECT:
SELECT emp.Id,
CASE WHEN tab.NOT_CH_APPROVAL = 'T' THEN dbo.fnBuildUrl(tab.PAGE, emp.EMP_VALUE) + '&userCanApprove=1'
ELSE dbo.fnBuildUrl(tab.PAGE, emp.EMP_VALUE) END AS RedirectURL
FROM EMPLOYEES emp
LEFT OUTER JOIN CATEGORY tab
ON tab.EMP_ID = emp.Id
AND tab.Id = 19

Need help adding WHERE clause in pre-written SQL statement

Preface: my SQL is rudimentary. I received a SQL query from a vendor, it selects and exports every single employee comment and other data from a few different DBs as CSV meant for import, it was written by them but they're not helping with this request. The query is pulling so much data it makes a large time consuming file for import. So I want to add to / modify the query to have a "WHERE date > whateverdate" to narrow my results to recent data. For example, I want to pull only comments entered in the past 2 days.
The column I'm looking to add the clause for is the column "A.CMS502", defined as datetime. I believe this is the only relevant column in this query. An example date in this column is "2003-10-06 17:05:21.000". I am using SQL Server 2008 if it helps. Is it possible here? Thank you.
SELECT
'ID,Acct/LnNbr,NoteCreatedDate,CollectorId,ApplytoAll,Note'
UNION ALL
SELECT
ID + ',' + ID + ',' + NoteCreatedDate + ',' + CollectorId + ',' + 'No' + ',' + Note
FROM
(SELECT
CASE WHEN SUBSTRING(A.CMS301,LEN(A.CMS301),1) = 'S'
THEN SUBSTRING(A.CMS301,1,LEN(A.CMS301) - 1)
ELSE A.CMS301
END + '-' +
CASE WHEN SUBSTRING(A.CMS301,LEN(A.CMS301),1) = 'S'
THEN 'S' ELSE 'L'
END AS [ID],
REPLACE(CONVERT(VARCHAR, A.CMS501, 10), '-', '') AS [NoteCreatedDate],
CASE WHEN U.CMS1201 IS NOT NULL
THEN U.CMS1205 + ' ' + U.CMS1204
ELSE (SELECT CMS1205 + ' ' + CMS1204 FROM sysUSER WHERE CMS1201 = 'PSUSER')
END AS CollectorId,
CAST(A.CMS512 AS NVARCHAR(MAX)) AS [Note]
FROM
ACTIVITY AS A
LEFT JOIN
sysUSER AS U ON A.CMS503 = U.CMS1201
WHERE
A.CMS504 NOT IN (411,500,511,711,804,900,901,903,907,2000,999777)
AND A.CMS504 NOT BETWEEN 1102 AND 1199) AS S
Try this, this will output last 2 days.
SELECT 'ID,Acct/LnNbr,NoteCreatedDate,CollectorId,ApplytoAll,Note'
UNION ALL
SELECT ID + ',' + ID + ',' + NoteCreatedDate + ',' + CollectorId + ',' + 'No' + ',' + Note
FROM
(
SELECT CASE WHEN SUBSTRING(A.CMS301,LEN(A.CMS301),1) = 'S' THEN SUBSTRING(A.CMS301,1,LEN(A.CMS301) - 1) ELSE A.CMS301 END
+ '-' + CASE WHEN SUBSTRING(A.CMS301,LEN(A.CMS301),1) = 'S' THEN 'S' ELSE 'L'
END AS [ID]
,REPLACE(CONVERT(varchar,A.CMS501,10),'-','') AS [NoteCreatedDate]
,CASE WHEN U.CMS1201 IS NOT NULL THEN U.CMS1205 + ' ' + U.CMS1204 ELSE
(SELECT CMS1205 + ' ' + CMS1204 FROM sysUSER WHERE CMS1201 = 'PSUSER')
END AS CollectorId
,CAST(A.CMS512 AS nvarchar(max)) AS [Note]
FROM ACTIVITY AS A
LEFT JOIN sysUSER AS U
ON A.CMS503 = U.CMS1201
WHERE A.CMS504 NOT IN (411,500,511,711,804,900,901,903,907,2000,999777)
AND A.CMS504 NOT BETWEEN 1102 AND 1199
AND A.CMS502 >= DATEADD(D, -2, GETDATE())
) AS S

FOR XML PATH : DISTINCT sort cost increased

I'd like to put together only unique values in the concatenated string. My code is currently:
SELECT PITEM2.orderid,
(SELECT ISNULL(E.FIRSTNAME + ' ' + E.LASTNAME,' ') + ', ' AS [text()]
FROM F_PURCHASEITEM PITEM1
LEFT JOIN E__EMPLOYEE E ON e.EMPLOYEEID=PITEM1.APPROVED_BY
WHERE PITEM1.ORDERID = PITEM2.ORDERID
AND PITEM1.PISTATUS =
(SELECT POSTATUSID
FROM F_POSTATUS
WHERE POSTATUSNAME = 'Invoice Received') GROUP By ISNULL(E.FIRSTNAME + ' ' + E.LASTNAME,' ') + ', '
FOR XML PATH ('') ) [EmployeeNames]
FROM F_PURCHASEITEM PITEM2
WHERE ORDERID=305089 Group By PITEM2.orderid
This gives me the output I'd expect, but the cost of the query increased and execution plan shows the Distinct sort as 46.3%.
How can I decrease the cost for this distinct?

Cannot set the Order By to my SQL Statement, need a workaround

I understand that I cannot have the SQL order by PaymentDate but my results come out not in Payment Date Order. Is there an easy way I can make sure the PERIOD column is in actual date order?
The SQL below works perfect its just if i add "--order by f.PaymentDate" I get 'Column "PaymentItem.PaymentDate" is invalid in the ORDER BY clause because it is not contained in either an aggregate function or the GROUP BY clause.' So i'm trying to think how to get around this
select g.SiteDescription,
case a.Surname when '' then a.Company else a.Surname + ', ' + isnull(a.Forename,'') end as Landowner,
h.PaymentTypeDesc as [RentalElection],
d.RelevantProportion,#IN_showRelevantProportion as ShowRelevantProportion,
g.SiteId,a.LandownerId,e.PaymentTypeId,e.PaymentCategoryId,
case #IN_OutputFormat
when 'Monthly' then
convert(char(3), f.PaymentDate, 0) + '-' + ltrim(Year(f.PaymentDate))
when 'Annually' then
ltrim(Year(f.PaymentDate))
else
ltrim(Year(f.PaymentDate)) + ' Qtr ' + ltrim(datepart(quarter,f.PaymentDate))
end as Period,
sum(isnull(f.ActualPayment,0)) as Total
from
[Site] g,
Landowner a,
[Site] c,
SiteAgreement d,
Payment e,
PaymentItem f,
PaymentType h
where a.LandownerId = d.LandownerId
and g.SiteId = d.SiteId
and e.SiteAgreementId = d.SiteAgreementId
and f.PaymentId = e.PaymentId
and e.PaymentTypeId = h.PaymentTypeId
and f.paymentdate between #IN_daysFrom and #IN_daysTo
and isnull(f.ActualPayment,0) != 0
group by g.SiteDescription,
case a.Surname when '' then a.Company else a.Surname + ', ' + isnull(a.Forename,'') end,
h.PaymentTypeDesc,
d.RelevantProportion,
g.SiteId,a.LandownerId,e.PaymentTypeId,e.PaymentCategoryId,
case #IN_OutputFormat
when 'Monthly' then
convert(char(3), f.PaymentDate, 0) + '-' + ltrim(Year(f.PaymentDate))
when 'Annually' then
ltrim(Year(f.PaymentDate))
else
ltrim(Year(f.PaymentDate)) + ' Qtr ' + ltrim(datepart(quarter,f.PaymentDate))
end
--order by f.PaymentDate
Order by the entire expression that uses your Payment Date column:
ORDER BY case #IN_OutputFormat
when 'Monthly' then
convert(char(3), f.PaymentDate, 0) + '-' + ltrim(Year(f.PaymentDate))
when 'Annually' then
ltrim(Year(f.PaymentDate))
else
ltrim(Year(f.PaymentDate)) + ' Qtr ' + ltrim(datepart(quarter,f.PaymentDate))
end
I got this going by just ordering at a string in format YYYY-MM. The MM needed left padded 0 of course:
CONVERT(CHAR(4), f.PaymentDate, 120) + ' ' + right('0'+ rtrim(ltrim(datepart(mm,f.PaymentDate))), 2)

More than 2 columns in a CONCAT function

In SQL Server 2012 I want to concat 5 columns into 1 but in the query it works but when I put in in a view it gives me an error like
Msg 174, Level 15, State 1, Line 3
The CONCAT function requires 2 argument(s).
What's the problem so I can fix it because concat is a good function for concatenate more than 1 column because if its null they make it empty..
CODE:
SELECT
'Aan ' + A.Name AS 'Naam',
{ fn CONCAT('T.a.v. ', C.Salutation + ' ', C.FirstName + ' ', C.MiddleName + ' ', C.LastName) } AS 'T.a.v.',
ISNULL(ISNULL(A.Address1_Line2, A.Address1_Line1),
C.Address1_Line2) AS 'Adres',
ISNULL(A.Address1_PostalCode + ' ' + A.Address1_City, A.Address2_PostalCode + ' ' + A.Address2_City) AS 'Woonplaats',
'heer' + ' ' + ISNULL(C.MiddleName + ' ', N'') + ISNULL(C.LastName, N'') AS 'Aanhef'
FROM
dbo.Account AS A
FULL OUTER JOIN
dbo.Contact AS C ON A.Name = C.AccountIdName
WHERE
(C.Salutation = 'Dhr.') AND (A.Name IS NOT NULL) AND (A.StatusCode = 1)
AND (ISNULL(C.StatusCode, 1) = 1) OR (C.Salutation = 'dhr.') AND (A.Name IS NOT NULL) AND (A.StatusCode = 1) AND (ISNULL(C.StatusCode, 1) = 1)
Hy. If you want to use CONCAT as a canonical function {fn CONCAT(...)} into view designer, there is a work-around solution in order to concatenate more than two columns/chars.
You can use CONCAT inside CONCAT like this:
Let's suppose you want to concatenate two codes into a single one with a "-" between
column1 = 123456
column2 = 0001
{fn CONCAT({fn CONCAT(column1, '-')}, column2)}
As a result you will have: 123456-0001
There must be an error somewhere else in your view!!
Ok, then what I did with your code was to change this line
{ fn CONCAT('T.a.v. ', C.Salutation + ' ', C.FirstName + ' ', C.MiddleName + ' ', C.LastName) } AS 'T.a.v.'
to this
CONCAT('T.a.v. ', C.Salutation + ' ', C.FirstName + ' ', C.MiddleName + ' ', C.LastName) AS 'T.a.v.'
Edit:
Just to explain the difference in code, is that the one with { fn ....} is a Canonical function and microsoft promise that it will work on all ODBC connections.
From MSDN:
Canonical functions are functions that are supported by all data providers, and can be used by all querying technologies. Canonical functions cannot be extended by a provider.
I had the same problem and all the other answers did not work for me and i did not want to use the one from Andrei.
I managed to create the view using a create view statement.
CREATE VIEW ViewName AS
SELECT
'Aan ' + A.Name AS 'Naam',
{ fn CONCAT('T.a.v. ', C.Salutation + ' ', C.FirstName + ' ', C.MiddleName + ' ', C.LastName) } AS 'T.a.v.',
ISNULL(ISNULL(A.Address1_Line2, A.Address1_Line1),
C.Address1_Line2) AS 'Adres',
ISNULL(A.Address1_PostalCode + ' ' + A.Address1_City, A.Address2_PostalCode + ' ' + A.Address2_City) AS 'Woonplaats',
'heer' + ' ' + ISNULL(C.MiddleName + ' ', N'') + ISNULL(C.LastName, N'') AS 'Aanhef'
FROM dbo.Account AS A
FULL OUTER JOIN
dbo.Contact AS C ON A.Name = C.AccountIdName
WHERE
(C.Salutation = 'Dhr.') AND (A.Name IS NOT NULL) AND (A.StatusCode = 1)
AND (ISNULL(C.StatusCode, 1) = 1) OR (C.Salutation = 'dhr.') AND (A.Name IS NOT NULL) AND (A.StatusCode = 1) AND (ISNULL(C.StatusCode, 1) = 1)
I got the same error. Here is how it happened. I used the query/view builder in SQL Server (2014) Management Studio. I typed the function "CONCAT (...", yet it transformed it to "{fn CONCAT(...)}". Then I got the error despite having more than one item.
I got rid of the "{fn ... }" and it worked fine.
Use CONCAT_WS instead of CONCAT.
It will be kept untouched in a view even if you use it in design mode in SSMS, and with it you can specify a string separator that will not be appended at the end of the string.
Example:
select CONCAT_WS('; ',NULL,'Frank',NULL,'Mary')
The result will be Frank; Mary
create CONCAT FUNCTION in view SQL Server must requires 2 arguments. So you can try this :
SELECT
concat(
concat('T.a.v. ', C.Salutation + ' '),
concat(C.FirstName + ' ', concat(C.MiddleName + ' ', C.LastName))
) AS 'T.a.v.'
For me that's worked so fine !
select (column1 + column2 + column3) as myconcat from myview
instead {fn CONCAT({fn CONCAT(column1, '-')}, column2)}
I had this issue when I wanted to create view using designer and the ssms designer automatically added fn{ exp ….} but I instead used script,
Cerate View ViewName
my concat script
this worked with no issue

Resources