1

In a Symfony 3.4 Application I have an Entity with 4 properties plus the id.

It is managed by doctrine on a mySql DB.

Say the properties where named p1, p2, p3 and q. An example DB table could be like this:

id  p1  p2  p3  q
------------------
1   x   y   z   1
2   x   y   n   2
3   x       z   1
4   x       z   2
5   x   y   z   3
6   x   y   z   4
7   x   n   z   1

What I need to do is to request all entities from the DB that have different combinations of p1, p2, p3. So using the given sample DB table the result I need would be

id  p1  p2  p3  q
------------------
1   x   y   z   1
2   x   y   n   2
3   x       z   1
7   x   n   z   1

So the rows with id's 4, 5 and 6 wouldn't be in the set because the have "doubled" combinations of p1, p2, p3.

Now - how can I do this using the methods on the Repository class of Symfony 3.4 like described here:

https://symfony.com/doc/3.4/doctrine.html

Or are there any other ways to achieve what I am looking for?

Any hints are very welcome.

EDIT: Basically I am looking for a list of all existing combinations of p1, p2, p3 without having a combination doubled in the list. It doesn't matter which row is returned in the result set (regarding the properties id and q) as long as one (and only one) row of each combination of p1, p2, p3 is included.

user3440145
  • 793
  • 10
  • 34
  • In your example, there's the same values for `p1`, `p2`, `p3` at indexes 1 and 5. What are the criterias concerning the values of `id` and `q`? Anything you've tried so far? – Cid Oct 23 '18 at 15:59
  • @Cid thanks, thats true - I edited my question to fix the wrong target set. There are no criterias for id and q. Id is just the autoincrementing unique row id and q is another property that allowes to store multiple different values for q on the same combination of p1, p2, p3. What I need is to query for all different combinations of p1, p2, p3 but getting only one hit in the result list if one combination exists twice or more times (i doesn't matter which hit I get then). – user3440145 Oct 23 '18 at 16:13
  • I meant, why in your query `1 x y z 1` is prefered over `5 x y z 3` or `6 x y z 4` ? – Cid Oct 23 '18 at 16:17
  • @Cid the chosen row isn't prefered - it's just the first one in the table. I am only looking for a complete list of all existing combinations of p1, p2, p3. See my edit in the Question as well. – user3440145 Oct 23 '18 at 16:19

2 Answers2

2

A "group by" subquery to eliminate duplicated data, and a main query to search from ids:

$dql = 'SELECT r FROM myTable r
WHERE r.id IN (
    SELECT min(s.id) FROM myTable s
    GROUP BY s.p1, s.p2, s.p3
)';

$rows = $em->createQuery($dql)
    ->getResult();
Guillaume
  • 162
  • 3
  • 11
  • Thank you. This works and is correct I think. I mark @Cid s answere as the correct one only because it adds some info I can use as well and using the dql query builder methods seems to be prefered over the string representation. – user3440145 Oct 25 '18 at 09:39
  • @user3440145 don't hesitate to upvote his answer, even if you didn't mark it as solved, it's encouraging – Cid Oct 25 '18 at 10:14
1

If you only want the differents uniques combination of p1, p2 and p3 and don't care about id and q, you can exclude them from your query and use a distinct clause.

There is no built-in method of the Repository class for your need, you might want to create a custom repository class (I personnally do it every time I have to write custom queries for my entities)

Let's consider your entity (located in example in src/AppBundle/Entity/MyEntity.php) declared such way :

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="AppBundle\Repository\MyEntityRepository")
 */
class MyEntity
{
    //declarations of $id, $p1 and so on...
}

You can create a custom repository class (in example src/AppBundle/Repository/MyEntityRepository.php) with a method to get the needed result :

namespace AppBundle\Repository;

use Doctrine\ORM\EntityRepository;

class MyEntityRepository extends EntityRepository
{
    public function findAllUniqueCombinations()
    {
        $result = $this->createQueryBuilder('m')
                       ->select('m.p1 p1', 'm.p2 p2', 'm.p3 p3')
                       ->distinct()
                       ->getQuery()
                       ->getResult();

        return ($result);
    }
}

And, in some controller action :

$MyCombinationList = $this->getDoctrine()
                          ->getManager()
                          ->getRepository(MyEntity::class)
                          ->findAllUniqueCombinations();

I used quite the same query for testing (only the select() changed)

Input datas

id | name       | firstname
---+------------+---------- 
 1 | Smith      | John 
 2 | Smith      | John 
 3 | Smith      | John 
 4 | Smith      | John 
 5 | Doe        | Jane 
 6 | Connor     | Sarah 
 7 | The Sponge | Bob 
 8 | Marley     | Bob

The select was ->select('c.name name', 'c.firstname firstname')

The output var_dump($result); gave :

array (size=5)
  0 => 
    array (size=2)
      'name' => string 'Smith' (length=5)
      'firstname' => string 'John' (length=4)
  1 => 
    array (size=2)
      'name' => string 'Doe' (length=3)
      'firstname' => string 'Jane' (length=4)
  2 => 
    array (size=2)
      'name' => string 'Connor' (length=6)
      'firstname' => string 'Sarah' (length=5)
  3 => 
    array (size=2)
      'name' => string 'The Sponge' (length=9)
      'firstname' => string 'Bob' (length=3)
  4 => 
    array (size=2)
      'name' => string 'Marley' (length=6)
      'firstname' => string 'Bob' (length=3)
Cid
  • 14,968
  • 4
  • 30
  • 45
  • Although the answere of @Guillaume is correct as well I pick your's to be the correct one as I like the additional info on repository classes. Using the dql query builder methods seem to be the encouraged way instead of the string representation too. I implemented it this way and it works very good. Thank you. – user3440145 Oct 25 '18 at 09:38
  • I just noticed that this way I do not get an array of MyEntity Objects but an array with the pure result list from the DB. How could I get this to return an array of Objects of type MyEntity? I think all the inherited find methods from the repository class do that - don't they? – user3440145 Oct 25 '18 at 11:42
  • This is because you are getting some fields of that entity instead of a whole entity, so the object can't be built, hence an array of arrays. Take a look at [this](https://stackoverflow.com/questions/10482085/how-to-fetch-class-instead-of-array-in-doctrine-2/12044461#12044461) – Cid Oct 25 '18 at 12:30
  • OK I see. Thanks for that. Didn't test it but I assume it would help me out if I needed the Objects :-) – user3440145 Oct 25 '18 at 12:49