টপিকঃ তারিখসহ ইউনিক নম্বর পিএইচপিতে কিভাবে জেনারেট করব?

আমার এমনটা দরকার
দিন-মাস-বছর-চারসংখ্যার ইউনিক নম্বর
২৮-০৬-২০১৪-০০০০

একই দিনে যেহেতু একাধিক নম্বর জেনারেট হতে পারে, তাই শেষের চারসংখ্যা দ্বারা সেটা ইউনিক করার ইচ্ছা। এবং প্রতিদিন ০০০০ থেকে শুরু হবে।

Re: তারিখসহ ইউনিক নম্বর পিএইচপিতে কিভাবে জেনারেট করব?

আপনি কী 28-06-2014-0000, 28-06-2014-0001, 28-06-2014-0002 . . . 28-06-2014-9999 এভাবে ইনক্রিজ করতে চাচ্ছেন? সেক্ষেত্রে ডেটা কোথাও সংরক্ষণ করতে হবে।

28-06-2014-53adcefe8c397
28-06-2014-53adcf2764d12

উপরের মত আউটপুট যদি চলে তাহলে নিচের কোডটি ব্যবহার করতে পারেন।

uniqid(date('d-m-Y-'));

কিংবা টাইমস্ট্যাম্প ও ব্যবহার করতে পারেন। সেটাও ইউনিক হবে।

লেখাটি CC by-nc-sa 3.0 এর অধীনে প্রকাশিত

Re: তারিখসহ ইউনিক নম্বর পিএইচপিতে কিভাবে জেনারেট করব?

একই সেকেন্ডে যদি দুটো এন্ট্রি হয়? confused

ডেটাবেজ আছে।

28-06-2014-0000, 28-06-2014-0001, 28-06-2014-0002 . . . 28-06-2014-9999 আমি এভাবেই বাড়াতে চাচ্ছি।

Re: তারিখসহ ইউনিক নম্বর পিএইচপিতে কিভাবে জেনারেট করব?

দক্ষিণের-মাহবুব লিখেছেন:

একই সেকেন্ডে যদি দুটো এন্ট্রি হয়? confused

কলাম ইউনিক ডিফাইন করা যেতে পারে। আরও অনেক পদ্ধতি আছে নিশ্চিত হওয়ার জন্য। wink

নিচের কোডটা ব্যবহার করতে পারেন। smile

function getUniqueId($id) {
    // You could use preg_split() instead
    $dateFromId = substr($id, 0, 10);
    $tokenFromId = substr($id, 11);
    
    $today = date('d-m-Y');
    
    return ($dateFromId != $today) ? $today . '-0000' : $dateFromId . '-' . sprintf('%04d', ($tokenFromId + 1));
}

$id = '28-06-2014-0099'; // SELECT `id` FROM `table` ORDER BY `id` DESC LIMIT 0, 1;

echo getUniqueId($id);

লেখাটি CC by-nc-sa 3.0 এর অধীনে প্রকাশিত

Re: তারিখসহ ইউনিক নম্বর পিএইচপিতে কিভাবে জেনারেট করব?

ডেটাবেইজ যখন ব্যবহার করছেন তখন SQL-এই অফলোড করে দিতে পারেন unique ID generation

postgres/oracle/sql server-এ sequence আছে। sequence ব্যবহার করে auto-incrementing id জেনারেট করা যায়।

যেমন, SQL server-এ MySequence নামে একটা সিকোয়েন্স তৈরী করলামঃ

CREATE SEQUENCE [MySequence]
 AS INT
 START WITH 0
 INCREMENT BY 1

এরপর NEXT VALUE FOR MySequence কল করলেই একটা একটা করে নতুন সিকোয়েনশিয়াল নাম্বার (1,2,3...) জেনারেট হতে থাকবেঃ

DECLARE @seqCounter INT
SET @seqCounter = NEXT VALUE FOR [MySequence]

আপনার রিকোয়ারমেন্ট অনুযায়ী T-SQL কোডঃ

DECLARE @seqCounter INT
SET @seqCounter = NEXT VALUE FOR [MySequence]

DECLARE @currentDate DATE
SET @currentDate = CAST(GETDATE() AS DATE)

