I'm trying to write a SOQL query that pulls back User information along with the DefaultDivision's name. When executing the following:
Select u.Email, u.FirstName, u.LastName, u.DefaultDivision from User u
the value for 'DefaultDivision' is an Id (like 02d3498202020222) instead of the friendly name (like North America). I know that the DefaultDivision maps to the Division object's Id, but how do I get the name?
I have tried things like:
select u.Email, (select Name from Division where Id = u.DefaultDivision) from User u
but that doesn't work because there is no direct relationship (and yet, there is...!).
Unlike SQL, SOQL does not support subqueries of the type you have given there.
In most cases with SOQL where there is an explicit relationship defined, you can query data from that explicit relationship directly, like
select u.Email, u.DefaultDivision.Name from User u where Id=blahblahblah
However there are some cases where such a relationship is not explicitly defined, and I believe DefaultDivision is one of those (so in fact my query above probably will not work). When this is the case, there's no single-query way to get the information you want -- you'll have to first query on divisions and their IDs, then query users with their DefaultDivision, and then resolve the division names from the IDs using the results of the first query.
Fortunately this type of situation doesn't happen very often anymore, but in using Divisions you're plumbing the depths of Salesforce.com a bit so you may find some unusual stuff there.
Related
I have a query in SQL that I want to convert to SOQL.
I know that a LEFT JOIN is not possible in SOQL. But I don't how to write this in SOQL.
I want to check Cases without Decision__c. There is a Lookup relation between Case(Id) and Decision__c (Case__c).
That would be in SQL:
Select Id
FROM Case
LEFT JOIN Decision__c D
on D.Case__c = Case.Id
WHERE Case__c IS NULL
I exported all Cases (Case) and all Decisions (Decision__c) to Excel. With a VLOOKLUP I connected the Case with the decision. An error = no linked decision.
I exported the objects in PowerQuery and performed a left join to merge the two queries. Those with no decision where easily filtered (null value).
So I got my list of Cases without Decision, but I want to know if I can get this list with a SOQL query, instead of these extra steps.
To simply put it, you must, literally, select cases without Decision__c, the query should look like this:
SELECT Id FROM Case WHERE Id NOT IN(SELECT Case__c FROM Decision__c)
Although we don't JOINs in Salesforce we can use several "subqueries" to help filter records.
refer to the following link:
https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select.htm
I have a table with about 50,000 records (a global index of corporate and government bonds).
I would like the user to be able to filter this master index firstly into a smaller subset index (based on permanent logic), and then apply further run time criteria that vary each time.
For example, let's say the user wanted to start from one of many subset indices of bonds, let's say of government bonds only, rather than government and corporate bonds, and also only wanted the US$ government bond index specifically. This would be a permanently defined subset of the master index, with a where clause something like "[Level1]='Government' AND [Currency]='USD' AND [CountryCode]='US'"
At run time, the user would additionally request additional criteria, say for example "AND [IssueSize] > 1,000,000,000 AND [Yield] > 0.0112".
I initially thought of having a separate table that stored the different criteria for these permanent sub-indices as where clauses, for example it might have columns "IndexCode, IndexLogic", and using the example above the values would be "UST", "[Level1]='Government' and [Currency]='USD' AND [CountryCode]='US'", and there would be dozens of rows in this table defining commonly used bond indices.
I had originally thought of creating a dynamic string at run-time, where the user supplies their choice of sub-index code ('UST' in the example above), which then adds the relevant where conditions, and any additional criteria passed as separate parameters, and then doing an exec(#tsql) type command. I had also thought of perhaps having a where clause that was a function call, but this seems very inefficient?
Is the dynamic string method the best way of doing this, or is there a better way involving some kind of 'eval' function equivalent which can take a field value and use that as a where clause?
The problem here is you don't know in advance what the filtered index is.
A solution I have used in this instance, where the filtered index can often change is to grab the definition of the filter back into the client app, and use that to dynamically generate the SQL batch. You can also do this with dynamic SQL in a stored procedure:
SELECT ISNULL(
(SELECT i.filter_definition
FROM sys.indexes i
WHERE i.object_id = OBJECT_ID(#tablename) AND
i.name = #indexname AND has_filter = 1),
'(1=1)');
You pass the table name, and the index name, and you get back the exact definition for the index. This has the benefit of if the index is dropped, the condition becomes (1=1) i.e. every row. You can change this to (1=0) to return nothing instead.
Then you concat this into your dynamic query like so:
SELECT *
FROM table
WHERE regular_conditions_here
AND concated_filter_here
If you are joining other tables, I would advise you to subquery the filter, otherwise you many get column clash as there are no aliases.
SELECT *
FROM (SELECT * FROM table WHERE concated_filter_here) table
JOIN othertables etc
WHERE regular_conditions_here
I am unable to get the user information from LoginHistory object.
I tried using this
SELECT User.FirstName FROM LoginHistory
but not it says
INVALID_FIELD:
SELECT User.FirstName FROM LoginHistory
^
ERROR at Row:1:Column:8
Didn't understand relationship 'User' in field path. If you are attempting to use a custom relationship, be sure to append the '__r' after the custom relationship name. Please reference your WSDL or the describe call for the appropriate names.
System.debug(JSON.serializePretty(LoginHistory.UserId.getDescribe())); shows "null" as the "relationshipName". Not all relations allow going "up" this way, you can check my answer https://salesforce.stackexchange.com/a/23507/799 for some examples.
You'll need to make-do with two separate queries. There's equally no way to reverse it because the related list doesn't have name either. This won't work:
SELECT FirstName,
(SELECT Id FROM LoginHistories LIMIT 10)
FROM User
LIMIT 10
Maybe there's an idea you can upvote? Maybe you'll have more luck with Event Monitoring. Haven't used it personally but my understanding is it can track login, logout, exporting a report... Might be easier to query.
I am currently creating a simple report in Crystal Reports with two tables:
{Table1.group_name_id} --> {Table2.technical_group_id}
Table 1 holds all of the groups; ID's, Names etc
Table 2 holds only the technical groups ID
With these two tables linked it means the only records that will return are those where technical groups are involved, perfect! But now I want to add a dynamic parameter to return the Technical Group Names for the End User to select.
Because {Table2} only holds one field (the ID) which links to {Table1}'s ID, I have to perform the Parameter selection on {Table1}'s name field.
But this is pulling back all of {Table1}'s names and is discounting the Join on {Table2} even with an enforced join present.
Is there a way to force it to only pull back {Table1}'s names as long as it matches the JOIN between {Table1} and {Table2}?
Thanks in advance!
Edit (additional information)
As I thought - the problem was Crystal Reports was not recognising the JOIN when displaying the parameter values.
After some reading, I found out that the JOINS are only recognised when the query is passed to the database (logically). So when selecting a Parameter, it doesn't recognise the JOINS.
I got around this by creating a custom SQL command, forcing it to only pull back the groups in the second table.
First, please confirm your join INNER JOIN.
For Addition,
You can pass the User Input as a parameter in to the crystal report and use this {#Parameter} to filter the result set using SelectionFormula in Crystal Report.
Or you can even set the selectionformula itself from the application.
I want to create a join on two custom objects joining on the Name field. Normally joins require a lookup or master-detail relationship between the two objects, but I just want to do a text match.
I think this is a Salesforce limitation but I couldn't find any docs on whether this was so. Can anyone confirm this?
Yes, you can make a join (with dot notation or as subquery) only if there's a relationship present. And relationships (lookup or master-detail) can be made only by Id. There are several "mutant fields" (like Task.WhoId) but generally speaking you can't write a JOIN in SOQL and certainly can't use a text column as a foreign key.
http://www.salesforce.com/us/developer/docs/soql_sosl/Content/sforce_api_calls_soql_relationships.htm#relate_query_limits
Relationship queries are not the same as SQL joins. You must have a
relationship between objects to create a join in SOQL.
There are some workarounds though. Why exactly do you need the join?
Apex / SOQL - have a look at SOQL in apex - Getting unmatched results from two object types for example. Not the prettiest thing in the world but it works. If you want to try something really crazy - SOSL that would search your 2 objects at the same time?
Reports - you should have no problem grouping by text field - that means a joined report might give you results you're after. Since Winter'13 joined reports allow charts and exporting, that was quite a limiting factor...
Easy building of links between data - use external ids and upsert operation, especially if you plan to load data from outside SF easily. Check my answer for Can I insert deserialized JSON SObjects from another Salesforce org into my org?
Uniqueness constraints - you can still mark fields as required & unique.
Check against "dictionary" of allowed values - Validation rule with VLOOKUP might do what you're after.