Как вы используете sql выбранные данные в выражении where / и - PullRequest
3 голосов
/ 22 апреля 2020

У меня есть этот mysql код, который работает нормально, но я хотел знать, как можно избежать вычисления RAW-данных дважды, вот мой код

SELECT `users`.*, ( 3959 * ACOS(COS(RADIANS(43.9743)) *
  COS(RADIANS(locations.lat)) * 
  COS( RADIANS(-75.9122) - RADIANS(locations.LONG)) +
                              SIN(RADIANS(43.9743)) *
  SIN(RADIANS(locations.lat) )) ) AS distance 
FROM   `users` 
INNER JOIN `addresses` ON `users`.`id` = `addresses`.`user_id` 
LEFT JOIN `locations` ON `addresses`.`zip` = `locations`.`zip` 
WHERE  `type` = 'doctor' 
  AND ( 3959 * ACOS(COS(RADIANS(43.9743)) * COS(RADIANS(locations.lat)) *
    COS( RADIANS(-75.9122) - RADIANS(locations.LONG)) +
    SIN(RADIANS(43.9743)) * SIN(RADIANS(locations.lat) )) ) < 100
  AND `users`.`deleted_at` IS NULL 
ORDER BY distance ASC
LIMIT  15 OFFSET 0 

, как вы можете видеть, я использую это вычисление дважды ( 3959 * ACOS(COS(RADIANS(43.9743)) * COS(RADIANS(locations.lat)) * COS( RADIANS(-75.9122) - RADIANS(locations.LONG)) + SIN(RADIANS(43.9743)) * SIN(RADIANS(locations.lat) )) ) для И и SELECT оператора.

Я пытался получить AND distance < 100, но я получил ошибку, говоря, что столбец не существует.

Ценю любую помощь

Ответы [ 2 ]

4 голосов
/ 22 апреля 2020

MySQL расширяет использование предложения having, и это лучший способ решить эту проблему:

SELECT u.*,
       ( 3959 * ACOS(COS(RADIANS(43.9743)) * COS(RADIANS(l.lat) ) * 
                     COS( RADIANS(-75.9122) - RADIANS(l.LONG)) +
                     SIN(RADIANS(43.9743)) * SIN(RADIANS(l.lat))
                    )
       ) AS distance 
FROM `users` u INNER JOIN
     `addresses` a 
     ON u.`id` = a.`user_id` LEFT JOIN
     `locations` l
     ON a.`zip` = l.`zip` 
WHERE `type` = 'doctor' AND u.`deleted_at` IS NULL 
HAVING distance < 100
ORDER BY distance ASC
LIMIT  15 OFFSET 0 

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

4 голосов
/ 22 апреля 2020

Вы можете поместить вычисленные столбцы в подзапрос (в частности, «табличное выражение»), где именованный столбец доступен из.

Например:

select *
from ( -- the definition of table expression "x" starts
  SELECT `users`.*, ( 3959 * ACOS(COS(RADIANS(43.9743)) *
    COS(RADIANS(locations.lat)) * 
    COS( RADIANS(-75.9122) - RADIANS(locations.LONG)) +
                              SIN(RADIANS(43.9743)) *
    SIN(RADIANS(locations.lat) )) ) AS distance 
  FROM   `users` 
  INNER JOIN `addresses` ON `users`.`id` = `addresses`.`user_id` 
  LEFT JOIN `locations` ON `addresses`.`zip` = `locations`.`zip` 
) x -- the definition of table expression "x" ends
WHERE `type` = 'doctor' 
  AND distance < 100 -- here we use the "distance" column
  AND `users`.`deleted_at` IS NULL 
ORDER BY distance ASC
LIMIT  15 
OFFSET 0 

In MySQL 8.x вы можете использовать CTE (Common Table Expression), например:

with
x as (
  SELECT `users`.*, ( 3959 * ACOS(COS(RADIANS(43.9743)) *
    COS(RADIANS(locations.lat)) * 
    COS( RADIANS(-75.9122) - RADIANS(locations.LONG)) +
                              SIN(RADIANS(43.9743)) *
    SIN(RADIANS(locations.lat) )) ) AS distance 
  FROM   `users` 
  INNER JOIN `addresses` ON `users`.`id` = `addresses`.`user_id` 
  LEFT JOIN `locations` ON `addresses`.`zip` = `locations`.`zip` 
)
SELECT *
FROM x
WHERE  `type` = 'doctor' 
  AND distance < 100
  AND `users`.`deleted_at` IS NULL 
ORDER BY distance ASC
LIMIT  15 
OFFSET 0 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...