SQL on salesforce not applicable - sql

I have this code on SQL and I am trying to use it in Salesforce. I get an error that it does not recognize the JOIN function.
Here is the code :
SELECT
lu_table.Name,
lu_table.id,
primary.Start_date,
primary.end_date,
secondary.metric
FROM primary
LEFT JOIN secondary
ON primary.xyz= secondary.xyz
LEFT JOIN lu_table
ON primary.id = lu_table.id
group by lu_table.Name;

Salesforce has own query language named SOQL. This language has no JOIN function. Here is the reference
SOQL syntax:
SELECT fieldList [subquery][...]
[TYPEOF typeOfField whenExpression[...] elseExpression END][...]
FROM objectType[,...]
[USING SCOPE filterScope]
[WHERE conditionExpression]
[WITH [DATA CATEGORY] filteringExpression]
[GROUP BY {fieldGroupByList|ROLLUP (fieldSubtotalGroupByList)|CUBE (fieldSubtotalGroupByList)}
[HAVING havingConditionExpression] ]
[ORDER BY fieldOrderByList {ASC|DESC} [NULLS {FIRST|LAST}] ]
[LIMIT numberOfRowsToReturn]
[OFFSET numberOfRowsToSkip]
[FOR {VIEW | REFERENCE}[,...] ]
[ UPDATE {TRACKING|VIEWSTAT}[,...] ]
EDIT
You query in SOQL it'd be something like that.
SELECT
Start_date,
end_date,
(SELECT Id, Name FROM lu_table),
(SELECT metric FROM secondary)
FROM primary
WHERE xyz IN (SELECT xyz FROM secondary WHERE condition)
AND Id IN (SELECT id FROM lu_table WHERE condition)
GROUP BY lu_table.Name;
But I'm not sure that in such form the query will not reach SF limits

Related

How to make table name dynamic Postgresql

This is my query which join the result of query performed in postgresql from one database with another query from another database the thing is the table's name in the seconde database depend on the result of the query that target the first database. Here is the query:
select
gdr.id ,
attachment_id ,
state ,
gdr.user_id ,
gdr.document_id ,
internal_code,
ia."name" ,
gdd.id,tb2.col_3095
from
gediso_document_record as gdr
inner join ir_attachment ia on ia.id = gdr.attachment_id
inner join gediso_document_descriptor gdd on gdd.document_id = gdr.document_id
inner join (
select * from dblink('dbname=gediso_document','select id,record_id,col_3095 from doc_id_'||gdr.id)
AS tb2(id int,record_id int,col_3095 varchar)
)AS tb2 ON tb2.record_id = gdr.id
where
gdr.user_id =2031
limit 100
The problem resides in this line { select * from dblink('dbname=gediso_document','select id,record_id,col_3095 from doc_id_'||gdr.id) }
It won't allow me to use gdr.id
Can anyone help me please ? Thank you in advance.

SQL add a column with COUNT(*) to my query

