Unique document number for the month - php

I need to create an invoice number in format:
CONSTANT_STRING/%d/mm/yyyy
mm - Month (two digits)
yyyy - Year
Now, the %d is the number of the invoice in the specific month. Another words, this number is reseted every month.
Now I am checking in database what is the highest number in current month. Then after its incrementation I am saving the row.
I need the whole number to be unique. However, it sometimes happens that it is being duplicated (two users save in the same time).
Any suggestions?

Put a unique index on the field and catch the database error when trying to save the second instance. Also, defer getting the value until the last possible moment.

One solution is SELECT ... FOR UPDATE, which blocks the row until you update it, but can cause deadlocks with a serios multitasking application.
The best way is to fetch the number and increment it in a transaction and then start the work.
This way, the row is not locked for long.
Look into BEGIN WORK and COMMIT.

Use the primary key (preferably an INT) of the invoice table or assign a unique number to each invoice, e.g. via uniqid.
PS. If you are using uniqid, you can increase the uniqueness by setting more_entropy parameter to true.

set the id all in one query.
$query = 'INSERT INTO table (invoice_number) VALUES (CONCAT(\''.CONSTANT.'\', \'/\', (SELECT COUNT(*) + 1 AS current_id FROM table WHERE MONTH(entry_date) = \''.date('n').'\' AND YEAR(entry_date) = \''.date('Y').'\'), \'/\', \''.date('m/Y').'\'))';

Related

How to generate unique auto increment value for each user in laravel and add it to database

I am developing a event organization website. Here when the user registers for an event he will be given a unique random number(10 digit), which we use to generate a barcode and mail it to him. Now,
I want to make the number unique for each registered event.
And also auto increment
One solution is to grab all the auto increment numbers in an array and generate a auto increment number using laravel takes the form (0000000001 to 9999999999) and loop through and check all the values. Grab the first value that doesn't equal to any of the values in the array and add it to the database.
But I am thinking that there might be a better solution to this. Any suggestion?
Select Maximum number stored in your DB and add 1 in it like:
SELECT (MAX(Column_Name)+1) AS Max_val FROM Table_Name;
I suggest simple timestamp-based solution using the Carbon class to produce a unique number using timestamp. It's fairly simple to have a basic unique and random stamp generation using timestamp.
You can use as given below,
use Carbon\Carbon;
$current_timestamp = Carbon::now()->timestamp; // Produces something like this 1552296328
You can use it as a unique identifier. If you want the next numbers, just +1. But keep in mind, you have to manage another number batch in a timely manner. (i.e if you have generated 500 numbers for now by increment, You should not generate another number for the next 500 seconds. Otherwise, it will repeat the number). If you want to know more, you can read here.
The solution with rand() function may not work here because it can re-produce the existing number in the database and you will be errored for Unique Constraint Violation(i.e. If you have column unique in DB).
No matter what approach you use, it would never be truly random. It will be PRNG. For your case, I think auto increment with zero fill should be enough.
But if you are set on using random number then using rand() function of PHP should be enough. 10 digit means 10000000000 unique number.Unless your project has millions of events it should realistically be no problem. So, approach 1 should be no problem. Also, you can check after generating any random number that whether that number is already present(There is 0.000001% or something like that chance.). If it is present then try to generate a random number again.
But if your project gets very successful (I.E. millions of events) then problems similar to Y2K might creep up.
MySQL UUID would give you truly unique is: Store UUID v4 in MySQL
You don’t need to worry about auto incrementing.

Purge old data in dynamo db by rate limiting in php