DECLARE @uniqueId VARCHAR(20)
SET @uniqueId = FORMAT(@currentDate, 'dd-MM-yyyy ') + CAST(@seqCounter AS CHAR(4))

SELECT @uniqueId

ওপরের পুরো কোডটা ১ লাইনেই করা যায়, তবে বোঝার সুবিধার জন্য স্টেপ বাই স্টেপ ভেঙ্গে দিলাম।


SET @seqCounter = NEXT VALUE FOR [MySequence]

এখানে MySequence-এর পরবর্তী ভ্যালুটি @seqCounter ভ্যারিয়েবলে নিচ্ছি

SET @currentDate = CAST(GETDATE() AS DATE)

আজকের তারিখটি @currentDate-এ রাখছি। GETDATE() ফাংশন পুরো ডেট+টাইম রিটার্ণ করে, তাই CAST() ফাংশন ব্যবহার করে শুধু তারিখ পার্টটি নিচ্ছি।

SET @uniqueId = FORMAT(@currentDate, 'dd-MM-yyyy-') + CAST(@seqCounter AS CHAR(4))

@currentDate-এর তারিখটিকে 'dd-MM-yyyy-' প্যাটার্ণে ফরম্যাট করছি। এছাড়া @seqCounter-কে স্টৃং-এ পরিণত করছি।

পিএসঃ আপনার রিকোয়ারমেণ্টে দেখলাম ৪ ডিজিট নাম্বারটি left zero-padded। SQL server-এ প্যাডিং করার জন্য কোনো বিল্ট-ইন ফাংশন নাই। একটু ঘুরপথে করতে হবেঃ

SET @padstr = REPLICATE('0', 4)
SET @seqString = RIGHT(@padstr + CAST( @seqCounter AS VARCHAR(4)), 4)

ওপরের কোডটি আপনার ব্যবহৃত ডেটাবেইজের জন্য মডিফাই করে নিতে পারবেন গুগলের সাহায্যে। আর SQL নিয়ে বেশি ঝামেলা করতে না চাইলে PHP-তে অফলোড করে নিতে পারেন। সেক্ষেত্রে শুধুমাত্র ডেটাবেইজ থেকে শুধুমাত্র "SELECT NEXT VALUE FOR [MySequence]" কুয়েরী করে অয়ন ভাইয়ের কোডটি ব্যবহার করুন।

পিএস: 28-06-2014-0001 এর চাইতে 2014-06-28-0001 ফরম্যাটটি (yyyy-mm-dd...) বরং আরো অপ্টিমাইজড

পিএস #২: কি ডেটাবেইজ ব্যবহার করছেন?

Calm... like a bomb.

Re: তারিখসহ ইউনিক নম্বর পিএইচপিতে কিভাবে জেনারেট করব?

invarbrass লিখেছেন:

পিএস #২: কি ডেটাবেইজ ব্যবহার করছেন?

lol lol lol

প্রতিদিন যদি ৯৯৯৯টির বেশি রেকর্ড তৈরী হওয়ার সম্ভাবনা থাকে তাহলে পূর্বের পোস্টে যেই সমাধানটি দিয়েছি সেটা ব্যবহার করতে পারেন। মনে রাখবেন, এক্ষেত্রে ডেটাবেইজে `id` কলামের লেন্থ অবশ্যই ১৫ – এর বেশি দিতে হবে। তবে আপনি যদি নিশ্চিত থাকেন যে ৯৯৯৯টির বেশি রেকর্ড তৈরী হওয়ার সম্ভাবনা নেই তাহলে নিচের সমাধানটি ব্যবহার করতে পারেন।

function getUniqueId($id) {
    // You could use preg_split() instead
    $dateFromId = substr($id, 0, 10);
    
    $today = date('d-m-Y');
    
    if($dateFromId != $today) {
        return $today . '-0000';
    }
    
    // You could use preg_split() instead
    $tokenFromId = substr($id, 11, 14);
    
    if($tokenFromId >= 9999) {
        throw new Exception('Token limit reached for today!');
    }
    
    return $dateFromId . '-' . sprintf('%04d', ($tokenFromId + 1));
}

