Right join query in symfony3 with doctrine - sql

I want to convert the sql query below to doctrine query in symfony.
select p.name,p.id,sum(t.amount) as bal from transactions t right join processors p on t.processor_id=p.id where user_id=18 or user_id is null group by p.id
The above code fetches balance from transactions table by summing up amounts of each transaction for a user for each processor.
Result:
Processor1 --------- 43
Processor2 --------- 12
Processor3 --------- NULL
Processor4 --------- NULL
Processor5 --------- NULL
The query i tried with dql is:
$sql = $procRepo->createQueryBuilder('t');
$sql->select('p.name');
$sql->leftJoin('t.processorId','p');
$sql->addSelect('sum(t.amount) as bal');
$sql->groupBy('p.id');
$sql->orderBy('p.name')->getQuery()->getResult();
Result:
Processor1 --------- 43
Processor2 --------- 12
So my problem is i also want to get the NULL rows.
Note: I am using Symfony 3
Can anybody help?

You needs to invert the join statement to gets all processors:
$sql = $procRepo->createQueryBuilder('p');
$sql->select('p.name', 'sum(t.amount) as bal');
$sql->leftJoin('p.transaction', 't');
$sql->groupBy('p.id');
$result = $sql->orderBy('p.name')->getQuery()->getResult();
This query must be made in your ProcessorRepository.

Related

Getting Duplicates in Person ID and ASSIGNMENT_ID

This is the query I'm using:
select DISTINCT "HRG_GOAL_ACCESS"."PERSON_ID" as "PERSON_ID",
"HRG_GOAL_ACCESS"."BUSINESS_GROUP_ID" as "BUSINESS_GROUP_ID",
"HRG_GOALS"."GOAL_ID" as "GOAL_ID",
"HRG_GOALS"."ASSIGNMENT_ID" as "ASSIGNMENT_ID",
"HRG_GOALS"."GOAL_NAME" as "GOAL_NAME",
"HRG_MASS_REQ_RESULTS"."ORGANIZATION_ID" as "ORGANIZATION_ID",
"HRG_MASS_REQ_RESULTS"."RESULT_CODE" as "RESULT_CODE",
"HRG_GOAL_PLN_ASSIGNMENTS"."CREATED_BY" as "CREATED_BY"
from "FUSION"."HRG_GOAL_PLN_ASSIGNMENTS" "HRG_GOAL_PLN_ASSIGNMENTS",
"FUSION"."HRG_MASS_REQ_RESULTS" "HRG_MASS_REQ_RESULTS",
"FUSION"."HRG_GOALS" "HRG_GOALS",
"FUSION"."HRG_GOAL_ACCESS" "HRG_GOAL_ACCESS"
where "HRG_GOAL_ACCESS"."PERSON_ID"="HRG_GOALS"."PERSON_ID"
and "HRG_MASS_REQ_RESULTS"."PERSON_ID"="HRG_GOALS"."PERSON_ID"
and "HRG_GOAL_PLN_ASSIGNMENTS"."PERSON_ID"="HRG_MASS_REQ_RESULTS"."PERSON_ID"
Output
PERSON_ID BUSINESS_GROUP_ID GOAL_ID ASSIGNMENT_ID GOAL_NAME RESULT_CODE CREATED_BY
---------------- ----------------- --------------- --------------- ------------------ -------------------- -------------------
300000048030404 1 300000137711224 300000048033078 NANO_CLASS SUCCESS anonymous G_1
300000048030404 1 300000137637946 300000048033078 INCREASE SALES BY 40% SUCCESS REDDI.SAREDDY G_1
300000048030404 1 300000137637946 300000048033078 INCREASE SALES BY 40% SUCCESS CURTIS.FEITTY
Your output does not contain duplicates. You have more than one row for PERSON_ID (300000048030404) but that's because the master table (? HRG_GOAL_ACCESS ?) has multiple rows in its child tables.
Each row has different details, so the set is valid. There are different values of HRG_GOALS.GOAL_ID, HRG_GOALS.GOAL_NAME and HRG_GOAL_PLN_ASSIGNMENTS.CREATED_BY.
If this response does not make you happy you need to explain more clearly what your desire output would look like. Alternatively you need to figure out your data model and understand why your query returns the data it does. Probably you have a missing join condition; the use of distinct could be hindering you in finding that out.

Hibernate criteria left join with query

