我认为您应该以相反的方式进行操作以提高效率。下面我将向您展示我用来创建查询的过程。所以只有最后的查询是你需要的。但我解释了这些步骤,所以它可能会在未来帮助你。
First I would select all jobs. Most likely there are a lot less jobs then users if your goal is 100.000 users.
select JOB.id, JOB.category
FROM table.work JOB
Now we have all the jobs, lets see which users want to be notified about it.
select JOB.id, JOB.category, NOTIFY.user_id
FROM table.work JOB
LEFT JOIN table.notification_options NOTIFY
ON JOB.category=NOTIFY.category
WHERE NOTIFY.user_id IS NOT NULL
This creates a list with for each job, all the userID's that want to be notified about it. I added the WHERE
clause to remove all jobs from the list nobody wants to see.
Now we can JOIN
the users table to get user details aswell.
select JOB.id
, JOB.post_date
, JOB.longitude
, JOB.latitude
, USR.user_id
, USR.method_of_contact
, USR.contact_frequency
, USR.center_of_work_area_long
, USR.center_of_work_area_lat
, USR.distance_from_center
, ((ACOS(SIN(USR.center_of_work_area_lat * PI() / 180) * SIN(JOB.latitude * PI() / 180) + COS(USR.center_of_work_area_lat * PI() / 180) * COS(JOB.latitude * PI() / 180) * COS((USR.center_of_work_area_long – JOB.longitude) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS `distance`
FROM table.work JOB
LEFT JOIN table.notification_options NOTIFY
ON JOB.category=NOTIFY.category
LEFT JOIN table.user USR
ON NOTIFY.user_id=USR.user_id
WHERE NOTIFY.user_id IS NOT NULL
HAVING `distance`<=USR.distance_from_center
ORDER BY USR.user_id ASC, distance ASC
I included the distance in the query. Notice that I use HAVING
to check if the distance is smaller then the user supplied. If you would add it to the WHERE
clause you would get an error saying distance
is an unknown column.
I also added the ORDER BY
class to first sort it on user ID and then on distance. This will make it easier to create the array you want in PHP.
Now there are a lot of ways to implement the daily/weekly intervals. One of them is to create seperate scripts for each interval and only select the users that set it.
For example, you could create a script 'daily.php' which you run each day and have the following query
select JOB.id
, JOB.post_date
, JOB.longitude
, JOB.latitude
, USR.user_id
, USR.method_of_contact
, USR.contact_frequency
, USR.center_of_work_area_long
, USR.center_of_work_area_lat
, USR.distance_from_center
, ((ACOS(SIN(USR.center_of_work_area_lat * PI() / 180) * SIN(JOB.latitude * PI() / 180) + COS(USR.center_of_work_area_lat * PI() / 180) * COS(JOB.latitude * PI() / 180) * COS((USR.center_of_work_area_long – JOB.longitude) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS `distance`
FROM table.work JOB
LEFT JOIN table.notification_options NOTIFY
ON JOB.category=NOTIFY.category
LEFT JOIN table.user USR
ON NOTIFY.user_id=USR.user_id
WHERE NOTIFY.user_id IS NOT NULL
AND USR.contact_frequency = 'daily'
HAVING `distance`<=USR.distance_from_center
ORDER BY USR.user_id ASC, distance ASC
Now we have the query, lets create the PHP code for it. We can loop trough all the rows and create the array. Obviously instead of creating the array you could also directly process the result. Because if you create an array first, you do need to loop trough that array again afterwards.
<?php
$arNotify = array();
foreach ($queryresult as $row) {
$userid = $row->user_id;
$jobid = $row->id;
//check if there is an entry for the user in the database, else create it
if (!array_key_exists($userid, $arNotify))
$arNotify[$userid] = array();
//and then push the job
$arNotify[$userid][] = $jobid;
//the array is being created, but I still like to process the job directly
//notify_user($userid, $jobid);
}
var_dump($arNotify);
?>
There you go, the array as you want with the jobs sorted on closest first.