sql multiple join (right. left, inner) to mongodb aggregate - mongodb

//I have a sql like this
SELECT
x.attr1,
p.attr2,
p2.attr3,
o.attr4,
p2.attr5,
a2.attr6
FROM TABLE_O o
RIGHT JOIN TABLE_A a ON a.id = o.id AND a.id2 IS NULL
LEFT JOIN TABLE_A a2 ON a2.id = o.id AND a2.id2 = a.id3
LEFT JOIN TABLE_P p ON a.id4 = p.id4
LEFT JOIN TABLE_P p2 ON a2.id4 = p2.id4
INNER JOIN TABLE_X x ON a.id3 = x.id3
WHERE o.type = 'someText' AND a2.id4
IN ( SELECT id3 FROM TABLE_P WHERE TYPE = "anotherText")
AND x.attr1 = "someText"
//I need an idea about how can i do this on mongo aggregates, thanks.

nosql is a non-relational database type. but The following link may be useful.
mongodb aggregation

Related

How to aggregate calculation in SQL Server?

I have a following script to get the total unit but it gives me an error
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
Do I need to calculate SUM(ta.Qty) outside the main table?
SELECT
ta.ProductName
, SUM(ta.Total)
, SUM(SUM(ta.Qty) * ta.Unit)
FROM
tableA tA
INNER JOIN
tableB tB on tA.ID = tb.TableAID
INNER JOIN
tableC tc on ta.ID = tc.TableAID
INNER JOIN
tableD td on td.ID = tb.TableBID
GROUP BY
ta.ProductName
Here is a query in the AdventureWorks database that produces the same error (but might make some sense):
SELECT v.Name AS Vendor, SUM(SUM(p.ListPrice*d.OrderQty)+h.Freight)
FROM Production.Product p
INNER JOIN Purchasing.PurchaseOrderDetail d ON p.ProductID = d.ProductID
INNER JOIN Purchasing.PurchaseOrderHeader h ON h.PurchaseOrderID = d.PurchaseOrderID
INNER JOIN Purchasing.Vendor v ON v.BusinessEntityID = h.VendorID
GROUP BY v.Name
And here are two ways that I could rewrite that query to avoid the error:
SELECT v.Name AS Vendor, SUM(x.TotalAmount+h.Freight)
FROM (
SELECT PurchaseOrderID, SUM(p.ListPrice*d.OrderQty) AS TotalAmount
FROM Production.Product p
INNER JOIN Purchasing.PurchaseOrderDetail d ON p.ProductID = d.ProductID
GROUP BY PurchaseOrderID
) x
INNER JOIN Purchasing.PurchaseOrderHeader h ON h.PurchaseOrderID = x.PurchaseOrderID
INNER JOIN Purchasing.Vendor v ON v.BusinessEntityID = h.VendorID
GROUP BY v.Name
SELECT v.Name AS Vendor, SUM(x.TotalAmount+h.Freight)
FROM Purchasing.PurchaseOrderHeader h
INNER JOIN Purchasing.Vendor v ON v.BusinessEntityID = h.VendorID
CROSS APPLY (
SELECT SUM(p.ListPrice*d.OrderQty) AS TotalAmount
FROM Production.Product p
INNER JOIN Purchasing.PurchaseOrderDetail d ON p.ProductID = d.ProductID
WHERE d.PurchaseOrderID=h.PurchaseOrderID
) x
GROUP BY v.Name
The first query uses derived tables and the second one uses CROSS APPLY.

Postgres UPDATE statement

I have moved from mysql to psql, but find it hard to get my head around the UPDATE statement using multiple left joins.
How would you rewrite this in Postgres? (I am using postresql 9.4)
update task t
left join project p on t.project_id = p.id
left join client c on t.client_id = c.id
left join user u on t.user_id = u.id
set t.project_name = p.name,
t.client_name = c.name,
t.user_name = u.name;
Any pointer will be welcome.
Here you go:
WITH task_data AS (
SELECT t.id,
p.name AS project_name,
c.name AS client_name,
u.name AS user_name
FROM task t
LEFT JOIN project p ON t.project_id = p.id
LEFT JOIN client c ON t.client_id = c.id
LEFT JOIN "user" u ON t.user_id = u.id
)
UPDATE task t
FROM task_data d
SET
project_name = d.project_name,
client_name = d.client_name,
user_name = d.user_name
WHERE t.id = d.id
I would be curious to see if there is a more efficient way

TSQL efficiency - INNER JOIN replaced by EXISTS