I have two classes Apartment and AdditionalSpace representing tables as below.
Apartment table
ID AREA SOLD
---- ------ ----
1 100 1
2 200 0
AdditionalSpace table
ID AREA APARTMENTID
---- ------ -----------
10 10 1
11 10 1
12 10 1
20 20 2
21 20 2
As you can see Apartment's table has a one-to-many relation with AdditionalSpace table, i.e. Apartment.ID=AdditionalSpace.APARTMENTID.
Question:- How to retrieve total area of a sold apartment including its additional space area.
The SQL which I have used so far to retrieve similar result is :-
select sum(apt.area + ads.adsarea) from apartment apt left outer join (select sum(area) as adsarea, apartmentid from additionalspace group by apartmentid) ads on ads.apartmentid=apt.id where apt.sold=1
I am struggling to find a way in order to implement the above scenario via criteria instead of SQL/HQL. Please suggest. Thanks.
I don't think this is possible in criteria. The closest I can see is to simply get the size of the apartment and the sum of the additional areas as two columns in your result, like this:
Criteria criteria = session.createCriteria(Apartment.class,"a");
criteria.createAlias("additionalSpaces", "ads");
criteria.setProjection(Projections.projectionList()
.add(Projections.property("area"))
.add(Projections.groupProperty("a.id"))
.add(Projections.sum("ads.area")));
Alternatively, if you still want to use Hibernate but are happy to write it in HQL, you can do the following:
select ads.apartment.id,max(a.area)+sum(ads.area)
from Apartment a
join a.additionalSpaces ads
group by ads.apartment.id
This works because HQL allows you to write the + to add together the two projections, but I don't know that an analogous method exists on the projections api.

Join in SQLite with per-row selection of join table based on value in link table

I have tables as follows:
muscles
id primary_synonym_id source
---------- ------------------ ----------
1 1 1
2 2 2
3 3 3
muscle_synonyms
id synonym
---------- ---------------
1 Gluteus maximus
2 Soleus
3 Infraspinatus
sources (As you can probably tell, sources is intended as a link table.)
id type sub_id
---------- ---------- ----------
1 url 1
2 url 2
3 book 1
source_urls
id url
---------- ------------------
1 http://v.gd/3NCOMC
2 http://v.gd/fWdonY
source_books
id isbn
---------- ----------
1 1405006692
From the above, which query would you recommend, to generate the following output?
id synonym ref
---------- --------------- ------------------
1 Gluteus maximus http://v.gd/3NCOMC
2 Soleus http://v.gd/fWdonY
3 Infraspinatus 1405006692
Please mention worthwhile alternatives - if any - to such a query, that you think would promote good database practice. (For example, a different way to structure the data and the use of a simpler query.)
I was unfamiliar with the coalesce() function. The following query was inspired by this, and it works:
select muscles.id, synonym, coalesce(url, isbn) as ref
from muscles
join muscle_synonyms on muscles.primary_synonym_id = muscle_synonyms.id
join sources on muscles.source = sources.id
left join source_urls on
sources.type = 'url' and
sources.sub_id = source_urls.id
left join source_books on
sources.type = 'book' and
sources.sub_id = source_books.id
where ref not null;
i dont exactly understand what is sub_id in sources and how its linked to source_books
sql will almost looks like this
select m.id,ms.synonym,su.url from muscles m
join muscle_synonym ms on ms.id=m.primary_synonym_id
join sources s on s.id=m.source
join source_url su on s.sub_id=su.id
I can't see any advantage in having 2 different tables for source_*.
I would merge source_url and source_book into source_ref so:
id type ref
---------- ---------- ------------------
1 url http://v.gd/3NCOMC
2 url http://v.gd/fWdonY
3 book 1405006692
And sources will become a two table join:
id ref_id
---------- ----------
1 1
2 2
3 3
So you query will become simple joins as:
SELECT muscles.id, muscle_synonyms.synonym, source_ref.ref FROM muscles
LEFT JOIN muscle_synonyms ON muscles.id=muscle_synonyms.id
LEFT JOIN source ON muscles.source=source.id
LEFT JOIN source_ref ON source.ref_id=source_ref.id;
This will include all muscles, including those without synonym neither sources, neither any ref for source.

SQL Alternative to performing an INNER JOIN on a single table

