Skip to content
Advertisement

PHP/SQL select based on sum result

I’m having a hard time limiting my query results based on sum. Example code:

    $rows = Entry::find()
      ->section('cities')
      ->select('state')
      ->having("sum(case when covered = '1' then 1 else 0 end) = 0")
      ->asArray()
      ->all();

I want to only select states where 0 cities are “covered”. Running my code above the “having” line seems to be ignored (it includes both zero and non-zero cases). I tried using “where” instead of “having” but it results in a PDOException – “Invalid use of group function”. I assume “having” is the right approach, but that I’m making a novice mistake — any tips?

/*** UPDATE 1 ***/

Thanks @scaisEdge and @angelm for the tip — groupBy helps, but it’s still not working as expected. It seems the “having” line is still ignored. With modified code:

    $test = Entry::find()
      ->section('cities')
      ->select(['state', 'covered', "sum(case when covered = '1' then 1 else 0 end) as numCovered"])
      ->groupBy('state')
      ->having("sum(case when covered = '1' then 1 else 0 end) = 0")
      ->asArray()
      ->all();

I log the following results:

{state: "AL", covered: "0", numCovered: "0"}
{state: "AK", covered: "0", numCovered: "0"}
{state: "CA", covered: "1", numCovered: "19"}
{state: "CO", covered: "0", numCovered: "0"}
...

As you can see above, states (CA) are included when numCovered is clearly not 0.

I also tried the following code for “having” (which I assume is the same):

->having("numCovered = 0")

/*** UPDATE 2 ***/

Using a reduced test case suggested by @cpalmer still results in “CA” being selected despite having numCovered = 19. I’m now wondering if this is a peculiarity with Craft CMS, since it would seem my query is correct?

    $test = Entry::find()
      ->section('cities')
      ->select('state')
      ->groupBy('state')
      ->having("sum(case when covered = '1' then 1 else 0 end) = 0")
      ->asArray()
      ->all();

Is there a way to write this query without having?

/*** UPDATE 3 ***/

As suggested by the DB Fiddle posted by @pocketrocket my sql should work. Dumping the raw sql suggests the having line is ignored. The issue likely resides with CraftCMS/Yii and my lack of understanding of the environment.

Advertisement

Answer

First of all: I am total with @Olivier, you should decouple the SQL part of your question from the architecture itself. For the SQL part, it’s important to let others know which database or SQL dialect you use (MySQL, PostgreSQL, MsSQL…).

Just guessing it’s MySQL what you are using: Both ways should actually work, repeating the querypart in having or referencing it by name as suggested by user126587

If both don’t work and you would like to work without having maybe you can implement a subselect?

SELECT 
    state, 
    sum(case when covered = '1' then 1 else 0 end) as numCovered 
FROM cities 
GROUP BY state
HAVING sum(case when covered = '1' then 1 else 0 end) = 0;

SELECT 
    state, 
    sum(case when covered = '1' then 1 else 0 end) as numCovered 
FROM cities 
GROUP BY state
HAVING numCovered = 0;

SELECT * FROM (
  SELECT 
      state, 
      sum(case when covered = '1' then 1 else 0 end) as numCovered 
  FROM cities 
  GROUP BY state
) sub_select
WHERE sub_select.numCovered = 0;

You can play around with it here: DB Fiddle Link

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement