SQL to DQ, use sub select - symfony

I'm trying to convert a SQL function to a DQL function.
I don't know how to do the following step:
Join on multiple class
Join on temporary table (created by doctrine)
Call a sub select in my function
Here my actual working SQL code.
SELECT ut.token
FROM user_token ut
INNER JOIN factory f ON f.id = ut.factory_id
INNER JOIN article_factory af ON af.factory_id = f.id
INNER JOIN article a ON a.id = af.article_id
WHERE ut.factory_id = (
SELECT f.id
FROM factory f
INNER JOIN article_factory af ON af.factory_id = f.id
INNER JOIN article a ON a.id = af.article_id
WHERE a.id = :article
)
GROUP BY ut.token
In case of, here a screen of my table relation.
article_factory is not an entity or a class. article_factory was created for my relation between article and factory, when I specified a ManyToMany relation.
EDIT: Tryed throught plain SQL, but got issue making link between article and fatory, since DQL only know entity, and Doctrine is creating a table, which I canno't use. With DQL, I still got the same issue than above, I don't know how to properly join my classes, and make my sub-select.

Related

EF Core - Count from a specific column

I almost have my EF Core query working... This is the SQL getting produced (notice the Count(*):
SELECT [u].[Key], [u].[Url], [u].[CreatedBy], [u].[CreatedOn], COUNT(*) AS [Clicks]
FROM [URLs] AS [u]
LEFT JOIN [OwnerUrls] AS [o] ON [u].[Key] = [o].[ShortUrlKey]
LEFT JOIN [Clicks] AS [c] ON [u].[Key] = [c].[ShortUrlKey]
GROUP BY [u].[Key], [u].[Url], [u].[CreatedBy], [u].[CreatedOn]
What I need is (have Count look at a specific column/table)
SELECT [u].[Key], [u].[Url], [u].[CreatedBy], [u].[CreatedOn], COUNT(c.ID) AS [Clicks]
FROM [URLs] AS [u]
LEFT JOIN [OwnerUrls] AS [o] ON [u].[Key] = [o].[ShortUrlKey]
LEFT JOIN [Clicks] AS [c] ON [u].[Key] = [c].[ShortUrlKey]
GROUP BY [u].[Key], [u].[Url], [u].[CreatedBy], [u].[CreatedOn]
Here is the EF Query that I'm using...
query = (from u in db.URLs
join ou in db.OwnerUrls on u.Key equals ou.ShortUrlKey into urlOwners
from subSet in urlOwners.DefaultIfEmpty()
join c in db.Clicks on u.Key equals c.ShortUrlKey into urlClicks
from subClicks in urlClicks.DefaultIfEmpty()
group subClicks by new { u.Key, u.Url, u.CreatedBy, u.CreatedOn } into g
select new ShortURL()
{
Key = g.Key.Key,
Url = g.Key.Url,
CreatedBy = g.Key.CreatedBy,
CreatedOn = g.Key.CreatedOn,
Clicks = g.Count()
});
I've tried changing the g.Count() to g.Select(x=>x.Id).Count() and that just causes EF Core to barf and complain about client side evaluation vs server side evaluation etc..
I should mention that the reason I'm joining the first model (OwnerUrls) is to support a where clause that I didn't include here...
Thanks!
I'm not a EF developer, but have worked with SQL Server for a while now. In SQL Server i would use COUNT(DISTINCT c.ID) to eliminate any duplicates you might get from JOINS.
If duplicates are impossible due to the model the COUNT(*) shoud be sufficient.
Maybe this might help:
https://entityframeworkcore.com/knowledge-base/51892585/linq-select-distinct-count-performed-in-memory

Convert SQL into Doctrine 2 QueryBuilder

I need help to convert a valid SQL query into createQueryBuilder. The problem I have is I don't know how to LEFT JOIN on a SELECT in the createQueryBuilder.
SELECT username, count(c.user_owner_id) as num_contact, a_g.name as
group_name
FROM `oro_user` as u
INNER JOIN `oro_user_access_group` as u_g on u.id=u_g.user_id
INNER JOIN `oro_access_group` as a_g on u_g.group_id=a_g.id
LEFT JOIN
(SELECT cc.user_owner_id
FROM `orocrm_contact` as cc
INNER JOIN`orocrm_contact_to_contact_grp` as cc_g on cc_g.contact_id=cc.id
INNER JOIN `orocrm_contact_group`
as c_g on cc_g.contact_group_id=c_g.id
WHERE c_g.label='New One' and cc.semester_contacted='2017A')
as c on u.id=c.user_owner_id
WHERE a_g.name='Full-timer' and u.enabled = 1 and u.gender='male'
GROUP BY u.id
ORDER BY num_contact
I have two queries below, I want user to LEFT JOIN the results from contact
$user = $this->em->getRepository('OroUserBundle:User')->createQueryBuilder('u')
->select('u.username')
->innerJoin('u.groups','g')
->andWhere('g.name = :group')
->setParameter('group', 'Full-timer')
->getQuery();
$contacts = $this->em->getRepository('OroContactBundle:Contact')->createQueryBuilder('c')
->select('c')
->innerJoin('c.groups','g')
->andWhere('g.label = :group')
->andWhere('c.semester_contacted = :sem')
->setParameter('group', 'New One')
->setParameter('sem', '2017A')
->setMaxResults(1)
->getQuery();
This is a pretty complex queries and since the ORM QueryBuilder works closer to your entities than the database I'm not sure if you can just "dump" the DQL into a ->join(). The good news with the DBAL QueryBuilder that works:
$dbalQueryBuilder
->from('user_table as u')
...
->join('u', '('.$otherDbalQueryBuilder->getSQL().')', 'c')
This is from memory so it might be a little different, but something like that.
With that you can get all the fields you require, but you won't get any entities. Luckily Doctrine provides ways to build entities from Native SQL using ResultSetMapping.
$userWithContacts = $entityManager->createNativeQuery(
$dbalQueryBuilder->getSQL(),
$yourResultSetMapping
);
I know this is will require more code and is probably not as nice as just using the ORM QueryBuilder, but I find it oftentimes to be the best way to deal with existing queries that need to be ported to ORM somehow.

Complex AX Query

i want to rebuild this SQL Query as AX Query.
I tried it in several ways, but I don't get it.
I am not completely new to AX queries, but I only have experience with some simple queries not with such complex SQL queries.
SELECT * FROM ( SELECT DH.[RECID] AS RECID_DIMENSIONHIERARCHY
,DH.[NAME] AS NAME__DIMENSIONHIERARCHY
,DH.[DESCRIPTION] AS DESC__DIMENSIONHIERARCHY
,DH.[PARTITION] AS PARTITION_DIMENSIONHIERARCHY
,DL.[DIMENSIONATTRIBUTE] AS RECID_DIMENSIONATTRIBUTE
,DA.[NAME] AS NAME_DIMENSIONATTRIBUTE
,DN.[RECID] AS RECID_DIMENSIONCONSTRAINTNODE
,DNC.[RECID] AS RECID_DIMENSIONCONSTRAINTNODECRITERIA
,DNC.[RANGETO] AS #Owner
,DNCR.[WILDCARDSTRING] AS #Agreement
FROM (SELECT * FROM [dbo].[DIMENSIONHIERARCHY]
WHERE [STRUCTURETYPE] = 1 AND [NAME] LIKE 'AG-OW%'
) AS DH
INNER JOIN [dbo].[DIMENSIONHIERARCHYLEVEL] AS DL
ON DH.[RECID] = DL.[DIMENSIONHIERARCHY]
AND DH.[PARTITION] = DL.[PARTITION]
INNER JOIN [dbo].[DIMENSIONATTRIBUTE] AS DA
ON DL.[DIMENSIONATTRIBUTE] = DA.[RECID]
AND DL.[PARTITION] = DA.[PARTITION]
INNER JOIN [dbo].[DIMENSIONCONSTRAINTNODE] AS DN
ON DL.[RECID] = DN.[DIMENSIONHIERARCHYLEVEL]
AND DL.[PARTITION] = DN.[PARTITION]
INNER JOIN [dbo].[DIMENSIONCONSTRAINTNODECRITERIA] AS DNC
ON DN.[RECID] = DNC.[DIMENSIONCONSTRAINTNODE]
AND DN.[PARTITION] = DNC.[PARTITION]
INNER JOIN [dbo].[DIMENSIONCONSTRAINTNODECRITERIA] AS DNCR
ON DN.[PARENTCONSTRAINTNODE] = DNCR.[DIMENSIONCONSTRAINTNODE]
AND DN.[PARTITION] = DNCR.[PARTITION]
) AS Sub
You need to break down your query and implement it in small chunks. Then combine all of it to get the desired result.
There are two ways to create query in X++.
Create query using select statement for example:
Select * from HcmWorker join * from DirPerson
where DirPerson.RecId == HcmWorker.Person
See this link : Select statement syntax
Create query with AOT structure. You might want to have a look at the following link:
Create query in AOT by using X++

How to make JOIN with OR expression in DQL?

Here is the SQL equivalent of what I expect to get from Doctrine:
SELECT c.* FROM comments c
LEFT JOIN articles a
ON a.id = c.articles_id OR a.translation = c.articles_id
WHERE c.published = 1 AND c.language = a.language
The problem is that I cannot make Doctrine to generate the JOIN operation with OR as it is supposed to be. If we execute query from the following QueryBuilder object:
$qb->select('c')
->from('Project:Comment', 'c')
->leftJoin('c.article', 'a', 'WITH', 'a = c.article OR a.translation = c.article')
->where('c.published = true AND c.language = a.language');
we receive the following SQL statement:
SELECT
...
FROM comments c0_
LEFT JOIN articles a0_ ON c0_.articles_id = a0_.id
AND (
a0_.id = c0_.articles_id OR
a0_.translation = c0_.profiles_id
)
WHERE c0_.published = 1 AND c0_.language = a0_.language
which is obviously not the same as the initial query, as WITH operator seems to add additional conditions to the basic one instead of replacing the whole condition.
Is there any way to force Doctrine to output exactly what I need? I know that I may use native SQL but I doubt that it will be as convenient as QueryBuilder. Maybe there is a way to extend Doctrine with normal JOIN ON implementation instead of this odd JOIN WITH?
Doctrine doesn't implement this because it is (as far as I understand at least) not considered optimized enough for SQL.
See this SO post for precisions.
What you intend to do could appearantly be done using Union and other types of Join.

Querying 2/3 tables with one SQL statement

I have three tables: users, projects, user_project
user_project contains user_id, project_id and role_id, where user_id and project_id are both primary keys connected to projects.project_id and users.user_id.
I want to get the the name and surname of all the users from the users table that has to do with a certain project from the projects table through user_project.
What SQL statement do I have to use? I was thinking something like this:
SELECT
users.name, users.surname
FROM users
WHERE users.user_id = user_project.user_id AND projects.project_id = #parameter
I am using SQL Server 2012 and ASP.NET/VB.NET.
Db Diagram:
http://i.imgur.com/lrv52wO.png
SELECT users.name, users.surname
FROM users u
INNER JOIN user_project up
ON u.user_id = up.user_id
WHERE up.project_id = #parameter
You'll need to join to your other tables - either from Users through User_Project all the way to Projects if you want to base your selection on something in the Projects table:
SELECT
u.name, u.surname
FROM users u
INNER JOIN user_project up ON u.user_id = up.user_id
INNER JOIN project p ON p.project_id = up.project_id
WHERE p.project_name = 'something'
or at least to the link table, if you can use the project_id as criteria:
SELECT
u.name, u.surname
FROM users u
INNER JOIN user_project up ON u.user_id = up.user_id
WHERE up.project_id = #parameter
Update: assuming your Role table is connected to Users through again a link table Users_role then you need this to select role name, too:
SELECT
u.name, u.surname,
RoleName = r.Name
FROM users u
INNER JOIN user_project up ON u.user_id = up.user_id
INNER JOIN user_roles ur ON u.user_id = ur.user_id
INNER JOIN role r ON ur.role_id = r.role_id
WHERE up.project_id = #parameter
SELECT
users.name, users.surname
FROM users
inner join user_project
on users.user_id = user_project.user_id
WHERE user_project.project_id = #parameter
This should do it.
SELECT users.name, users.surname
FROM users
INNER JOIN user_project ON user_project.user_id = users.user_id
WHERE (user_project.project_id = #parameter)
The important line here is the line that starts INNER JOIN. You don't need the project table as the project_id column is in user_project. If you wanted to get the project name for example you would need the project table. You would do this by writing another INNER JOIN.
INNER JOIN project ON project.project_id = user_project.project_id
Now that you have joined you can access all the columns in the project table.

Resources