try {
    $id = '28-06-2014-0099'; // SELECT `id` FROM `table` ORDER BY `id` DESC LIMIT 0, 1;
    
    echo getUniqueId($id);
} catch(Exception $e) {
    echo $e->getMessage();
}

লেখাটি CC by-nc-sa 3.0 এর অধীনে প্রকাশিত

সর্বশেষ সম্পাদনা করেছেন invarbrass (২৮-০৬-২০১৪ ১১:২৪)

Re: তারিখসহ ইউনিক নম্বর পিএইচপিতে কিভাবে জেনারেট করব?

অয়ন খান লিখেছেন:

প্রতিদিন যদি ৯৯৯৯টির বেশি রেকর্ড তৈরী হওয়ার সম্ভাবনা থাকে তাহলে পূর্বের পোস্টে যেই সমাধানটি দিয়েছি সেটা ব্যবহার করতে পারেন। মনে রাখবেন, এক্ষেত্রে ডেটাবেইজে `id` কলামের লেন্থ অবশ্যই ১৫ – এর বেশি দিতে হবে। তবে আপনি যদি নিশ্চিত থাকেন যে ৯৯৯৯টির বেশি রেকর্ড তৈরী হওয়ার সম্ভাবনা নেই তাহলে নিচের সমাধানটি ব্যবহার করতে পারেন।

সম্ভবতঃ উনার ডেইলী ক্লায়েন্ট কাউণ্ট ওই সংখ্যা এক্সীড করবে না। আমাদের ক্লিনিকেও একই টেকনিক ব্যবহার করছি - ২০০০ এর বেশি আইডি কখনোই জেনারেট হয় না। আমার সিস্টেমে আইডি জেনারেট করি এভাবে - A1,A2,A3...B1,B2... Z99

উপস!  surprised একটা ব্যাপার ভুলে গিয়েছিলাম - দিনের শেষে সিকোয়েন্সটা রিসেট করতে হবেঃ

ALTER SEQUENCE sequence_name RESTART WITH 0

mssql-এর এজেণ্টের মাধ্যমে প্রতি রাত ১২:০১ মিনিটে ওই কুয়েরীটা শিডিউল করে রেখেছি। তবে এটাও ফেইল করতে পারে (যদি সার্ভার শাটডাউন থাকে ওই সময়ে)। তাই প্রথমবার ক্লায়েন্ট লগিন করার  পরও দরকার পড়লে রিসেট করে অটোমেটিকালী:
SELECT COUNT(*) FROM some_table WHERE date_field=TODAY() - এটার রিটার্ণ ভ্যালু যদি 0 হয়, সেক্ষেত্রে সিকোয়েন্সটা ফোর্সড রিসেট করি।  cool

Calm... like a bomb.

Re: তারিখসহ ইউনিক নম্বর পিএইচপিতে কিভাবে জেনারেট করব?

ধন্যবাদ। ট্রাই করে দেখি। ডেটাবেজ আছে আপাতত mysql তবে সামনে sql সার্ভারে যাওয়াও হতে পারে। টেস্ট ল্যাবে mysql ব্যবহার করছি। প্রতিদিন ২০০-৩০০ এর মত রেকর্ড তৈরি হতে পারে। এর বেশী না হয়ত।

Re: তারিখসহ ইউনিক নম্বর পিএইচপিতে কিভাবে জেনারেট করব?

ইয়ে মানে mysql এর ডিফল্ট ইনক্রিমেন্ট ইউজাইলে সমস্যা কোথায় hmm

সারিম'এর ওয়েবসাইট

লেখাটি CC by-nc-sa 3.0 এর অধীনে প্রকাশিত

১০

Re: তারিখসহ ইউনিক নম্বর পিএইচপিতে কিভাবে জেনারেট করব?

দক্ষিণের-মাহবুব লিখেছেন:

একই দিনে যেহেতু একাধিক নম্বর জেনারেট হতে পারে, তাই শেষের চারসংখ্যা দ্বারা সেটা ইউনিক করার ইচ্ছা। এবং প্রতিদিন ০০০০ থেকে শুরু হবে।

জ্ঞানী গুণীদের মাঝে আমার হালকা মতামত। হাসাহাসি করবেন না।   tongue

