Subquery inside the 'FROM' statement in doctrine? - symfony

I would like to write this SQL query
select id FROM
(SELECT article.id AS id, MATCH(titre, intro, contenu) AGAINST ('query') as score FROM article ORDER BY score DESC) t1
where score>0
in doctrine with a querybuilder subquery.
I'am using a doctrine extension to interpret the MATCH AGAINST.
I cannot find the doctrine/querybuilder syntax to create the subquery inside the 'FROM'
So I do :
$this->createQueryBuilder('a')
->andWhere('MATCH(a.titre, a.intro, a.contenu) AGAINST (:q boolean) >0')
->orderBy('MATCH(a.titre, a.intro, a.contenu) AGAINST (:q boolean)', 'DESC')
->setParameter('q', $query)
This syntax is working but i would like to do it efficiently without repeating the 'MATCH(a.titre, a.intro, a.contenu) AGAINST (:q boolean) twice.
So I need to write the subquery version.

I think there are at least 2 approaches here and neither requires a subquery:
1) You can use HAVING instead of WHERE and reference the selected column name (+ hide that column from results with HIDDEN keyword). Though this might be less performant as it would do condition matching and sorting on the already selected data, so it is not available for query optimizer to optimize it.
$this->createQueryBuilder('a')
->select('a.id, HIDDEN MATCH(a.titre, a.intro, a.contenu) AGAINST (:q boolean) AS score')
->andHaving('score > 0')
->orderBy('score', 'DESC')
->setParameter('q', $query);
2) If repetition is the only issue you are having, just define the repeated part as a variable and use that instead:
$score = 'MATCH(a.titre, a.intro, a.contenu) AGAINST (:q boolean)'
$this->createQueryBuilder('a')
->select('a.id')
->andWhere("{$score} > 0")
->orderBy($score, 'DESC')
->setParameter('q', $query)
As for repetition in the query causing performance penalty - as far as I remember you don't need to worry about it - MySQL should handle that for you by reusing the same value (not recalculating it). In other words it would not be doing the matching twice just because it is present in your query twice - as long as the expression is identical, optimizer will take of that. (Although now I can't find the exact place in the docs where it dais that)

Related

expression is of wrong type for function

CREATE OR REPLACE FUNCTION k_w_b_salary(k IN NUMBER, b IN BOOLEAN)
RETURN EMP.ENAME%TYPE IS
names name_table;
BEGIN
IF (b = true) THEN
SELECT ENAME BULK COLLECT INTO names
FROM
(SELECT *
FROM EMP
ORDER BY SAL ASC)
WHERE ROWNUM <= k;
RETURN names;
ELSIF (b = false) THEN
SELECT ENAME BULK COLLECT INTO names
FROM
(SELECT *
FROM EMP
ORDER BY SAL DESC)
WHERE ROWNUM <= k;
RETURN names;
END IF;
END;
And I get this error:
12/9 PL/SQL: Statement ignored
12/16 PLS-00382: expression is of wrong type
20/9 PL/SQL: Statement ignored
20/16 PLS-00382: expression is of wrong type
I have this function that tries to find the best/worst paid employees. But i get the above error.
I think it's something to do with the ROWNUM but I am not sure.
I think the lines the error points out are not the lines with the error.
I had this function writen differently and the lines in the error where pointing to the ROWNUM <= k lines.
I have tried putting a fixed number there (<= 3) for example and I got the same error.
I have no idea what else to try, i can't really understand why this is not working.
It's not obvious to me why this is not working. I think it should work fine but obviously it dousen't.
The code for the table i use is :
CREATE OR REPLACE TYPE name_table IS TABLE OF VARCHAR2(10);
Any help is appreciated!
In the function declaration, you said
RETURN EMP.ENAME%TYPE
I assume the data type of column ENAME in table EMP is some sort of string (VARCHAR2(40) or similar) - right?
In the declarations section, you declare a variable names of data type name_table. You didn't show us the definition of the name_table type (that must be given outside the function, not in it); we can probably assume it is a nested table of some sort. Right? [EDIT - I take that back; you did show us your definition of name_table, at the end of your question.]
In the end, your function returns names. Which is of type name_table. But you said the function returns something else: EMP.ENAME%TYPE. In particular, you said the function returns a scalar data type, but you are returning a collection.
This will not work even if the collection has a single element. A table with a single "record" is not the same data type as the "record" itself - even if an actual table has a single "record" in it.
(And, much more so, when the table has three records in it!)
Rather: It seems that you want a table function: one that returns a table of things. If so, then declare the function that way. Perhaps you want the function to
RETURN NAME_TABLE
(at the top, in the function declaration)

Symfony3.4 / Doctrine : subquery in FROM Clause : Error: Class 'SELECT' is not defined

