Как я могу использовать вычисленное значение в предложении WHERE? - PullRequest
0 голосов
/ 25 октября 2019

У меня следующий SQL:

SELECT members.id, FLOOR(DATEDIFF('2019-10-25', crew_cv.dob) / 365.25) as age
FROM members
JOIN crew_cv ON members.id=crew_cv.user_id 
WHERE members.active=1 AND age>20 AND age<30 
ORDER BY crew_cv.last_name, crew_cv.first_name 
LIMIT 0,30

И я получаю следующую ошибку в phpMySQL:

#1054 - Unknown column 'age' in 'where clause'

Как использовать вычисленное значение age в WHERE пункт?

Ответы [ 3 ]

1 голос
/ 25 октября 2019
FROM clause
ON clause
OUTER clause
WHERE clause
GROUP BY clause
HAVING clause
SELECT clause
DISTINCT clause
ORDER BY clause
TOP clause

Это порядок выполнения запроса, это означает, что в вашем запросе используется вычисление (в предложении where) перед определением (в предложении select).

Если вы все еще хотите разместить все в одном запросе, это мой рекомендуемый запрос:

SELECT members.id, temp.age
FROM members, 
     (SELECT user_id, crew_cv.last_name, crew_cv.first_name
             FLOOR(DATEDIFF('2019-10-25', crew_cv.dob) / 365.25) as age
      FROM crew_cv) as temp
WHERE members.id = temp.user_id  
      AND members.active=1
      AND temp.age > 20 AND temp.age < 30
ORDER BY temp.last_name, temp.first_name
LIMIT 0,30
1 голос
/ 25 октября 2019

Максим уже отвечает на вопрос, но удалил ответ.

MySQL расширяет предложение HAVING, поэтому оно работает даже в запросах без агрегации. Это позволяет ему фильтровать запрос, используя псевдонимы - и это может быть удобно. Итак:

SELECT m.id,
       FLOOR(DATEDIFF('2019-10-25', c.dob) / 365.25) as age
FROM members m JOIN
     crew_cv c
     ON m.id = c.user_id 
WHERE m.active = 1 
HAVING age > 20 AND age < 30 
ORDER BY c.last_name, c.first_name 
LIMIT 0, 30;

MySQL делает это, потому что имеет тенденцию материализовать подзапросы. Это добавляет накладные расходы для чтения и записи данных. В большинстве других баз данных вы бы просто выразили это, используя подзапрос или CTE, не влияя на производительность. MySQL перегружает HAVING в качестве альтернативного метода.

И все это говорит о том, что / 365.25 является приближенным. Более точный запрос будет:

SELECT m.id,
       FLOOR(DATEDIFF('2019-10-25', c.dob) / 365.25) as age
FROM members m JOIN
     crew_cv c
     ON m.id = c.user_id 
WHERE m.active = 1 AND
      c.dob >= DATE('2019-10-25') - INTERVAL 30 YEAR AND
      c.dob <= DATE('2019-10-25') - INTERVAL 21 YEAR
ORDER BY c.last_name, c.first_name 
LIMIT 0, 30;

Это также имеет то преимущество, что он может использовать индекс для (dob), если MySQL считает, что это уместно.

1 голос
/ 25 октября 2019

В sql нельзя использовать псевдоним в предложении where (необходимо повторить код столбца)

  SELECT members.id, FLOOR(DATEDIFF('2019-10-25', crew_cv.dob) / 365.25) as age
  FROM members
  JOIN crew_cv ON members.id=crew_cv.user_id 
  WHERE members.active=1 AND FLOOR(DATEDIFF('2019-10-25', crew_cv.dob) / 365.25)>20 
      AND age<FLOOR(DATEDIFF('2019-10-25', crew_cv.dob) / 365.25) 
  ORDER BY crew_cv.last_name, crew_cv.first_name 
  LIMIT 0,30

, но вы можете создать представление

create view my_view as 
select   members.id, crew_cv.last_name, crew_cv.first_name , FLOOR(DATEDIFF('2019-10-25', crew_cv.dob) / 365.25) as age
 FROM members
  JOIN crew_cv ON members.id=crew_cv.user_id 
  WHERE members.active=1

, а затем

SELECT id,  age, last_name, first_name
from  my_view 
where  age>20 AND age<30 
      ORDER BY last_name, first_name 
      LIMIT 0,30

или примените условие к имеющему предложению

В sql там ключи оцениваются в определенном порядке
где условие оценивается перед предложением select (поэтому псевдоним столбца вне знаю на этом этапе) вместо этого, имеющее предложение оценивается после предложения select

...