I am currently trying to solve a complex problem with MySQL and PHP.
Here is an example of the tables that I have:
List of clients:
table_clients Client_ID | Client_Name | Address | Zip Code | ----------|-------------|-----------------|----------| 1 | Mark | 127 Park Ave | 12235 | 2 | John | 6 Freeman Drive | 12899 | 3 | Allan | 450 Clever Rd | 12235 |
List of services:
table_services Service_ID | Service_Name | Service_Price | -----------|--------------|---------------| 1 | Fertilizer | 100.00 | 2 | Bug Spray | 50.00 | 3 | Seeds | 20.00 |
The following table stores which customer has which services (one or more), the status of the service and the date it was completed, if applicable:
table_jobs Job_ID | Client_ID | Service_ID | Status | Date_Done | -------|-----------|------------|--------|------------| 1 | 1 | 1 | done | 2013-05-01 | 2 | 1 | 3 | active | NULL | 3 | 2 | 1 | active | NULL | 4 | 2 | 2 | active | NULL | 5 | 3 | 1 | active | NULL | 6 | 3 | 3 | active | NULL |
Now comes the hard part. Some services should have a certain time difference with others. For example, one client cannot receive seeds if he received fertilizer in the last 30 days. To track this, I have a third table with information:
table_time_difference Service_ID_1 | Service_ID_2 | Time_Diff | -------------|--------------|-----------| 1 | 3 | 30d | 1 | 4 | 7d | 2 | 4 | 14d | 4 | 5 | 14d |
Now that everything is stored in the database (keep in mind that there may be dozens of services and thousands of customers), I try to get client lines with certain services or not, always observing the time difference.
For instance:
I want all the client that should receive the Fertilizer to return:
Client_ID | Client_Name | Zip Code | Job_ID | Service_ID | Service_Name | ----------|-------------|----------|--------|------------|--------------| 2 | John | 12235 | 3 | 1 | Fertilizer | 3 | Allan | 12145 | 5 | 1 | Fertilizer |
Now, if I want to do all the clients that should get Fertilizer AND Bug Spray:
Client_ID | Client_Name | Zip Code | Job_ID | Service_ID | Service_Name | ----------|-------------|----------|--------|------------|--------------| 2 | John | 12235 | 3 | 1 | Fertilizer | 2 | John | 12235 | 4 | 2 | Bug Spray |
And if I want to do all the clients that should receive seeds in ZIP code 12235:
Client_ID | Client_Name | Zip Code | Job_ID | Service_ID | Service_Name | ----------|-------------|----------|--------|------------|--------------| 3 | Allan | 12235 | 6 | 3 | Fertilizer |
Please note that Mark is not included because it does not meet the requirements of 30 days since the last fertilizer service.
I tried many different options with all kinds of JOINS, but never found a solution that would work as described. The closest I got is to generate subqueries with PHP and join them in a large request.
For example, one of my attempts looked like this (for the last expected result above):
SELECT c.Client_ID, c.Client_Name, c.Zip_Code, j.Job_ID, s.Service_ID, s.Service_Name FROM clients c LEFT JOIN jobs j ON j.Client_ID = c.Client_ID LEFT JOIN services s ON s.Service_ID = j.Service_ID WHERE s.Service_ID = "1" && c.Zip_Code = "12235" && c.Client_ID NOT IN ( SELECT Client_ID FROM jobs WHERE Status = "done" && Date_Done < (UNIX_TIMESTAMP() - 2592000) )
- Please note that a subquery was generated by a PHP script that searches for the restrictions corresponding to the requested service and the minimum time difference for this service, since there can be several restrictions for the same service, and I do not know if I can do this in pure SQL.
Now the request shown above works for this exact scenario (although it is very slow), it breaks, and I could not adapt it to my other needs (several services included or excluded).
Tell me if you need any other information or if you are ready to discuss it further.
Thanks to everyone who read the whole question (very long), and I hope that some of you will understand my needs and help me!