I have dataset in dynamodb, whose primary key is user ID, and timestamp is one of the data attribute. I want to run a purge query on this table, where timestamp is older than 1 week.
I do not want to eat up all writes per s units. I would ideally want a rate limiting delete operation(in php). Otherwise for a dataset that's 10sof GBs in size, it will stop other writes.
I was wondering on lines of usingglobal secondary indexing on timestamp (+user ID) would help reduce the rows to be scanned. But again, I'd not want to thrash table such that other writes start failing.
Can someone provide rate limiting insert/delete example code and references for this in php?
You can create a global secondary index:
timestampHash (number, between 1 and 100)
timestamp (number)
Whenever you create/update your timestamp, also set the timestampHash attribute as a random number between 1 to 100. This will distribute the items in your index evenly. You need this hash because to do a range query on a GSI, you need a hash. Querying by user id and timestamp doesn't seem to make sense because that will only return one item every time and you will have to loop over all your users (assuming there is one item per user id).
Then you can run a purger that will do a query 100 times for each timestampHash number and all items with timestamp older than 1 week. Between each run you can wait 5 minutes, or however long you think is appropriate, depending on the number of items you need to purge.
You can use BatchWriteItem to leverage the API's multithreading to delete concurrently.
In pseudocode it looks like this:
while (true) {
for (int i = 0; i < 100; i++) {
records = dynamo.query(timestampHash = i, timestamp < Date.now());
dynamo.batchWriteItem(records, DELETE);
}
sleep(5 minutes);
}
You can also catch ProvisionedThroughputExceededException and do an exponential back off so that if you do exceed the throughput, you will reasonably stop and wait until your throughput recovers.
Another way is to structure structure your tables by time.
TABLE_08292016
TABLE_09052016
TABLE_09122016
All your data for the week of 08/28/2016 will go into TABLE_08292016. Then at the end of every week you can just drop the table.

Finding Interval of a data present on latest 2 dates

I'm developing a web-based tool that can help analyze number intervals that occurs in a 6-digit lottery.
Let us focus on a certain number first. Say 7
The sql query I've done so far:
SELECT * FROM `l642` WHERE `1d`=7 OR `2d`=7 OR `3d`=7 OR `4d`=7 OR `5d`=7
OR `6d`=7 ORDER BY `draw_date` DESC LIMIT 2
This will pull the last two latest dates where number 7 is present
I'm thinking of using DATEDIFF but I'm confused on how to get the previous value to subtract it on the latest draw_date
My goal is to list the intervals of numbers 1-42 and I'll plan to accomplish it using PHP.
Looking forward to your help
A few ideas spring to mind.
(1) First, since you perfectly have your result set ordered, use PHP loop on the two rows getting $date1 =$row['draw_date']. Then fetch next/last row and set $date2 =$row['draw_date']. With these two you have
$diff=date_diff($date1,$date2);
as the difference in days.
(2)
A second way is to have mysql return datediff by including a rownumber in the resultset and doing a self-join with aliases say alias a for row1 and alias b for row2.
datediff(a.draw_date,b.drawdate).
How one goes about getting rownumber could be either:
(2a) rownumber found here: With MySQL, how can I generate a column containing the record index in a table?
(2b) worktable with id int auto_increment primary key column with select into from your shown LIMIT 2 query (and a truncate table worktable between iterations 1 to 42) to reset auto_increment to 0.
The entire thing could be wrapped with an outer table 1 to 42 where 42 rows are brought back with 2 columns (num, number_of_days), but that wasn't your question.
So considering how infrequent you are probably doing this, I would probably recommend not over-engineering it and would shoot for #1

How to generate a unique transaction id in a shopping cart