I have a large table (TokenFrequency) which has millions of rows in it. The TokenFrequency table that is structured like this:
Table - TokenFrequency
id - int, primary key
source - int, foreign key
token - char
count - int
My goal is to select all of the rows in which two sources have the same token in it. For example if my table looked like this:
id --- source --- token --- count
1 ------ 1 --------- dog ------- 1
2 ------ 2 --------- cat -------- 2
3 ------ 3 --------- cat -------- 2
4 ------ 4 --------- pig -------- 5
5 ------ 5 --------- zoo ------- 1
6 ------ 5 --------- cat -------- 1
7 ------ 5 --------- pig -------- 1
I would want a SQL query to give me source 1, source 2, and the sum of the counts. For example:
source1 --- source2 --- token --- count
---- 2 ----------- 3 --------- cat -------- 4
---- 2 ----------- 5 --------- cat -------- 3
---- 3 ----------- 5 --------- cat -------- 3
---- 4 ----------- 5 --------- pig -------- 6
I have a query that looks like this:
SELECT F.source AS source1, S.source AS source2, F.token,
(F.count + S.count) AS sum
FROM TokenFrequency F
INNER JOIN TokenFrequency S ON F.token = S.token
WHERE F.source <> S.source
This query works fine but the problems that I have with it are that:
I have a TokenFrequency table that has millions of rows and therefore need a faster alternative to obtain this result.
The current query that I have is giving duplicates. For example its selecting:
source1=2, source2=3, token=cat, count=4
source1=3, source2=2, token=cat, count=4
Which isn't too much of a problem but if there is a way to elimate those and in turn obtain a speed increase then it would be very useful
The main issue that I have is speed of the query with my current query it takes hours to complete. The INNER JOIN on a table to itself is what I believe to be the problem. Im sure there has to be a way to eliminate the inner join and get similar results just using one instance of the TokenFrequency table. The second problem that I mentioned might also promote a speed increase in the query.
I need a way to restructure this query to provide the same results in a faster, more efficient manner.
Thanks.
I'd need a little more info to diagnose the speed issue, but to remove the dups, add this to the WHERE:
AND F.source<S.source
Try this:
SELECT token, GROUP_CONCAT(source), SUM(count)
FROM TokenFrequency
GROUP BY token;
This should run a lot faster and also eliminate the duplicates. But the sources will be returned in a comma-separated list, so you'll have to explode that in your application.
You might also try creating a compound index over the columns token, source, count (in that order) and analyze with EXPLAIN to see if MySQL is smart enough to use it as a covering index for this query.
update: I seem to have misunderstood your question. You don't want the sum of counts per token, you want the sum of counts for every pair of sources for a given token.
I believe the inner join is the best solution for this. An important guideline for SQL is that if you need to calculate an expression with respect to two different rows, then you need to do a join.
However, one optimization technique that I mentioned above is to use a covering index so that all the columns you need are included in an index data structure. The benefit is that all your lookups are O(log n), and the query doesn't need to do a second I/O to read the physical row to get other columns.
In this case, you should create the covering index over columns token, source, count as I mentioned above. Also try to allocate enough cache space so that the index can be cached in memory.
If token isn't indexed, it certainly should be.

SQL Query Advice - Most recent item

I have a table where I store customer sales (on periodicals, like newspaper) data. The product is stored by issue. Example
custid prodid issue qty datesold
1 123 2 12 01052008
2 234 1 5 01022008
1 123 1 5 01012008
2 444 2 3 02052008
How can I retrieve (whats a faster way) the get last issue for all products, for a specific customer? Can I have samples for both SQL Server 2000 and 2005? Please note, the table is over 500k rows.
Thanks
Assuming that "latest" is determined by date (rather than by issue number), this method is usually pretty fast, assuming decent indexes:
SELECT
T1.prodid,
T1.issue
FROM
Sales T1
LEFT OUTER JOIN dbo.Sales T2 ON
T2.custid = T1.custid AND
T2.prodid = T1.prodid AND
T2.datesold > T1.datesold
WHERE
T1.custid = #custid AND
T2.custid IS NULL
Handling 500k rows is something that a laptop can probably handle without trouble, let alone a real server, so I'd stay clear of denormalizing your database for "performance". Don't add extra maintenance, inaccuracy, and most of all headaches by tracking a "last sold" somewhere else.
EDIT: I forgot to mention... this doesn't specifically handle cases where two issues have the same exact datesold. You might need to tweak it based on your business rules for that situation.
Generic SQL; SQL Server's syntax shouldn't be much different:
SELECT prodid, max(issue) FROM sales WHERE custid = ? GROUP BY prodid;
Is this a new project? If so, I would be wary of setting up your database like this and read up a bit on normalization, so that you might end up with something like this:
CustID LastName FirstName
------ -------- ---------
1 Woman Test
2 Man Test
ProdID ProdName
------ --------
123 NY Times
234 Boston Globe
ProdID IssueID PublishDate
------ ------- -----------
123 1 12/05/2008
123 2 12/06/2008
CustID OrderID OrderDate
------ ------- ---------
1 1 12/04/2008
OrderID ProdID IssueID Quantity
------- ------ ------- --------
1 123 1 5
2 123 2 12
I'd have to know your database better to come up with a better schema, but it sound like you're building too many things into a flat table, which will cause lots of issues down the road.
If you're looking for most recent sale by date maybe that's what you need:
SELECT prodid, issue
FROM Sales
WHERE custid = #custid
AND datesold = SELECT MAX(datesold)
FROM Sales s
WHERE s.prodid = Sales.prodid
AND s.issue = Sales.issue
AND s.custid = #custid
To query on existing growing historical table is way too slow!
Strongly suggest you create a new table tblCustomerSalesLatest which stores the last issue data of each customer. and select from there.