Can the following be rewritten to be more efficient?
I would use EXISTS if I didn't need fields from country but I do need those fields, and am not sure how to write this to make it more efficient.
SELECT distinct
p.ProvinceID,
p.Abbv as RegionCode,
p.name as RegionName,
cn.Code as CountryCode,
cn.Name as CountryName
FROM dbo.provinces AS p
INNER JOIN dbo.Countries AS cn ON p.CountryID = cn.CountryID
INNER JOIN dbo.Cities c on c.ProvinceID = p.ProvinceID
INNER JOIN dbo.Listings AS l ON l.CityID = c.CityID
WHERE l.IsActive = 1 AND l.IsApproved = 1
There are two things to note:
You're joining to dbo.Listings which results in many records, so you need to use DISTINCT (usually an expensive operator)
For any tables with columns not in the select you can move into an EXISTS (but the query planner effectively does this for you anyway)
So try this:
SELECT
p.ProvinceID,
p.Abbv as RegionCode,
p.name as RegionName,
cn.Code as CountryCode,
cn.Name as CountryName
FROM dbo.provinces AS p
INNER JOIN
dbo.Countries AS cn
ON p.CountryID = cn.CountryID
WHERE EXISTS (SELECT 1 FROM
dbo.Listings l
INNER JOIN dbo.Cities c
on l.CityID = c.CityID
WHERE c.ProvinceID = p.ProvinceID
AND l.IsActive = 1 AND l.IsApproved = 1
)
Check the query plans before and after - the query planner might be smart enough to do this anyway, but you have removed your distinct
The following will often perform even better by providing the optimizer more useful information:
SELECT
p.ProvinceID,
p.Abbv as RegionCode,
p.name as RegionName,
cn.Code as CountryCode,
cn.Name as CountryName
FROM dbo.provinces AS p
INNER JOIN
dbo.Countries AS cn
ON p.CountryID = cn.CountryID
INNER JOIN (
SELECT
p.ProvinceID
FROM
dbo.Listings l
INNER JOIN dbo.Cities c
on l.CityID = c.CityID
WHERE l.IsActive = 1 AND l.IsApproved = 1
GROUP BY
p.ProvinceID
) list
on list.ProvinceID = p.ProvinceID

JPA Criteria JOIN et ON

I have been searching for a while, I haven't found any responses to my problem.
I am making an application in JSF, EclipseLink, Glassfish in which the user can have one or more groups. The application contains modules and permissions as follows:
Module => permission => utilisateur
Module => permission => groupe => utilisateur
I am looking for a criteria query (not in jqpl) to get all of the modules of a user. I have constructed my SQL query, which functions very well like this:
SELECT *
FROM core_module m
WHERE m.id IN (
SELECT m.id
FROM core_module m
INNER JOIN modules_permissions mp
ON mp.modules_id = m.id
INNER JOIN core_permission p
ON p.id = mp.permissions_id
INNER JOIN users_permissions up
ON p.id = up.permissions_id
INNER JOIN core_user u
ON u.id = 1
)
OR m.id IN (
SELECT m.id
FROM core_module m
INNER JOIN modules_permissions mp
ON m.id = mp.modules_id
INNER JOIN core_permission p
ON p.id = mp.permissions_id
INNER JOIN groups_permissions gp
ON gp.permissions_id = p.id
INNER JOIN core_group g
ON g.id = gp.groups_id
INNER JOIN users_groups ug
ON g.id = ug.groups_id
INNER JOIN core_user u
ON u.id = ug.users_id
WHERE u.id = 1
)
I am trying somehow to transform this into a criteria query without great success. I have just started the first part of the query, which gives me the modules immediately accessible to a user. I have the impression that I am missing some conditions or joins, as I am getting 2 results when I shouldn't be getting any. In effect, I haven't been able to include my ON clauses, so I can't change my to joins in my query since the entities don't exist: the table modules_permissions is created by a #ManyToMany in my entities...
Here is my first draft subquery:
List<Module> modules;
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Module> query = cb.createQuery(Module.class);
Root<Module> root_module = query.from(Module.class);
Root<User> root_user = query.from(User.class);
Root<Permission> root_permission = query.from(Permission.class);
Root<Group> root_group = query.from(Group.class);
Join<Module, Permission> join_module_permission = root_module.join(Module_.permissions);
Join<Permission, User> join_permission_user = root_permission.join(Permission_.users);
query.where(cb.equal(root_user.get(User_.email), current.getEmail()));
modules = getEntityManager().createQuery(query).getResultList();
Try turning EclipseLink logging to finest so you can see the SQL that is generated. You might also use JPQL as it is closer to the SQL, and then convert to criteria once you have something working. Something like
"select m from Module m where
m in (select m1 from Module m1 join m1.permissions p join p.users u where u.id = 1) or
m in (select m2 from Module m2 join m2.permissions p2 join p2.groups g join g.users u2 where u2.id =1)"
The key here is that you use the entity relationships in the criteria query so that it matches what you want in the generated SQL. Don't use multiple from clauses when you only want those tables and their joins included in an inner query. If the above JPQL works and the relationships exist, something like this is equivalent:
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Module> query = cb.createQuery(Module.class);
Root<Module> root_module = query.from(Module.class);
Path path = root_module.get(Module_.id);
Subquery<Integer> subquery = criteriaQuery.subquery(Integer.class);
Root subRoot = subquery.from(Module.class);
subquery.select(subRoot.get((Module_.id)));
Join user1 = subRoot.join(Module_.permissions).join(Permission_.users);
subquery.where(criteriaBuilder.equals(user1.get(User_.id), 1));
Subquery<Integer> subquery2 = criteriaQuery.subquery(Integer.class);
Root subRoot2 = subquery.from(Module.class);
subquery2.select(subRoot2.get((Module_.id)));
Join user2 = subRoot2.join(Module_.permissions).join(Permission_.groups).join(Group_.users);
subquery2.where(criteriaBuilder.equals(user2.get(User_.id), 1));
query.where(criteriaBuilder.or(criteriaBuilder.in(path ).value(subquery),
criteriaBuilder.in(path ).value(subquery2)));
The final answer is :
in JPQL :
#NamedQuery(name = "core_user.findModuleAssociated", query = "select m from Module m where m.id in (select m1.id from Module m1 join m1.permissions p join p.user u where u.id = :userid) or m.id in (select m2.id from Module m2 join m2.permissions p2 join p2.group g join g.users u2 where u2.id = :userid)")
in criteria query :
List<Module> modules;
CriteriaQuery<Module> query = cb.createQuery(Module.class);
Root<Module> root_module = query.from(Module.class);
Path path = root_module.get(Module_.id);
Subquery<Integer> subquery = query.subquery(Integer.class);
Root subRoot = subquery.from(Module.class);
subquery.select(subRoot.get((Module_.id)));
Join user1 = subRoot.join(Module_.permissions).join(Permission_.user);
subquery.where(cb.equal(user1.get(User_.id), current.getId()));
Subquery<Integer> subquery2 = query.subquery(Integer.class);
Root subRoot2 = subquery.from(Module.class);
subquery2.select(subRoot2.get((Module_.id)));
Join user2 = subRoot2.join(Module_.permissions).join(Permission_.group).join(Group_.users);
subquery2.where(cb.equal(user2.get(User_.id), current.getId()));
query.where(cb.or(cb.in(path).value(subquery), cb.in(path).value(subquery2)));
modules = getEntityManager().createQuery(query).getResultList();
Special thanks to Chris