I am working on a shopping cart and a local payment gateway that requires each transaction to have a unique order id. This id is supposed to be saved in the database against the order details and sent as a variable to the payment gateway. My dilemma is on how to generate the unique id and how to save it before sending my variables to the gateway so that I can check that it matches when a response is received from the gateway's IPN. The variable in question is show below:
$reference = $_POST['reference'];//unique order id of the transaction, generated by merchant
Here is how i used to generate the random key, even though its bit lengthy you can achieve unique random key.
$id.time().uniqid(mt_rand(),true)
uniqid() - this will generate the 13 character uniqid
mt_rand() - generates random number by using Mersenne Twister algorithim and is 4 times more fast then rand()
uniqid(mt_rand()) - prefixing the random generate number with uniqueid
uniqid(mt_rand(), true) - to get more strong random i am enabling entropy of uniqid by setting second parameter to 'true'
$id.time().uniqid(mt_rand(), true) - here $id may be userid, productid or any id which you want to choose, time() will generate current unix time stamp, lastly i will append with my uniqid(...)
Do not use md5() on uniqueid() it will actually loose on security. To append or prepend md5 value is OK.
That said I would stick to http://www.php.net/manual/en/pdo.lastinsertid.php to get newly inserted ID, but also generate uniqueid() with prefix parameter set to lets say 'username_' so that way it should be pretty much unique.
If you really want an unique-id, here is the code which I am using. This simple creates 7 characters string and if it already exists in database -> regenerate new, until it is 100% unique. uniqid() is not really unique id, you could put there your own prefix which could be mixed with my code, but alone uniqid() with putting it to base64 and md5 and sha1 and I dont know what else IS NOT unique.
function randString($length, $charset='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')
{
$str = '';
$count = strlen($charset);
while ($length--) {
$str .= $charset[mt_rand(0, $count-1)];
}
return $str;
}
$unique_id = randString(7);
while(mysqli_num_rows(mysqli_query($con, "SELECT unique_id FROM table WHERE unique_id = '".mysqli_real_escape_string($con, $unique_id)."'")) > 0) {
$unique_id = randString(7);
}
//insert this id into database and use it
Insert the order details into a table. The primary key of that table should have AUTO INCREMENT property set. Then retrieve the last inserted id http://php.net/manual/en/function.mysql-insert-id.php
Besides primary key of order table, a combination of a string, year, month, day and 4 digit no. can be useful.
eg.
orders placed on 8th Aug 2013 could have following order numbers:
OS201308080001
OS201308080002
orders placed on 9th Aug 2013 could have following order numbers:
OS201308090001
OS201308090002
OS201308090003
where OS could be initial's of your store name, next 4 digits are year, next 2 digits are months, next 2 digits are date and next 4 digits (starting from 0001 every day) can identify number of orders each day.
I would say that the way to make the most unique ID would be a combination of the current timestamp (unix using time()) and then append and/or prepend it with something like the current users username. This way it is almost impossible to create a duplicate. You could also add in the last inserted ID as well.
In my opinion the combination of these three is a simple method and will make it almost impossible for duplicates due to the fact that time() will change every second and a user is very unlikely to be able to add 2 orders at the exact same second.
Something based on a table of your database? A column with AUTO_INCREMENT. You can fetch the last insert ID with PDO with this: http://www.php.net/manual/en/pdo.lastinsertid.php
Or something like
$reference = sha1(md5(time()));

How do I retrieve a random (but unique for a date) primary key value?

I have about 10,000 products in the product table. I want to retrieve one of those items and display it in a section of a web page which stays the same for that particular day. Something like "Product of the day".
For example, if today I get product_id 100, then all of the visitors should be viewing this product item for today. Tomorrow it may fetch any random valid primary key, say, 1289 and visitors get 1289 product all day tomorrow.
Any ideas/suggestions?
Thanks for your help.
SELECT id
FROM products
ORDER BY
RAND(UNIX_TIMESTAMP(CURRENT_DATE()))
LIMIT 1
Maybe you can store the id of the item of the day in a table in the database?
How about create a cache file and invalidate it at midnight?
The benefit of this is you don't make unnecessary calls to your DB as you're only checking the timestamp on the cache file - only once per day do you make DB requests to populate a new cache file.
You don't need a CRON job for this:
if(date_of_file(potd_cache_file) != today){
potd_cache_file = generate_from_db();
}
load_file(potd_cache_file);
This will mean only the first visitor of the day to your website will trigger the regeneration, and every subsequent visitor will have a fast loading cache file served to them.
The idea is pretty simple,
Set a table up call ProductOfTheDay with a product ID and a date field
On the product of the day page when a user visits check the date field
If it is todays date then show the product
If it is not then randonly pick a new product and save it to the field.
Its not that complex of an operation.
SELECT id
FROM products
ORDER BY (id + RAND(UNIX_TIMESTAMP(CURRENT_DATE()))) MOD some_reasonable_value
LIMIT 1
You can start random number generators with a seed value.
Make the seed value be the day (21st) + month(10) + year(2009) so today's seed is 2041.
You will get the same random number all day, and tomorrow a different one. This is more how it works in .net. The random function takes a max and min value (this is your min and max ID values) then an optional seed value and returns a number. For the same seed number you get the same random number generated. It's possible if you change the max and min this can affect the number generated. You would have to look up how php works.
total = SELECT COUNT(id) FROM products;
day_product = SELECT id FROM products WHERE id = (UNIX_TIMESTAMP(CURRENT_DATE()) MOD total) LIMIT 1;
See also this question.

Categories