ইউনিক নাম্বার জেনারেশানের কোডটা ইন্টারফেসে না রেখে ডাটাবেস লেভেলে রাখেন। তাহলে একই সেকেন্ডে ২ দুইজন না, ২০০০ জন ক্লিক মারলেও ইউনিক নাম্বার পাবে। SQL Server এ Store Procedure বলে একটা ব্যাপার আছে সম্ভবত। আর ইন্টারফেসে রাখতে চাইলে yyyyMMdd-userlogin এই ফরমেটে রাখতে পারেন (যদি login সিস্টেম থাকে)  smile

invarbrass লিখেছেন:

পিএস: 28-06-2014-0001 এর চাইতে 2014-06-28-0001 ফরম্যাটটি (yyyy-mm-dd...) বরং আরো অপ্টিমাইজড

একমত। এই ফরম্যাটের ডাটা দারুনভাবে সর্টিং করা যায়।  smile

১১

Re: তারিখসহ ইউনিক নম্বর পিএইচপিতে কিভাবে জেনারেট করব?

সারিম লিখেছেন:

ইয়ে মানে mysql এর ডিফল্ট ইনক্রিমেন্ট ইউজাইলে সমস্যা কোথায় hmm

কোনো সমস্যা নাই। ইন ফ্যাক্ট, মূল টেবিলে auto-inc-pri-key ব্যবহৃত হবেই।
তবে মাহবুব ভাইয়ের রিকোয়ারমেণ্ট হলো (সম্ভবতঃ এণ্ড-ইউজারের জন্য) ইউনিক আইডি জেনারেট করা যা প্রতিদিন রিসেট হবে।
একই ধরণের রিকোয়ারমেণ্ট আমাদের ক্লিনিকেও ছিলো। স্টাফদের পক্ষে invoice id #964587312 মনে রাখার চাইতে "২৮ তারিখের B22" হ্যাণ্ডল করা অনেক সহজ। মূল টেবিলের প্রাইমারী কী auto-inc দিয়েই জেনারেট হয়, কিন্তু সেই সাথে এণ্ড-ইউজারের জন্য হিউম্যান-রীডেবল আরেকটি সারোগেট আইডি-ও তৈরী করতে হয়।

Calm... like a bomb.

১২

Re: তারিখসহ ইউনিক নম্বর পিএইচপিতে কিভাবে জেনারেট করব?

invarbrass লিখেছেন:

স্টাফদের পক্ষে invoice id #964587312 মনে রাখার চাইতে "২৮ তারিখের B22" হ্যাণ্ডল করা অনেক সহজ

বুঝলাম। আপনার সলুশ্যনটায় মনে হচ্ছে কুয়েরি করার সময় সিকোয়েন্সটা কল করছেন ?
আরেকটা আইডিয়া, ইনসার্ট করার সময় ট্রিগার দিয়েও করা যায়।

