Question

I have a query with subquery in it. the subquery returns the value, that i need to return in php and that also is used in "where" clause. i trying to figure out how can i not exequte th subquery two times. I trying to assign the value of it to the variable. And it works fine in "select", but when i use variable in "where" clause, the query returns 0 rows.

SELECT  t.tour_id, t.tour_name, u.company_name, u.first_name, u.last_name,
        @expireDate:= (SELECT DATE_ADD(tour_start_date, INTERVAL (t.tour_duration - 1) DAY)
                         FROM travelhub_tours_instance
                        WHERE tour_id = t.tour_id
                     ORDER BY tour_start_date DESC
                        LIMIT 1) AS expire,
        ( @expireDate + INTERVAL 14 DAY ) AS expirediff,
         CURDATE() AS now,
        ( (@expireDate + INTERVAL 14 DAY) = CURDATE() ) AS criteria
  FROM travelhub_tours t
  JOIN travelhub_users u ON t.operator_id = u.user_id
 WHERE (@expireDate + INTERVAL 14 DAY) = CURDATE()

In the WHERE clause, I put the same as in "criteria" column. and without the WHERE clause it variable work exactly how I expect. I'm confused - without "where": enter image description here

Was it helpful?

Solution

The WHERE clause is using the variable's value as present before the execution of the query.

Try embedding the correlated sub-query result in a sub-query of it's own, then filtering that. The RDBMS is clever enough to only process what is needed, as if the sub-query I've written didn't ever exist...

SELECT
  tour_id, tour_name, company_name, first_name, last_name, expire,
  (expire + INTERVAL 14 DAY ) AS expirediff,
  CURDATE() AS now,
  ( (expire + INTERVAL 14 DAY) = CURDATE() ) AS criteria
FROM
(
  SELECT
    t.tour_id, t.tour_name, u.company_name, u.first_name, u.last_name,
    (SELECT DATE_ADD(tour_start_date, INTERVAL (t.tour_duration - 1) DAY)
       FROM travelhub_tours_instance
      WHERE tour_id = t.tour_id
     ORDER BY tour_start_date DESC
     LIMIT 1) AS expire
  FROM
    travelhub_tours t
  JOIN
    travelhub_users u
      ON t.operator_id = u.user_id
)
  AS sub_query
WHERE
  (expire + INTERVAL 14 DAY) = CURDATE()

Note:

The WHERE clause involves adding 14 days to every expiure value. You may be better off taking 14 days from CURDATE() instead, it only happens once.

WHERE
  expire = CURDATE() - INTERVAL 14 DAY

EDIT:

Also, note that RDBMS are actually quite clever. The SQL you write isn't exactly what is executed, it gets parsed, optimised, compiled, etc. It ends up as traditional sequential code. This means that the RDBMS can spot that you have the same sub-query written several times, and know that it needs only execute once, not several times...

For example, the two identical sub_queries here won't get executed twice for every record. The RDBMS is cleverer than that :) In fact, it can even tell that it only needs executing once, ever, because the result is not dependant on the records being processed.

SELECT
  (SELECT MAX(event_date) FROM event_table) AS max_event_date,
  event_date
FROM
  event_table
WHERE
  (SELECT MAX(event_date) FROM event_table) - INTERVAL 7 DAY <= event_date

That said, using sub_queries such as my original answer can make code easier to maintain (only need changing in one place).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top