MySql rows based on column value compared with other column

Sumair Rasool :

I have a table person, which is like this,

Persons

id | name
1  | Alex
2  | Jack
3  | Roy

I have an other table

Properties

id | title          | format
1  | Age            | number
2  | Plays Football | checkbox
3  | Weight         | number

Persons and Properties have many to many relation through a third table PersonProperties.

PersonProperties

PersonId | PropertyId | value
1        | 1          | 24
1        | 2          | true
2        | 1          | 43

I want to filter out persons having age 20 to 30 and plays football. As i already have ids of Age and Plays Football with their values which are id 1 (min = 20, max = 30) and id 2 (true). To get that i query like this,

SELECT `Persons`.`id`,`name` FROM `Persons`
INNER JOIN `PersonProperties` ON `Persons`.id = `PersonProperties`.`PersonId`
WHERE ((`PersonProperties`.`value` >= 20 AND `PersonProperties`.`value` <= 30) AND `PersonProperties`.`PropertyId` = 1) 
  AND (`PersonProperties`.`value` = true AND `PersonProperties`.`PropertyId` = 2)
GROUP BY `Persons`.`id`

It return empty result.

Desired Outcome

id | name
1  | Alex
Gordon Linoff :

Your version doesn't work, because no single row can match both conditions. You need to match across rows.

Use aggregation for this:

SELECT p.id, p.name
FROM Persons p JOIN
     PersonProperties pp
     ON p.id = pp.PersonId
WHERE (p.PropertyId = 1 AND (p.value + 0) >= 20 AND (p.value + 0) <= 30) OR
      (p.PropertyId = 2 AND p.value = 'true')
GROUP BY p.id, p.name
HAVING COUNT(*) = 2;  -- both match

Notes:

  • Table aliases make a query much easier to write and to read.
  • Backticks make a query harder to write and to read.
  • Value is a string (presumably). Hence, you need to be careful with comparisons. I added the (+ 0) to be clear that a conversion is involved.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=372367&siteId=1