I need to add a column with the content of this query :
SELECT COUNT(*) FROM account_subscriptiongroups WHERE account_subscriptiongroups.active = true AND account_subscriptiongroups.user_id = account_user.id
to this query :
SELECT
account_user.id as user_id, account_user.email, account_user.first_name, account_user.last_name, account_user.phone,
account_subscriptiongroup.id as sub_group_id,
account_adminaction.description,
account_adminaction.id as admin_action_id,
account_adminaction.created_on as subscription_ended_on
FROM
account_adminaction
LEFT JOIN
account_user ON account_user.id = account_adminaction.user_id
LEFT JOIN
account_subscriptiongroup ON account_adminaction.sub_group_id = account_subscriptiongroup.id
WHERE
account_adminaction.created_on >= '2021-04-07' AND account_adminaction.created_on <= '2021-04-13' AND
((account_adminaction.description LIKE 'Arrêt de l''abonnement%') OR (account_adminaction.description LIKE 'L''utilisateur a arrêté%'))
ORDER BY
subscription_ended_on
I tried adding a LEFT JOIN like that:
LEFT JOIN
account_subscriptiongroup all_sg ON account_user.id = account_subscriptiongroup.user_id
with this line in my WHERE statement :
AND all_sg.active = true
and this line in my SELECT :
COUNT(all_sg.id)
but I get an error :
ERROR: column "account_user.id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 2: account_user.id as user_id, account_user.email, account_us...
^
I don't understand how I could perform this action properly
To count something, you need to specify a group where that count applies.
So every column that you select (and is not used in an aggregate function, like COUNT or SUM), you need to mention in the GROUP BY clause.
Or to put it the other way around: the non-aggregate columns must apply to all rows that are contained in that particular COUNT.
So between the WHERE and ORDER BY clauses, add a GROUP BY clause:
GROUP BY account_user.id, account_user.email, account_user.first_name, account_user.last_name, account_user.phone,
account_subscriptiongroup.id,
account_adminaction.description,
account_adminaction.id,
account_adminaction.created_on
If, on the other hand, you want a count from a different table, you can add a sub-select:
SELECT
account_user.id as user_id, account_user.email, account_user.first_name, account_user.last_name, account_user.phone,
account_subscriptiongroup.id as sub_group_id,
account_adminaction.description,
account_adminaction.id as admin_action_id,
account_adminaction.created_on as subscription_ended_on,
(SELECT COUNT(*)
FROM account_subscriptiongroups
WHERE account_subscriptiongroups.active = true
AND account_subscriptiongroups.user_id = account_user.id) AS groupcount
FROM
account_adminaction
LEFT JOIN
account_user ON account_user.id = account_adminaction.user_id
You can left join to to a derived table that does the grouping and counting:
SELECT au.id as user_id, au.email, au.first_name, au.last_name, au.phone,
asg.id as sub_group_id,
ad.description,
ad.id as admin_action_id,
ad.created_on as subscription_ended_on,
asgc.num_groups
FROM account_adminaction ad
LEFT JOIN account_user au ON au.id = ad.user_id
LEFT JOIN account_subscriptiongroups asg on ON ad.sub_group_id = asg.id
LEFT JOIN (
SELECT user_id, count(*) as num_groups
FROM account_subscriptiongroups ag
WHERE ag.active
GROUP by user_id
) asgc on asgc.user_id = au.id
WHERE ad.created_on >= '2021-04-07'
AND ad.created_on <= '2021-04-13'
AND ((ad.description LIKE 'Arrêt de l''abonnement%') OR (ad.description LIKE 'L''utilisateur a arrêté%'))
ORDER BY subscription_ended_on
It's not entirely clear to me, what you are trying to count, but another option (most probably slower) could be to use a window function combined with a filter clause:
count(*) filter (where asg.active) over (partition by asg.user_id) as num_groups
EDIT: my answer is the same as submitted by a_horse_with_no_name
Two answers, a literal one just solving the problem you posed, and then another one questioning whether what you asked for is really what you want.
Simple answer: modify your desired query to add user_id to the Select and remove user_id from the Where clause. Now you have a table that can be left-joined to the rest of your larger query.
...
Left Join (Select user_id, count(*) as total_count
From account_subscriptiongroup
Where account_subscriptiongroups.active = true
Group By user_id) Z
On Z.user_id=account_user.id
I question whether this count is what you really want here. This counts every account_subscriptiongroup entry for all time but only the active ones. Your larger query brings back inactive as well as active records, so if your goal is to create a denominator for a percentage, you are mixing 'apples and oranges' here.
If you decide you want a total by user of the records in your query instead, then you can add one more element to your larger query without adding any more tables. Use a windowing function like this:
Select ..., Sum(Case When account_subscriptiongroup.active Then 1 else 0 End) Over (Group By account_user.id) as total count
This just counts the records within the date range and having the desired actions.

Use count and group by in a joins table?

Here is my query and I want to add the "count of SalID group by OFID" and store the result in the same table.
SELECT
T_OF.OFID,
T_OF.OFDateDPrev, T_OF.OFDateFPrev,
T_OF_User.OFUserID,
T_OF_User.SalID
INTO T_tracing
FROM T_OF
INNER JOIN T_OF_User
ON T_OF_User.OFID = T_OF.OFID
I tried this:
SELECT
T_OF.OFID,
T_OF.OFDateDPrev, T_OF.OFDateFPrev,
T_OF_User.OFUserID,
Count (SalID) FROM T_OF_User GROUP BY OFID
INTO T_tracing
FROM T_OF
INNER JOIN T_OF_User
ON T_OF_User.OFID = T_OF.OFID
But I have an error message. Any help please?
I think you want a window function:
SELECT T_OF.OFID, T_OF.OFDateDPrev, T_OF.OFDateFPrev, T_OF_User.OFUserID,
Count(SalID) OVER (PARTITION BY T_OF.OFID) as cnt
INTO T_tracing
FROM T_OF JOIN
T_OF_User
ON T_OF_User.OFID = T_OF.OFID;
You also need to give the result of the expression a name for T_Tracing.