Using multiple resultsets combined with joins in T-SQL

I'm currently using joins inside my stored procedures for outputting elements from different tables. An aggressive example
select a.*, b.*, c.*, d.*, e.*, f.* from tableA a
join tableB b on a.id = b.foreignid
join tableC c on b.id = c.foreignid
join tableD d on c.id = d.foreignid
join tableE e on d.id = e.foreignid
join tableF f on e.id = f.foreignid
where a.id = 1
It's getting pretty unhandy to work with when mapping the output to entities in my C# code, since I have to maintain a lot of boilerplate code.
Instead I would look into using multiple resultsets, so that I could map each resultset into an object type in code.
But how would I go around achieving this when I my case the different results would all relate to each other? The examples I've been able to find all revolved around selecting from different tables where the data were not related by foreign keys like mine. If I were to ouput my result in multiple resultsets the only thing I can come up with is something like this
select a.* from tableA
where a.id = 1
select b.* from tableB
join tableA a on a.id = b.foreignid
where a.id = 1
select c.* from tableC
join tableB b on b.id = c.foreignid
join tableA on a.id = b.foreginid
where a.id = 1
select d.* from tableD
join tableC c on c.id = d.foreignid
join tableB b on b.id = c.foreignid
join tableA a on a.id = b.foreignid
where a.id = 1
select e.* from tableE
join tableD d on d.id = e.foreignid
join tableC c on c.id = d.foreignid
join tableB b on b.id = c.foreignid
join tableA a on a.id = b.foreignid
where a.id = 1
select f.* from tableF
join tableE e on e.id = f.foreignid
join tableD d on d.id = e.foreignid
join tableC c on c.id = d.foreignid
join tableB b on b.id = c.foreignid
join tableA a on a.id = b.foreignid
where a.id = 1
But this is not cleaner, a lot more ineffecient (I would suppose, since there's alot more join statements)
Is it possible to use multiple resultset in this way I'm trying to? I just don't know how I would write the sql statements in the stored proc without having to do massive joins per resultset as in the example. And with the current solution I get an explosion of columns since I join them all together
You can actually return multiplte resultsets from a single SP and consume them in c#, check this post for instance : http://blogs.msdn.com/b/dditweb/archive/2008/05/06/linq-to-sql-and-multiple-result-sets-in-stored-procedures.aspx
It's a lesser known feature but sounds like what you're asking for. You don't have to join them and return them as a flattend rowset, just get the seperate rowsets and piece them together in memory.
Also you may want to read up on ORM frameworks, that could save you a lot of typing that you coud spend on features if it fits your needs.
https://stackoverflow.com/questions/249550/what-orm-frameworks-for-net-do-you-like-best
Regards GJ