I'm working on a Symfony 3.4 project and I'm trying to translate an sql query to DQL query but I get an Issue.
Mysql Query:
select sum(montant_paye)
from
(select montant_paye
from vente
where client_id = 1
and montant_paye > 0
order by date ASC
limit 2)
as T;
DQL Query (Error):
return $this->getEntityManager()
->createQuery('
SELECT SUM(montantPaye) as Total
FROM
SELECT v.montantPaye
FROM AppBundle:Vente v
where v.montantPaye > 0
AND v.client = '.$clientId.'
ORDER BY v.date ASC
limit 2
')
->getResult();
Error :
[Semantical Error] line 0, col 71 near 'SELECT v.montantPaye
': Error: Class 'SELECT' is not defined.
Is any one have a solution for a correct DQL query ?
Quoting from Christophe stoef Coevoet (Symfony Core Developer):
DQL is about querying objects. Supporting subselects in the FROM clause means that the DQL parser is not able to build the result set mapping anymore (as the fields returned by the subquery may not match the object anymore).
This is why it cannot be supported (supporting it only for the case you run the query without the hydration is a no-go IMO as it would mean that the query parsing needs to be dependant of the execution mode).
In your case, the best solution is probably to run a SQL query instead
(as you are getting a scalar, you don't need the ORM hydration anyway)
Details here.
add this function to your VenteRepository:
public function sumMontantPaye($clientId)
{
return $this->createQueryBuilder("v")
->select("sum(v.montantPaye) as sum")
->where("v.client = :id")
->andWhere("v.montantPaye > 0")
->setParameter("id", $clientId)
->setMaxResults(2)
->getQuery()->getSingleResult();
}
you can access the sum using $result["sum"] assuming $result is the variable assigned to this function in the controller

Neo4j Cypher extracting data from collection using 'and/or' logical operators

I have a collection and I need to extract a name and id from each node and return them together to avoid post processing. I am trying:
extract(c IN nodes(c)| c.name +\': \'+ c.id) as results
The problem is that when a node without a name value is encountered it doesn't return anything.
Is there a way like 'and/or' to make the c.name optional allowing it to still return the c.id and a NULL for c.name?
Thanks
I would have thought at first that you could use toString to turn nulls into an empty string, but that doesn't seem to work. coalesce should help, though:
extract(c IN nodes(c)| coalesce(c.name, '') +\': \'+ c.id) as results

nature of SELECT query in MVC and LINQ TO SQL

i am bit confused by the nature and working of query , I tried to access database which contains each name more than once having same EMPid so when i accessed it in my DROP DOWN LIST then same repetition was in there too so i tried to remove repetition by putting DISTINCT in query but that didn't work but later i modified it another way and that worked but WHY THAT WORKED, I DON'T UNDERSTAND ?
QUERY THAT DIDN'T WORK
var names = (from n in DataContext.EmployeeAtds select n).Distinct();
QUERY THAT WORKED of which i don't know how ?
var names = (from n in DataContext.EmployeeAtds select new {n.EmplID, n.EmplName}).Distinct();
why 2nd worked exactly like i wanted (picking each name 1 time)
i'm using mvc 3 and linq to sql and i am newbie.
Both queries are different. I am explaining you both query in SQL that will help you in understanding both queries.
Your first query is:
var names = (from n in DataContext.EmployeeAtds select n).Distinct();
SQL:-
SELECT DISTINCT [t0].[EmplID], [t0].[EmplName], [t0].[Dept]
FROM [EmployeeAtd] AS [t0]
Your second query is:
(from n in EmployeeAtds select new {n.EmplID, n.EmplName}).Distinct()
SQL:-
SELECT DISTINCT [t0].[EmplID], [t0].[EmplName] FROM [EmployeeAtd] AS
[t0]
Now you can see SQL query for both queries. First query is showing that you are implementing Distinct on all columns of table but in second query you are implementing distinct only on required columns so it is giving you desired result.
As per Scott Allen's Explanation
var names = (from n in DataContext.EmployeeAtds select n).Distinct();
The docs for Distinct are clear – the method uses the default equality comparer to test for equality, and the default comparer sees 4 distinct object references. One way to get around this would be to use the overloaded version of Distinct that accepts a custom IEqualityComparer.
var names = (from n in DataContext.EmployeeAtds select new {n.EmplID, n.EmplName}).Distinct();
Turns out the C# compiler overrides Equals and GetHashCode for anonymous types. The implementation of the two overridden methods uses all the public properties on the type to compute an object's hash code and test for equality. If two objects of the same anonymous type have all the same values for their properties – the objects are equal. This is a safe strategy since anonymously typed objects are essentially immutable (all the properties are read-only).
Try this:
var names = DataContext.EmployeeAtds.Select(x => x.EmplName).Distinct().ToList();
Update:
var names = DataContext.EmployeeAtds
.GroupBy(x => x.EmplID)
.Select(g => new { EmplID = g.Key, EmplName = g.FirstOrDefault().EmplName })
.ToList();

how to return a cursor or a result set from a oracle stored function

I have a stored function
CREATE OR REPLACE FUNCTION schedule(name in varchar2,pass in varchar2 )
begin
select t.name,s.starttime from traininfo t,schedule s, trainslot ts
where t.trainid in( select ts.trainid from trainslot
where ts.slotid in (select s.slotid from schedule s
where s.source='dhaka'
and s.dest='bogra' ))
end
I want to return this result set using a cursor.
I don't see where you are using either of the input parameters in your function. I'll assume that is either intentional or an oversight because you're simplifying the code. It also appears that your query is missing conditions to join between the traininfo, schedule, and trainslot tables in the outer query. It seems odd that your nested IN statements are turning around and querying the schedule and trainslot tables given this lack of join conditions. I don't know whether this is a result of copy-and-paste errors or something that was missed in posting the question or whether these are real problems. I'll make a guess at the query you're intending to write but if my guess is wrong, you'll have to tell us what your query is supposed to do (posting sample data and expected outputs would be exceptionally helpful for this).
CREATE OR REPLACE FUNCTION schedule(name in varchar2,pass in varchar2 )
RETURN sys_refcursor
is
l_rc sys_refcursor;
begin
open l_rc
for select t.name, s.starttime
from traininfo t,
schedule s,
trainslot ts
where t.trainid = ts.trainid
and s.slotid = ts.slotid
and s.source = 'dhaka'
and s.dest = 'borga';
return l_rc;
end;

Resources