Doctrine, How can I do a select * (all) statememt?

I'm trying to mimic this sql query:
$sql = "SELECT *, log.id as logid, date_format(shipdate,'%m/%d/%Y') as shipdate
FROM log LEFT JOIN sub ON sub.id = sub_id
LEFT JOIN main ON id = main_id WHERE
shipdate >= '$datestart' AND shipdate <= '$dateend' ";
When I put SELECT * in the createQuery function of Doctrine, an error says it doesn't recognize that statement so I tried to grab all the entities by selecting individual ones:
$query = $this->getEntityManager()
->createQuery('
SELECT
m.dano, m.partno, m.batchno,
s.rackno, s.heatcode, s.diecode,
l.shipdate, l.qtyshipped, l.blno, l.id as logid
FROM
Bundle:Sub s
JOIN
s.main m
JOIN
s.log l
WHERE
l.shipdate >= :fromdate and l.shipdate <= :todate
')->setParameter('fromdate', $fromdate)
->setParameter('todate', $todate);
However when I do it this way, it doesn't return all the data that the original queries does. It skips some rows. Is there another way to be selecting all the entity?
You can mimic the following SQL using DQL. I believe that's the best way to do rather than using create query. Select all in DQL is 'select(alias)'. See my
SELECT *, log.id as logid, date_format(shipdate,'%m/%d/%Y') as shipdate
FROM log LEFT JOIN sub ON sub.id = sub_id
LEFT JOIN main ON id = main_id WHERE
shipdate >= '$datestart' AND shipdate <= '$dateend'
DQL
$dql = $qb2->select('m.dano, m.partno, m.batchno,
s.rackno, s.heatcode, s.diecode,
l.shipdate, l.qtyshipped, l.blno, l.id')
->from('YourBundle:Log','l')
->leftJoin('l.sub', 's', Expr\Join::ON, 's.id = l.sub_id')
->leftJoin('l.main', 'm', Expr\Join::ON, 'm.id = l.main_id')
->where('l.shipdate >= :shipdateStart')
->setParameter('shipdateStart', $datestart)
->where('l.shipdate <= :shipdateEnd')
->setParameter('shipdateEnd', $dateend)
By the way your selecting table and joining tables are slightly different in the given sql example compared to your query in create query function. I mimiced what's in your raw SQL which is listed above. Hope this helps you to understand converting SQL in to DQL.
Regards,

Subquery issue (SQL)

I am facing a challenge with a SQL query.
Basically I would like to retrieve the registers which present a [Start] later than their respective [Outgoing tasks].
The table looks like this:
Main Project Main Link Name Start Outgoing tasks
A 1 A1 02.01.2012 A2
A 1 A2 01.01.2012 A3
...
The query I wrote is this one:
SELECT [Name], [Start], [Outgoing tasks]
FROM [Sheet1$]
WHERE [Main project] = 'A'
AND [Main link] = '1'
AND [Outgoing tasks] IS NOT NULL
AND [Start] > (SELECT [Start]
FROM [Sheet1$]
WHERE [Main project] = 'A'
AND [Main link] = '1'
AND [Name] = [Outgoing tasks])
It doesn't return any error, however it simply doesn't bring the expected results.
Do you guys know what might be wrong?
Any support is very appreciated!!!
Further info:
This table comes from a MS Project like application. So we have a milestone, its data, successor and predecessor. What I actually need is a list of milestones which have a start date later than its successor (Which is an error in the project management perspective). So if A1.Start > A2.Start, then i should appear in the results. Let me know if you need any further detail.
Try
select t1.* from [$Sheet1] t1
inner join [$Sheet1] t2
on t1.[main project] = t2.[main project]
and t1.[main link] = t2.[main link]
and t1.[outgoing tasks] = t2.name
and t1.start>t2.start
If this is meant to be a correlated sub-query, you need a way to refer to the outer statement's table inside the inner query. In MySQL you'd do it like this:
SELECT name, start, outgoing_tasks FROM sheet1 foo WHERE main_project = 'A' AND main_link = '1' AND outgoing_tasks IS NOT NULL AND start > (SELECT start FROM sheet1 bar WHERE main_project = 'A' AND main_link = '1' AND bar.name = foo.outgoing_tasks);
Notice that I give the outer query's table an alias of foo and the inner query's table the alias of bar. Then I can refer to the outer table in the WHERE predicate of the nested (inner) query: ... AND bar.name = foo.outgoing_tasks ...