Jump to content

Recommended Posts

Hi Guys,

Was hoping I could get some help with a query I am struggling with. Basically I have a table that stores recurring services which clients have.

 

[b]Table structure:[/b]
CREATE TABLE `recurring_invoice_products` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `product_id` int(10) unsigned default NULL,
  `sell_price` decimal(9,2) default NULL,
  `quantity` int(10) unsigned default NULL,
  `details` text,
  `username` varchar(64) default NULL,
  `client_id` int(11) default NULL,
  `recurrence` smallint(6) default NULL,
  `recurrence_type` tinyint(4) default NULL,
  `last_occurrence` date default NULL,
  `start` date default NULL,
  `end` date default NULL,
  PRIMARY KEY  (`id`)
);

 

Now for the key explanations:

- start : start date of the service

- end : end date of the service

- recurrence_type: type of recurrence, 1 = days, 2 = months, 3 = years

- recurrence: this is the value of how many units of recurrence_type will pass, eg: 15 recurrence with a recurrence_type of 1 is 15 days

- last_occurrence: last time that this service 'occurred' (ie: was charged)

 

I already have a PHP function which can find out if it time to charge the client again or not, but I was wondering if could take it one step further and not even have MySQL return unnecessary rows.

 

[b]PHP Function:[/b]
function next_occurrence($recurrence,$recurrence_type,$from_date)
{
if ($recurrence_type == 1)
	return date('Y-m-d',mktime(0,0,0,date('m',strtotime($from_date)),date('d',strtotime($from_date))+$recurrence,date('Y',strtotime($from_date))));
elseif ($recurrence_type == 2)
	return date('Y-m-d',mktime(0,0,0,date('m',strtotime($from_date))+$recurrence,date('d',strtotime($from_date)),date('Y',strtotime($from_date))));
elseif ($recurrence_type == 3)
	return date('Y-m-d',mktime(0,0,0,date('m',strtotime($from_date)),date('d',strtotime($from_date)),date('Y',strtotime($from_date))+$recurrence));
else
	return false;
}

 

eg code of above function:

if (date('Y-m-d') = next_occurrence($row_data['recurrence'],$row_data['recurrence_type'],$row_data['last_occurrence'])) charge_client;

 

You guys know of a way?

Dont know if something like this is possible?

Link to comment
https://forums.phpfreaks.com/topic/74572-solved-complicated-date-query/
Share on other sites

In a single query I basically would like to return all the rows in 'recurring_invoice_products' which their last_occurrence value + the value of recurrence (based on the recurrence type) = today.

 

For example, lets say I have two records in recurring_invoice_products:

+------------+------------+----------------+------------+-----------------+
| start      | end        | last_occurence | recurrence | recurrence_type |
+------------+------------+----------------+------------+-----------------+
| 2007-01-03 | 2999-01-01 | 2007-10-01     |          1 |               1 |
| 2007-01-04 | 2999-01-01 | 2007-10-01     |          1 |               2 |
+------------+------------+----------------+------------+-----------------+

 

If you look at the first record, it has a recurrence of 1 and a recurrence type of 1 - this means each day this item should get charged.

So basically, in pseudo code, the SQL statement would be:

SELECT * FROM recurring_invoices WHERE last_occurrence + INTERVAL recurrence (as value: 1,2,3 - etc) recurrence_type (as type, 1=day,2=month,3=year) = CURDATE()

This is the solution I came up with; thanks for leading me in the right direction :)

SELECT
start, end, recurring_invoice_products.id as recurring_invoice_product_id, product,last_occurrence,
CASE 
	WHEN recurrence_type=1 THEN 
	(last_occurrence + INTERVAL recurrence DAY)
	WHEN recurrence_type=2 THEN
	(last_occurrence + INTERVAL recurrence MONTH)
	ELSE
	(last_occurrence + INTERVAL recurrence YEAR)
END as next_occurrence
FROM
recurring_invoice_products,products,product_types 
WHERE
product_types.id=products.product_type_id AND recurring_invoice_products.product_id=products.id AND end > NOW() 
HAVING
next_occurrence <= CURDATE()
ORDER BY product

Thanks :)

Whats improper about how I've done it? Please correct me :)

 

Here is the single update SQL statement thats updates the 'last_occurrence' to have the 'next_occurrence' value if anyones interested:

UPDATE
recurring_invoice_products
SET
last_occurrence = 
CASE 
	WHEN recurrence_type=1 THEN 
	(last_occurrence + INTERVAL recurrence DAY)
	WHEN recurrence_type=2 THEN
	(last_occurrence + INTERVAL recurrence MONTH)
	ELSE
	(last_occurrence + INTERVAL recurrence YEAR)
END
WHERE
end > NOW() AND 
(CASE 
WHEN recurrence_type=1 THEN 
(last_occurrence + INTERVAL recurrence DAY)
WHEN recurrence_type=2 THEN
(last_occurrence + INTERVAL recurrence MONTH)
ELSE
(last_occurrence + INTERVAL recurrence YEAR)
  END) <= CURDATE()

Thanks :)

Whats improper about how I've done it? Please correct me :)

 

FROM
recurring_invoice_products
INNER JOIN products ON ( products.id=recurring_invoice_products.product_id )
INNER JOIN product_types ON ( product_types.id=products.product_type_id )
WHERE end > NOW() 

Thanks fenway :)

Whats the difference/implications/etc?

First, it's easier to read -- which means easier to debug -- really hard to miss a JOIN condition this way.

Second, it "forces" the optimizer to pick the right conditions for the JOIN.

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.