CREATE TABLE `invoice` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `date` datetime NOT NULL,
  `patient_name` text NOT NULL,
  `invoice_id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
)
DELIMITER //

CREATE TRIGGER gen_invoice BEFORE INSERT ON invoice
FOR EACH ROW
BEGIN
  DECLARE invoiceNew INT(11);
  SELECT IF(MAX(invoice_id) IS null,1,MAX(invoice_id)+1) INTO invoiceNew FROM invoice WHERE date >= DATE(NOW());
  SET NEW.invoice_id = invoiceNew;
END
//

DELIMITER ;

এরপর ইনসার্ট করার সময় আর invoice_id দিতে হবেনা, অটো অটো তৈরী হবে।

INSERT INTO INVOICE (`patient_name`,`date`) VALUES ("halim", NOW())

ফলাফল,
http://cl.ly/WIDl/Screen%20Shot%202014-06-28%20at%207.10.22%20PM.jpg

সারিম'এর ওয়েবসাইট

লেখাটি CC by-nc-sa 3.0 এর অধীনে প্রকাশিত

১৩ সর্বশেষ সম্পাদনা করেছেন invarbrass (২৮-০৬-২০১৪ ২০:৪৯)

Re: তারিখসহ ইউনিক নম্বর পিএইচপিতে কিভাবে জেনারেট করব?

সারিম লিখেছেন:

বুঝলাম। আপনার সলুশ্যনটায় মনে হচ্ছে কুয়েরি করার সময় সিকোয়েন্সটা কল করছেন ?

না। পুরোটাই একটা stored procedure-এর মধ্যে। INSERT করার আগে কেবল সিকোয়েন্সটা কল করে।
প্রডাকশন ডেটাবেজ থেকে মূল sproc-টা (অনেক সংক্ষেপিত) কপিপেস্ট করে দিলামঃ
table schema:

CREATE TABLE [PROE].[PatientLabOrders] (
    [InvoiceId] BIGINT IDENTITY(1001, 1) NOT FOR REPLICATION NOT NULL,
    [OrderId] VARCHAR(8) NOT NULL,  -- << হিউম্যান রীডেবল আইডি
    [OrderDateTime] SMALLDATETIME NOT NULL DEFAULT (GETDATE()),
    -- ... other columns
    CONSTRAINT [PK_PATIENT_LABORDERS] PRIMARY KEY CLUSTERED ([InvoiceId])
)

stored procedure:

CREATE PROCEDURE [PROE].[SP_CreateNewLabOrder]
  @patientName             VARCHAR(120),
   -- ...other columns
  @newOrderId            BIGINT OUTPUT
  WITH
  EXEC AS CALLER
AS
  BEGIN
    SET  XACT_ABORT ON
    SET  NOCOUNT ON

    BEGIN TRANSACTION
      DECLARE @seqCounter   INT
      SET @seqCounter = NEXT VALUE FOR [LabOrders_Sequence] 

      DECLARE @cutoff   INT
      SET @cutoff     = 75

      DECLARE @letter   CHAR(1)
      DECLARE @num   INT

      SET @letter     = CHAR( ASCII( 'A') + ((@seqCounter / @cutoff) % 26))
      SET @num        = (@seqCounter % @cutoff) + 1

      DECLARE @orderNum   VARCHAR(8)
      SET @orderNum   = RTRIM(@letter + CAST( @num AS CHAR(4)))

      INSERT INTO [PROE].[PatientLabOrders](
          [OrderId],
          [PatientName],
           -- ...other columns
           )
      VALUES (
          @orderNum,
          @patientName,
           -- ...other columns
           )

      SELECT @newOrderId = SCOPE_IDENTITY()
    COMMIT TRANSACTION
  END
GO
সারিম লিখেছেন:

আরেকটা আইডিয়া, ইনসার্ট করার সময় ট্রিগার দিয়েও করা যায়।

প্রথম ভার্সনটা COUNT(*) [বা MAX(column)] দিয়ে করেছিলাম। কিন্তু এই টেকনিক পছন্দ হচ্ছিলো না। আইডি জেনারেট করার জন্য অসংখ্যবার টেবিলের রো কাউণ্ট করা ওভারকিল। সিকোয়েন্স বরং অনেক এলিগেন্ট, এফিশিয়েণ্ট এবং পারফর্ম্যান্ট।
তবে সিকোয়েন্স ব্যবহার করেও বার কয়েক ধরা খেয়েছি।  crying

Calm... like a bomb.

১৪ সর্বশেষ সম্পাদনা করেছেন সাইফুল_বিডি (২৮-০৬-২০১৪ ২১:১৩)

Re: তারিখসহ ইউনিক নম্বর পিএইচপিতে কিভাবে জেনারেট করব?

গুরুদের মাঝে একটু বা হাত ডুকাই।
টেবিলের স্কিমা হবে নিচের মত
id = auto incre.
date = date চাইলে ডেটটাইম ব্যবহার করতে পারেন তাহলে কুয়েরী কিছুটা চেঞ্জ করতে হবে। (WHERE DATE(datetime) = '2009-10-20')
uni = varchar(4)
...........................

নিচের মত কুয়েরি করে ডাটা ইন্সার্ট করুন। ডেট ডেট ফরম্যাটে রাখলে ডাটা খুজতে / সর্ট করতে সহজ হয়। আর ইউনিক আইডি আলাদা রাখলে আইডেন্টিফাই করতে সহজ হয়। পরে ডাটা বেরকরার সময় where date=date and uni=uni দিয়ে কুয়েরি করলে সহজে ডাটা বের করা যাবে।

$query = $db -> prepare("SELECT * FROM uni WHERE date=:date ORDER BY id DESC LIMIT 1");
    $query -> execute(array(':date' => date('Y-m-d')));
    $data = $query -> fetch();
    if($data==false){$uni = 0;}
    else{$uni = (int) $data['uni']+1;}
    $uni = sprintf("%04s", $uni);

    //save uniq id in database

যদি উল্টাপাল্টা বলি তাইলে ক্ষমা চাই  smile

এই ব্যাক্তির সকল লেখা কাল্পনিক , জীবিত অথবা মৃত কারো সাথে মিল পাওয়া গেলে তা সম্পুর্ন কাকতালীয়, যদি লেখা জীবিত অথবা মৃত কারো সাথে মিলে যায় তার দায় এই আইডির মালিক কোনক্রমেই বহন করবেন না। এই ব্যক্তির সকল লেখা পাগলের প্রলাপের ন্যায় এই লেখা কোন প্রকার মতপ্রকাশ অথবা রেফারেন্স হিসাবে ব্যবহার করা যাবে না।

১৫

Re: তারিখসহ ইউনিক নম্বর পিএইচপিতে কিভাবে জেনারেট করব?

সাইফুল_বিডি লিখেছেন:

নিচের মত কুয়েরি করে ডাটা ইন্সার্ট করুন। ডেট ডেট ফরম্যাটে রাখলে ডাটা খুজতে / সর্ট করতে সহজ হয়। আর ইউনিক আইডি আলাদা রাখলে আইডেন্টিফাই করতে সহজ হয়। পরে ডাটা বেরকরার সময় where date=date and uni=uni দিয়ে কুয়েরি করলে সহজে ডাটা বের করা যাবে।

$query = $db -> prepare("SELECT * FROM uni WHERE date=:date ORDER BY id DESC LIMIT 1");
    $query -> execute(array(':date' => date('Y-m-d')));
    $data = $query -> fetch();
    if($data==false){$uni = 0;}
    else{$uni = (int) $data['uni']+1;}
    $uni = sprintf("%04s", $uni);

    //save uniq id in database

এই টেকনিক প্রায়শঃই ফেইল করবে - কারণ একজন ক্লায়েণ্ট $query -> fetch() থেকে "save uniq id in database" পর্যায়ে যাবার ফাঁকেই হয়তো আরেক (বা একাধিক) ক্লায়েণ্ট দু-চার খানা রেকর্ড ঢুকিয়ে দেবে। hehe

এ কারণেই ভিবিকোডার ভাই এ ধরণের লজিক ডেটাবেইজ এঞ্জিনের ঘাড়ে ফেলতে উপদেশ দিয়েছিলেন।

Calm... like a bomb.

১৬

Re: তারিখসহ ইউনিক নম্বর পিএইচপিতে কিভাবে জেনারেট করব?

invarbrass লিখেছেন:

না। পুরোটাই একটা stored procedure-এর মধ্যে। INSERT করার আগে কেবল সিকোয়েন্সটা কল করে।

সিনট্যাক্স বুঝিনাই তো tongue

invarbrass লিখেছেন:

আইডি জেনারেট করার জন্য অসংখ্যবার টেবিলের রো কাউণ্ট করা ওভারকিল। সিকোয়েন্স বরং অনেক এলিগেন্ট, এফিশিয়েণ্ট এবং পারফর্ম্যান্ট।

হু। আরেকটা টেবিল করা যায় অবশ্য wink সেটায় শুধু date, lastInvoiceId থাকবে tongue still, ডাটাবেজ সার্ভারের নেটিভ সিকোয়েন্সই ভালো হবে।

@সাইফুল_বিডি ডাটাবেজ ইনজিন ইনসার্টের সময় টেবিল/রো লক করে, তাই ডাটাবেজ লেভেল থেকে করলে ডুপ্লিকেট এন্ট্রি পড়বেনা।

সারিম'এর ওয়েবসাইট

লেখাটি CC by-nc-sa 3.0 এর অধীনে প্রকাশিত