MySQL FIND_IN_SET() ব্যাখ্যা: কমা-সেপারেটেড মানগুলো নিরাপদে অনুসন্ধান (উদাহরণসহ)

目次

১. পরিচিতি: FIND_IN_SET প্রয়োজনীয় হয় এমন সাধারণ পরিস্থিতি

MySQL-এ ডেটা নিয়ে কাজ করার সময়, আপনি এমন কিছু কেসের মুখোমুখি হতে পারেন যেখানে “একটি কলামে একাধিক মান কমা দিয়ে আলাদা করে সংরক্ষিত থাকে।” উদাহরণস্বরূপ, ব্যবহারকারী-নির্বাচিত ট্যাগ, ক্যাটাগরি তথ্য, বা কনফিগারেশন ফ্ল্যাগগুলি php,python,sql এর মতো একটি একক স্ট্রিং হিসেবে সংরক্ষিত থাকতে পারে।

এই ধরনের স্ট্রাকচার ডেটাবেস নরমালাইজেশনের দৃষ্টিকোণ থেকে সুপারিশ করা হয় না। তবে, বিদ্যমান সিস্টেম ডিজাইনের উপর নির্ভর করে বা নমনীয় ডেটা ইনপুটকে অগ্রাধিকার দিলে, আপনাকে বাস্তবে এই ফরম্যাটটি ব্যবহার করতে হতে পারে।

ট্যাগ সার্চ জটিল হলে একটি জীবনরক্ষক

উদাহরণস্বরূপ, ধরুন আপনি চেক করতে চান যে একজন ব্যবহারকারীর “python” ট্যাগ আছে কি না। সাধারণ = অপারেটর বা LIKE অপারেটর দিয়ে, আংশিক মিল এবং চারপাশের অক্ষরগুলির কারণে নির্ভুলতার সীমাবদ্ধতা রয়েছে, যা ভুল ফলাফলের দিকে নিয়ে যেতে পারে।

এখানেই FIND_IN_SET() ফাঙ্কশন কাজে লাগে।

FIND_IN_SET() হলো একটি MySQL ফাঙ্কশন যা কমা-দিয়ে আলাদা করা স্ট্রিং-এর মধ্যে একটি নির্দিষ্ট স্ট্রিং-এর অবস্থান (ইনডেক্স) নির্ধারণ করে। যদি পাওয়া যায়, তাহলে এটি ইনডেক্স (১ থেকে শুরু) ফেরত দেয়। যদি না পাওয়া যায়, তাহলে 0 ফেরত দেয়। এই আচরণের সাথে, আপনি ট্যাগ, ক্যাটাগরি বা সেটিংস অন্তর্ভুক্ত কি না তা নির্ভুলভাবে এবং নমনীয়ভাবে নির্ধারণ করতে পারেন।

সাধারণ ব্যবহারের ক্ষেত্র

FIND_IN_SET যেখানে উজ্জ্বল হয় তা সাধারণ দৃশ্যপটগুলি অন্তর্ভুক্ত:

  • যখন আপনি একটি ফিল্ডে সংরক্ষিত কমা-দিয়ে আলাদা “ট্যাগ” বা “ক্যাটাগরি” থেকে একটি নির্দিষ্ট মান বের করতে চান
  • যখন আপনি অ্যাডমিন স্ক্রিনে ইনপুট করা CSV-স্টাইল মানগুলিকে সার্চ শর্ত হিসেবে ব্যবহার করতে চান
  • যখন আপনি WordPress-এর মতো একটি CMS-এ মেটা তথ্যের বিরুদ্ধে নমনীয় ফিল্টারিং করতে চান
  • যখন আপনি একটি বিদ্যমান টেবিল প্রসেস করতে চান যেখানে মাল্টি-সিলেক্ট মানগুলি একটি কলামে সংরক্ষিত, স্কিমা পরিবর্তন না করে

একই সাথে, FIND_IN_SET-এর অপব্যবহার পারফরম্যান্স হ্রাস বা ভুল পজিটিভ/ভুল মিল সৃষ্টি করতে পারে। এই নিবন্ধে, আমরা বেসিক সিনট্যাক্স থেকে শুরু করে বাস্তব দৃশ্যপট ব্যবহার করে প্র্যাকটিক্যাল উদাহরণ, ফাঁদ এবং ভালো বিকল্পগুলি ব্যাখ্যা করব।

২. FIND_IN_SET ফাঙ্কশন কী? (বেসিক সিনট্যাক্স এবং রিটার্ন মান)

MySQL-এর FIND_IN_SET() ফাঙ্কশন হলো একটি ফাঙ্কশন যা কমা-দিয়ে আলাদা স্ট্রিং-এর মধ্যে একটি নির্দিষ্ট মানের অবস্থান চেক করার জন্য ব্যবহৃত হয়। এটি বিশেষভাবে দরকারী যখন একাধিক মান একটি একক ফিল্ডে একসাথে সংরক্ষিত থাকে।

এই ফাঙ্কশনটি MySQL-এর জন্য নির্দিষ্ট এবং অন্যান্য ডেটাবেসে (যেমন PostgreSQL বা SQLite) ডিফল্টভাবে উপলব্ধ নয়, তাই এটিকে MySQL-নির্দিষ্ট ফিচার হিসেবে বিবেচনা করা যায়।

বেসিক সিনট্যাক্স

FIND_IN_SET(search_value, comma_separated_string)
  • search_value : স্ট্রিং যা আপনি খুঁজতে চান
  • comma_separated_string : সার্চ করার জন্য কমা-দিয়ে আলাদা লিস্ট

উদাহরণ

নিম্নলিখিত SQL বিবেচনা করুন:

SELECT FIND_IN_SET('python', 'php,python,sql');

এই ক্ষেত্রে, 'python' দ্বিতীয় আইটেম, তাই রিটার্ন মান 2

অন্যদিকে, যদি নির্দিষ্ট মান লিস্টে না থাকে, তাহলে 0 ফেরত দেওয়া হয়:

SELECT FIND_IN_SET('ruby', 'php,python,sql');
-- Result: 0

এছাড়া, যদি কোনো আর্গুমেন্ট NULL হয়, তাহলে রিটার্ন মানও NULL হয়।

SELECT FIND_IN_SET(NULL, 'php,python,sql');
-- Result: NULL

রিটার্ন মানের নিয়ম

ConditionReturn Value
The value exists in the list1 or greater (its position)
The value does not exist in the list0
Either argument is NULLNULL

রিটার্ন মানকে কার্যকরভাবে ব্যবহার করে, আপনি FIND_IN_SET-কে শুধু সার্চিং-এর জন্য নয়, বরং “একটি মান যে অবস্থানে আসে তা চেক করা” এর মতো ক্ষেত্রেও প্রয়োগ করতে পারেন।

গুরুত্বপূর্ণ নোট: ০ অর্থ “পাওয়া যায়নি”

যখন রিটার্ন মান 0 হয়, তখন এটি “লিস্টে পাওয়া যায়নি” নির্দেশ করে। MySQL-এ, 0 কে FALSE হিসেবে বিবেচনা করা হয়, তাই WHERE ক্লজে এটি সরাসরি ব্যবহার করলে আচরণ না বুঝলে বিভ্রান্তি সৃষ্টি হতে পারে।

পরবর্তী সেকশনে, আমরা FIND_IN_SET-কে বাস্তব টেবিল ডেটার বিরুদ্ধে ব্যবহারের বেসিক কোয়েরি উদাহরণ দেখাব।

৩. প্র্যাকটিক্যাল উদাহরণ ১: বেসিক ব্যবহার (একটি সিম্পল SELECT কোয়েরি)

FIND_IN_SET() ফাংশনটি ঠিক তার নামের মতোই কাজ করে—“সেটের মধ্যে খুঁজে বের করা।” তবে বাস্তব টেবিল ডেটার উপর প্রয়োগ করার সময় আপনি কীভাবে লিখবেন?
এখানে, আমরা একটি মৌলিক SELECT স্টেটমেন্ট ব্যবহার করে সবচেয়ে সহজ ব্যবহার দেখব।

একটি নমুনা টেবিল প্রস্তুত করুন

নিম্নলিখিত টেবিলটি ধরুন:

টেবিলের নাম: user_tags

idnametags
1Tanakaphp,python,sql
2Suzukijava,ruby
3Satopython,c,go

tags কলামটি ব্যবহারকারীদের দ্বারা নিবন্ধিত স্কিল ট্যাগগুলোকে কমা-সেপারেটেড স্ট্রিং হিসেবে সংরক্ষণ করে।

উদাহরণ: “python” ট্যাগ থাকা ব্যবহারকারীদের অনুসন্ধান

শুধুমাত্র “python” ট্যাগ থাকা ব্যবহারকারীদের বের করতে, নিম্নলিখিত SQL লিখুন:

SELECT * FROM user_tags
WHERE FIND_IN_SET('python', tags);

ফলাফল:

idnametags
1Tanakaphp,python,sql
3Satopython,c,go

দেখানো হয়েছে, শুধুমাত্র সেই রেকর্ডগুলো যেখানে tags কলামে “python” অন্তর্ভুক্ত আছে সেগুলোই ফেরত আসে।

সঠিক স্ট্রিং ম্যাচিংই মূল বিষয়

FIND_IN_SET() সঠিক স্ট্রিং সমতা এর উপর ভিত্তি করে ম্যাচ করে। এর মানে এটি “py” বা “pyth” এর মতো আংশিক স্ট্রিং ম্যাচ করবে না। যদি আপনাকে আংশিক ম্যাচিং দরকার হয়, তবে আপনি LIKE ব্যবহার করবেন, তবে LIKE '%python%' এর মতো কিছু লিখলে অন্য কন্টেন্ট ভুলভাবে ম্যাচ হতে পারে এবং কমা-সেপারেটেড তালিকার জন্য এটি ঝুঁকিপূর্ণ। তাই, কমা-সেপারেটেড তালিকার জন্য সাধারণত FIND_IN_SET বেশি উপযুক্ত

উদাহরণ: SQL-এ ভেরিয়েবল ব্যবহার করে অনুসন্ধান

যদি আপনি অনুসন্ধান মানটি ডায়নামিকভাবে পরিবর্তন করতে চান, তবে আপনি একটি ভেরিয়েবল ব্যবহার করতে পারেন:

SET @skill = 'python';

SELECT * FROM user_tags
WHERE FIND_IN_SET(@skill, tags);

এই প্যাটার্নটি অ্যাপ্লিকেশন বা স্টোরড প্রোসিডিউরের সাথে ইন্টিগ্রেট করার সময়ও উপকারী।

৪. ব্যবহারিক উদাহরণ ২: ডায়নামিক অনুসন্ধান সমর্থন (ভেরিয়েবল এবং ফর্ম ইন্টিগ্রেশন)

বাস্তব ওয়েব অ্যাপ্লিকেশন এবং ব্যবসায়িক সিস্টেমে, আপনাকে প্রায়ই SQL-এ ডায়নামিকভাবে অনুসন্ধান শর্ত তৈরি করতে হয়।
উদাহরণস্বরূপ, আপনি ফর্মে ব্যবহারকারীরা যে মানগুলো নির্বাচন করে সেগুলো ব্যবহার করে অথবা সিস্টেম স্বয়ংক্রিয়ভাবে তৈরি করা মানগুলো FIND_IN_SET() ব্যবহার করে অনুসন্ধান করতে চাইতে পারেন।

এখানে ভেরিয়েবল এবং ব্যাকএন্ড ইন্টিগ্রেশনকে ধরে নেওয়া কিছু ব্যবহারিক প্যাটার্ন দেওয়া হল।

SQL ভেরিয়েবল ব্যবহার করে ডায়নামিক অনুসন্ধান

যদি আপনি MySQL সেশন ভেরিয়েবল (@variable_name) ব্যবহার করেন, তবে আপনি শীর্ষে একটি অনুসন্ধান মান নির্ধারণ করে তা একাধিক কুয়েরিতে পুনরায় ব্যবহার করতে পারেন:

-- Store the tag you want to search for in a variable
SET @target_tag = 'python';

-- Dynamic search with FIND_IN_SET
SELECT * FROM user_tags
WHERE FIND_IN_SET(@target_tag, tags);

এটি অনুসন্ধান মানটি সহজে পরিবর্তন করতে সহায়তা করে এবং স্টোরড প্রোসিডিউর বা ব্যাচ প্রসেসিং-এ ভাল কাজ করে।

অ্যাপ্লিকেশন ইন্টিগ্রেশন: PHP উদাহরণ

উদাহরণস্বরূপ, যদি আপনি ওয়েব ফর্ম ইনপুটের ভিত্তিতে PHP ব্যবহার করে SQL চালান, তবে আপনি নিচের মতো কোড লিখতে পারেন:

<?php
$tag = $_GET['tag']; // Example: form input "python"

// Build SQL (a prepared statement is recommended)
$sql = "SELECT * FROM user_tags WHERE FIND_IN_SET(?, tags)";

$stmt = $pdo->prepare($sql);
$stmt->execute([$tag]);
$results = $stmt->fetchAll();
?>

প্রিপেয়ার্ড স্টেটমেন্টের সাথে মিলিয়ে, এটি SQL ইনজেকশন থেকে দৃঢ় সুরক্ষা প্রদান করে।

WordPress ব্যবহারিক উদাহরণ: কাস্টম ফিল্ডে ট্যাগ অনুসন্ধান

WordPress-এ, আপনি meta_query ব্যবহার করে কাস্টম ফিল্ড অনুসন্ধান করতে পারেন, তবে যদি আপনি FIND_IN_SET অন্তর্ভুক্ত করতে চান, সাধারণত আপনাকে সরাসরি SQL ব্যবহার করতে হবে, যেমন:

উদাহরণ: যখন কাস্টম ফিল্ড _user_tags তে "php,python,sql" সংরক্ষিত থাকে

global $wpdb;
$tag = 'python';

$sql = $wpdb->prepare(
  "SELECT * FROM {$wpdb->prefix}postmeta WHERE meta_key = %s AND FIND_IN_SET(%s, meta_value)",
  '_user_tags', $tag
);
$results = $wpdb->get_results($sql);

এই পদ্ধতি এমন নমনীয় অনুসন্ধানকে সম্ভব করে যা WordPress-এর স্ট্যান্ডার্ড ফিচারগুলো সামলাতে পারে না।

গুরুত্বপূর্ণ: হোয়াইটস্পেস এবং ফুল-উইডথ কমার দিকে নজর দিন

FIND_IN_SET ব্যবহার করার সময়, কমা-সেপারেটেড স্ট্রিংয়ে অতিরিক্ত হোয়াইটস্পেস বা ফুল-উইডথ ক্যারেক্টার থাকলে ম্যাচ হতে পারে না
সুতরাং, নিম্নলিখিত প্রিপ্রসেসিং করা সুপারিশ করা হয়:

  • TRIM() ফাংশন ব্যবহার করে হোয়াইটস্পেস সরান
  • কমার ফরম্যাট স্বাভাবিক করুন (ফুল-উইডথ → হাফ-উইডথ)
  • অ্যাপ্লিকেশন সাইডে ইনপুট ভ্যালিডেট করুন

৫. FIND_IN_SET ব্যবহার করে উন্নত কৌশল (GROUP_CONCAT, সাবকোয়েরি, JOIN)

FIND_IN_SET ফাংশনটি শুধুমাত্র একক-ফিল্ড অনুসন্ধানের চেয়ে বেশি কিছু পরিচালনা করতে পারে। এটি অন্যান্য SQL ফাংশন এবং সাবকোয়েরি এর সাথে সংযুক্ত করে, আপনি আরও নমনীয় এবং জটিল অনুসন্ধান লজিক তৈরি করতে পারেন। এই বিভাগে তিনটি সাধারণ উন্নত প্যাটার্ন পরিচয় করিয়ে দেওয়া হয়েছে।

GROUP_CONCAT এর সাথে সংযুক্ত করা

প্রথমটি হল GROUP_CONCAT() এর সাথে সংযুক্তি, যা একাধিক সারিকে একটি একক কমা-বিচ্ছিন্ন স্ট্রিং হিসেবে বিবেচনা করতে পারে। এটি তখন উপকারী যখন আপনি একটি টেবিল থেকে ট্যাগের তালিকা তৈরি করে তা অন্য টেবিল অনুসন্ধানের শর্ত হিসেবে ব্যবহার করতে চান।

উদাহরণ: user_tags এর tags কলামের মানকে master_tags থেকে প্রাপ্ত ট্যাগ তালিকার সঙ্গে তুলনা করুন

SELECT *
FROM user_tags
WHERE FIND_IN_SET('python', (
  SELECT GROUP_CONCAT(tag_name)
  FROM master_tags
));

এই কুয়েরিতে, master_tags এর ট্যাগ তালিকাকে একটি কমা-বিচ্ছিন্ন স্ট্রিংয়ে রূপান্তর করা হয়, এবং FIND_IN_SET() তা বিরুদ্ধে মিল আছে কিনা পরীক্ষা করে।

মনে রাখবেন, GROUP_CONCAT দ্বারা উৎপন্ন স্ট্রিংয়ের দৈর্ঘ্যের একটি সীমা আছে (ডিফল্ট ১০২৪ অক্ষর)। যদি আপনার অনেক মান থাকে, তবে group_concat_max_len সেটিংটি পরীক্ষা করুন।

সাবকোয়েরি ব্যবহার করে ডায়নামিকভাবে মান সংগ্রহ করা

পরবর্তীটি একটি প্যাটার্ন যেখানে আপনি সাবকোয়েরি দিয়ে অনুসন্ধান লক্ষ্য মানটি ডায়নামিকভাবে সংগ্রহ করেন এবং তা FIND_IN_SET-এ পাঠান।

উদাহরণ: একটি ম্যানেজমেন্ট টেবিল থেকে অনুসন্ধান শর্ত সংগ্রহ করুন এবং সেই অনুযায়ী ডেটা ফিল্টার করুন

SELECT *
FROM user_tags
WHERE FIND_IN_SET(
  'python',
  (SELECT setting_value FROM search_conditions WHERE id = 1)
);

এখানে, অনুসন্ধান শর্তটি একটি ম্যানেজমেন্ট টেবিলে সংরক্ষিত থাকে, যা আপনাকে সিস্টেম সেটিংস আপডেট করে সহজেই অনুসন্ধান আচরণ পরিবর্তন করতে দেয়। এটি কনফিগারযোগ্য অ্যাডমিন স্ক্রিন এবং ড্যাশবোর্ড-স্টাইল অ্যাপের জন্য সুবিধাজনক হতে পারে।

JOIN এর তুলনায়: স্বাভাবিকীকৃত স্কিমায় JOIN বেশি কার্যকর

FIND_IN_SET সুবিধাজনক, তবে যদি আপনার ডাটাবেস ডিজাইন সঠিকভাবে স্বাভাবিকীকৃত হয়, তবে JOIN দিয়ে অনুসন্ধান করা বেশি কার্যকর এবং নিরাপদ

উদাহরণস্বরূপ, একটি many-to-many সম্পর্ক একটি জংশন টেবিল ব্যবহার করে, আপনি JOIN দিয়ে পরিষ্কারভাবে অনুসন্ধান বাস্তবায়ন করতে পারেন:

উদাহরণ কাঠামো:

  • users টেবিল
  • tags টেবিল
  • user_tag_relation টেবিল (জংশন টেবিল, যেখানে user_id এবং tag_id রাখা হয়)
    SELECT users.*
    FROM users
    JOIN user_tag_relation ON users.id = user_tag_relation.user_id
    JOIN tags ON user_tag_relation.tag_id = tags.id
    WHERE tags.name = 'python';
    

এই ডিজাইন অনুসন্ধান পারফরম্যান্স উন্নত করে এবং ভবিষ্যতের ডেটা সম্প্রসারণকে সহজ করে।

কোন পদ্ধতি আপনি বেছে নেবেন?

ApproachBest For
FIND_IN_SET + GROUP_CONCATWhen you want to dynamically control a filter list
FIND_IN_SET + SubqueryWhen you want to pull conditions from a management table
JOINNormalized schemas, large data volumes, performance-focused systems

আপনি দেখতে পাচ্ছেন, অন্যান্য SQL বৈশিষ্ট্যের সঙ্গে সংযুক্ত হলে FIND_IN_SET() অনেক বেশি নমনীয় হয়ে ওঠে। তবে, আপনার স্কিমা এবং লক্ষ্য অনুযায়ী, JOIN বা অন্যান্য পদ্ধতি বেশি উপযুক্ত হতে পারে, তাই ডিজাইন এবং উদ্দেশ্যের ভিত্তিতে নির্বাচন করা গুরুত্বপূর্ণ।

৬. FIND_IN_SET এর দুর্বলতা এবং সতর্কতা (পারফরম্যান্স এবং ডিজাইন)

FIND_IN_SET একটি সুবিধাজনক ফাংশন যা কমা-বিচ্ছিন্ন স্ট্রিংয়ের বিরুদ্ধে নমনীয় অনুসন্ধান সক্ষম করে, তবে আপনাকে এটি অযত্নে ব্যবহার করা থেকে বিরত থাকতে হবে। এই বিভাগে, আমরা পারফরম্যান্স এবং ডাটাবেস ডিজাইন ঝুঁকি সম্পর্কিত সাধারণ বাস্তব সমস্যাগুলি ব্যাখ্যা করব।

সূচক (ইনডেক্স) ব্যবহার না হওয়ার কারণে দুর্বল পারফরম্যান্স

FIND_IN_SET এর সবচেয়ে বড় অসুবিধা হল এটি লক্ষ্য কলামের উপর ইনডেক্স ব্যবহারের বাধা দেয়

উদাহরণস্বরূপ, নিম্নলিখিত কুয়েরিটি বিবেচনা করুন:

SELECT * FROM user_tags
WHERE FIND_IN_SET('python', tags);

যদিও tags কলামটি ইনডেক্সড থাকে, FIND_IN_SET ব্যবহার করলে একটি পূর্ণ টেবিল স্ক্যান বাধ্য হয়, যার অর্থ MySQL প্রতিবার প্রতিটি সারি পড়ে এবং স্ট্রিং পার্স করে।

ফলস্বরূপ, বড় ডেটাসেটের (হাজার থেকে দশ হাজারের বেশি সারি) ক্ষেত্রে, অনুসন্ধানের গতি নাটকীয়ভাবে হ্রাস পেতে পারে।

প্রস্তাবিত সমাধানসমূহ:

  • উপযুক্ত হলে জংশন টেবিল ব্যবহার করে স্বাভাবিকীকরণ বিবেচনা করুন
  • যদি FIND_IN_SET ব্যবহার করতে হয়, প্রথমে প্রার্থীদের সীমিত করুন ( LIMIT ব্যবহার করুন বা অন্যান্য WHERE শর্তের সঙ্গে সংযুক্ত করুন)

এটি অ-স্বাভাবিকীকৃত কাঠামোকে উৎসাহিত করে

একটি কলামে কমা-বিচ্ছিন্ন মান সংরক্ষণ করা ডাটাবেস স্বাভাবিকীকরণ নীতিগুলোর লঙ্ঘন করে।

উদাহরণস্বরূপ, স্ট্রিং "php,python,sql" সুবিধাজনক দেখাতে পারে, তবে এটি নিম্নলিখিত সমস্যার সৃষ্টি করে:

  • প্রতিটি মানের জন্য সংগ্রহ ও পরিসংখ্যানিক প্রক্রিয়াকরণ কঠিন
  • একটিমাত্র মানকে আপডেট বা মুছে ফেলা কঠিন
  • ডুপ্লিকেট এবং টাইপো সহজে প্রবেশ করতে পারে (যেমন, “Python” বনাম “python”)

দীর্ঘমেয়াদে, এটি প্রায়ই পাঠযোগ্যতা, রক্ষণাবেক্ষণযোগ্যতা এবং স্কেলযোগ্যতা এর ক্ষেত্রে একটি বড় অসুবিধা হয়ে দাঁড়ায়, বিশেষ করে দলগত উন্নয়ন বা স্কেলযোগ্য সেবায়।

অ-কমা অক্ষর বা হোয়াইটস্পেসের কারণে অনুসন্ধান ব্যর্থতা

FIND_IN_SET খুব সংবেদনশীল। যদি ডেটায় নিম্নলিখিত সমস্যাগুলি থাকে, তবে মিল পাওয়া যাবে না:

  • মানের চারপাশে হোয়াইটস্পেস (স্পেস, ট্যাব, নিউলাইন)
  • ফুল‑উইডথ কমা (、)
  • অপ্রত্যাশিত উদ্ধৃতি চিহ্ন (ডাবল কোট বা সিঙ্গেল কোট)

উদাহরণ:

FIND_IN_SET('python', 'php, python ,sql')
-- => No match (because it becomes " python " with spaces)

প্রতিকার:

  • TRIM() ব্যবহার করে ইনসার্টের সময় হোয়াইটস্পেস সরান
  • REPLACE(tags, ' ', '') দিয়ে ইনপুট প্রি‑প্রসেস করুন
  • ফ্রন্টএন্ডে ইনপুট সীমাবদ্ধ করুন (অপ্রয়োজনীয় স্পেস/চিহ্ন সরান)

অস্থায়ী সমাধান হিসেবে ভাল, তবে স্থায়ী ব্যবহারের জন্য আদর্শ নয়

FIND_IN_SET একটি অস্থায়ী সমাধান হিসেবে খুবই উপযোগী, যা একটি বিদ্যমান নন‑নরমালাইজড টেবিলকে স্বল্পমেয়াদে ব্যবহারযোগ্য রাখে।
তবে, নতুনভাবে ডিজাইন করা সিস্টেম বা দীর্ঘমেয়াদে রক্ষণাবেক্ষণ ও সম্প্রসারণের প্রত্যাশা করা সিস্টেমের জন্য, সম্ভব হলে এটি এড়িয়ে চলা উচিত—অথবা অন্তত ভবিষ্যতে নরমালাইজড ডিজাইনে রূপান্তরের পরিকল্পনা থাকা দরকার।

৭. সাধারণ ভুল ধারণা এবং ব্যর্থতার কেস (LIKE থেকে পার্থক্য / সংখ্যার হ্যান্ডলিং)

FIND_IN_SET সহজ দেখায়, তবে যদি আপনি এটি সঠিকভাবে ব্যবহার না করেন, তবে অপ্রত্যাশিত ফলাফল পেতে পারেন।
এই অংশে, আমরা সাধারণ বাস্তব‑জগতের ভুল ধারণা এবং ভুলগুলোকে কভার করব, পাশাপাশি ব্যবহারিক সমাধানও প্রদান করব।

ভুল ১: LIKE এবং FIND_IN_SET এর পার্থক্য না বোঝা

সবচেয়ে সাধারণ ভুল হল LIKE এবং FIND_IN_SET() এর পার্থক্য না বোঝা, যা ভুল অনুসন্ধান শর্ত তৈরি করে।

-- Common incorrect usage
SELECT * FROM user_tags WHERE tags LIKE '%python%';

এই কুয়েরি প্রথমে সঠিক দেখাতে পারে, তবে এটি যেকোনো ডেটা মিলে যায় যা আংশিকভাবে python সাবস্ট্রিং ধারণ করে।

উদাহরণস্বরূপ, এটি "cpython", "pythonista" অথবা "java,pythonic" এর সাথে মিলে যেতে পারে, যা আপনি সম্ভবত চান না।
যদি আপনি php,python,sql এর মতো কমা‑বিচ্ছিন্ন তালিকায় “python” কে একটি স্বতন্ত্র আইটেম হিসেবে মেলাতে চান, তবে আংশিক‑ম্যাচ LIKE এর মিথ্যা পজিটিভের ঝুঁকি উচ্চ।

যদি আপনাকে নিশ্চিত করতে হয় যে “python” স্বতন্ত্র মান হিসেবে আছে, তবে FIND_IN_SET() সঠিক টুল

-- Correct usage
SELECT * FROM user_tags WHERE FIND_IN_SET('python', tags);

ভুল ২: সংখ্যামূলক মানে FIND_IN_SET ব্যবহার করা এবং বিভ্রান্ত হওয়া

FIND_IN_SET ধরে নেয় উভয় আর্গুমেন্টই স্ট্রিং হিসেবে বিবেচিত হয়

এমন ডেটা থাকলে, ডেভেলপাররা কখনো কখনো আচরণটি ভুলভাবে অনুমান করে:

-- tags column contains: 1,2,10,20
SELECT * FROM user_tags WHERE FIND_IN_SET(1, tags);

কেউ হয়তো ধরে নিতে পারে যে ১ মানে ১০‑ও মিলে যাবে, তবে বাস্তবে, FIND_IN_SET(1, '1,2,10,20') শুধুমাত্র অবস্থান ১‑এ থাকা “১” উপাদানের সাথে মিলে।

কারণ FIND_SET মানগুলোকে ভাগ করে এবং সঠিক সমতা পরীক্ষা করে, হল ১০ বা ২১ থেকে ভিন্ন।

তবুও, ডেভেলপাররা এই আচরণটি ভুলভাবে বুঝে “১” “১০”‑এ মিলে যাবে বলে ধারণা করতে পারে।

প্রস্তাবনা: সর্বদা মানগুলোকে স্পষ্টভাবে স্ট্রিং হিসেবে বিবেচনা করুন, যাতে দ্ব্যর্থতা ও বিভ্রান্তি এড়ানো যায়।

ভুল ৩: হোয়াইটস্পেস, ফুল‑উইডথ কমা, অথবা নিউলাইন মিল পাওয়া বাধা দেয়

FIND_IN_SET খুব সংবেদনশীল। যদি ডেটায় নিম্নলিখিত সমস্যাগুলি থাকে, তবে মিল পাওয়া যাবে না:

  • মানের চারপাশে হোয়াইটস্পেস (স্পেস, ট্যাব, নিউলাইন)
  • ফুল‑উইডথ কমা (、)
  • অপ্রত্যাশিত উদ্ধৃতি চিহ্ন (ডাবল কোট বা সিঙ্গেল কোট)

উদাহরণ:

FIND_IN_SET('python', 'php, python ,sql')
-- => No match (because it becomes " python " with spaces)

প্রতিকার:

  • ইনসার্টের সময় whitespace সরাতে TRIM() ব্যবহার করুন
  • ইনপুটকে REPLACE(tags, ' ', '') দিয়ে প্রি-প্রসেস করুন
  • ফ্রন্টএন্ডে ইনপুট সীমাবদ্ধ করুন (অপ্রয়োজনীয় স্পেস/সিম্বল সরিয়ে দিন)

সারাংশ: FIND_IN_SET নিরাপদে ব্যবহার করার মূল বিষয়গুলো

Common PitfallFix
Confusing it with LIKE and getting false positivesUse FIND_IN_SET when exact value matching is required
Unexpected behavior with numeric valuesTreat numbers as strings and compare explicitly
Whitespace/full-width characters break matchingNormalize and preprocess data consistently

যদি আপনি FIND_IN_SET ব্যবহার করেন এবং এই আচরণগুলো না বুঝে থাকেন, তাহলে আপনি ভাবতে পারেন “সার্চ কাজ করছে,” কিন্তু বাস্তবে প্রত্যাশিত রেকর্ডগুলো বের হচ্ছে না, যা গুরুতর বাগের কারণ হতে পারে।

পরবর্তী সেকশনে, আমরা “বিকল্প পদ্ধতি” নিয়ে আলোচনা করব যা এই সমস্যাগুলো মূল থেকে সমাধান করে।

8. FIND_IN_SET এর বিকল্প (সেরা চর্চা)

FIND_IN_SET কমা-সেপারেটেড স্ট্রিংয়ের উপর নমনীয় সার্চের সুযোগ দেয়, তবে এটি বৃহৎ ডেটাসেট বা স্কেলেবিলিটি প্রয়োজনীয় সিস্টেমের জন্য উপযুক্ত নয়
এই সেকশনে, আমরা প্রস্তাবিত বিকল্প (সেরা চর্চা) উপস্থাপন করব যা FIND_IN_SET ব্যবহার এড়িয়ে চলে।

স্বাভাবিকীকৃত টেবিল ডিজাইনে স্যুইচ করুন

সবচেয়ে সুপারিশকৃত পদ্ধতি হল ডেটাবেসকে স্বাভাবিকীকরণ করা এবং মানগুলোকে পৃথক রো হিসেবে পরিচালনা করা
একটি কমা-সেপারেটেড কলামে একাধিক মান সংরক্ষণ করার পরিবর্তে, একটি জংশন টেবিল (রিলেশন টেবিল) ব্যবহার করুন যাতে many-to-many সম্পর্ক স্পষ্টভাবে উপস্থাপিত হয়।

উদাহরণ: ব্যবহারকারী এবং ট্যাগের মধ্যে সম্পর্ক

প্রচলিত (ডিনরমালাইজড) কাঠামো:

user_idtags
1php,python,sql

স্বাভাবিকীকৃত কাঠামো:

users টেবিল

idname
1Tanaka

tags টেবিল

idname
1php
2python
3sql

user_tag_relation (জংশন টেবিল)

user_idtag_id
11
12
13

এই কাঠামো দিয়ে, আপনি FIND_IN_SET না ব্যবহার করে JOIN ব্যবহার করে নমনীয়ভাবে সার্চ করতে পারেন:

SELECT users.*
FROM users
JOIN user_tag_relation ON users.id = user_tag_relation.user_id
JOIN tags ON user_tag_relation.tag_id = tags.id
WHERE tags.name = 'python';

এই পদ্ধতি ইন্ডেক্সগুলোকে কার্যকরভাবে কাজ করতে দেয় এবং পারফরম্যান্স ও স্কেলেবিলিটি উল্লেখযোগ্যভাবে উন্নত করে।

JSON টাইপ ব্যবহার করুন (MySQL 5.7+)

MySQL 5.7 এবং তার পরের সংস্করণে, আপনি JSON কলাম ব্যবহার করতে পারেন। কমা-সেপারেটেড স্ট্রিং সংরক্ষণের পরিবর্তে, আপনি মানগুলোকে একটি JSON অ্যারে হিসেবে সংরক্ষণ করতে পারেন এবং JSON ফাংশন ব্যবহার করে সার্চ করতে পারেন।

উদাহরণ:

["php", "python", "sql"]

সার্চ উদাহরণ:

SELECT * FROM user_tags
WHERE JSON_CONTAINS(tags_json, '"python"');

এটি ট্যাগগুলোকে গঠনযুক্ত রাখে, whitespace দ্বারা সৃষ্ট ভুল ম্যাচ প্রতিরোধ করে, এবং ডেটা গুণগত সমস্যাগুলো কমায়।
অতিরিক্তভাবে, JSON-নির্দিষ্ট ইনডেক্সিং (MySQL 8.0+) পারফরম্যান্স আরও বাড়াতে পারে।

অ্যাপ্লিকেশন সাইডে স্প্লিট এবং রিবিল্ড করুন

যদি আপনি ডিজাইন পরিবর্তন করতে না পারেন এবং বর্তমান কাঠামো বজায় রাখতে চান, তবুও আপনি অ্যাপ্লিকেশন সাইডে অ্যারেতে ভাগ করে এবং লুপ করে, অথবা উপযুক্ত হলে SQL IN ক্লজে রূপান্তর করে একই ধরনের আচরণ বাস্তবায়ন করতে পারেন।

উদাহরণ (PHP):

$tags = explode(',', $record['tags']);
if (in_array('python', $tags)) {
    // Execute processing
}

এটি ডেটাবেস-সাইডের কাজের চাপ কমায় এবং নিরাপদ প্রক্রিয়াকরণকে সম্ভব করে।

FIND_IN_SET কে “এক্সসেপশন” হিসেবে ব্যবহার করুন, ডিফল্ট নয়

যথা বারবার উল্লেখ করা হয়েছে, FIND_IN_SET একটি অস্থায়ী ওয়ার্কঅ্যারাউন্ড হিসেবে খুবই উপকারী, যাতে বিদ্যমান ডিনরমালাইজড টেবিলগুলোকে স্বল্পমেয়াদে ব্যবহারযোগ্য রাখা যায়।
তবে, নতুন সিস্টেম বা দীর্ঘমেয়াদে রক্ষণাবেক্ষণ ও সম্প্রসারণের প্রত্যাশা থাকা সিস্টেমের জন্য, সম্ভব হলে এটি ব্যবহার এড়িয়ে চলুন—অথবা অন্তত ভবিষ্যতে স্বাভাবিকীকরণে মাইগ্রেট করার পরিকল্পনা রাখুন।

ApproachBest Fit
Normalization + JOINWhen performance and scalability matter
JSON type + JSON functionsWhen you want flexible structured storage
Application-side processingTemporary handling or read-only use cases
FIND_IN_SETShort-term workaround for legacy DBs where schema changes are difficult

9. FAQ: সাধারণ প্রশ্ন ও উত্তর

FIND_IN_SET ব্যবহার করার সময় বাস্তব কাজ ও শেখার সময় অনেক প্রশ্ন ও বিভ্রান্তি দেখা দেয়।
এখানে, আমরা সাধারণ অনুসন্ধান ইন্টেন্টের সাথে সামঞ্জস্যপূর্ণ Q&A ফরম্যাটে প্রায়শই জিজ্ঞাসিত প্রশ্নগুলো সংগঠিত করেছি।

Q1. কখন FIND_IN_SET ব্যবহার করা সঠিক?

A.
FIND_IN_SET ব্যবহার করা হয় যখন আপনি একটি নির্দিষ্ট মান কমা-সেপারেটেড স্ট্রিংয়ে অন্তর্ভুক্ত আছে কিনা তা পরীক্ষা করতে চান।
এটি নিম্নলিখিত পরিস্থিতিতে উপযুক্ত:

  • যখন ডিজাইনে এক কলামে একাধিক মান সংরক্ষণ করা প্রয়োজন (যেমন, ট্যাগ, পারমিশন, ফ্ল্যাগ)
  • যখন আপনি লেগেসি ডিনরমালাইজড ডেটাবেসকে পরিবর্তন না করে সার্চ করতে চান
  • ছোট থেকে মাঝারি আকারের ডেটাসেটের জন্য যেখানে ব্যবহার সীমিত (অ্যাডমিন টুল, ইন্টারনাল স্ক্রিন)

তবে, এটি মূল উৎপাদন প্রক্রিয়াকরণ বা বৃহৎ-স্কেল ডেটার জন্য উপযুক্ত নয়।

Q2. FIND_IN_SET এবং LIKE এর মধ্যে পার্থক্য কী?

উত্তর:
LIKE '%value%' একটি আংশিক মিল সম্পাদন করে, যার অর্থ এটি সাবস্ট্রিংয়ের আগে বা পরে কী আছে তা নির্বিশেষে মেলাতে পারে।
অন্যদিকে, FIND_IN_SET('value', comma_separated_string) প্রতিটি কমা-দ্বারা পৃথক উপাদানের জন্য সঠিক মিল অনুসন্ধান করে।

-- LIKE example (matches anything containing "python")
tags LIKE '%python%'

-- FIND_IN_SET example (matches only "python" as an independent element)
FIND_IN_SET('python', tags)

এটি একটি সাধারণ LIKE ফাঁদ, যেখানে “python” “cpython” বা “pythonista” এর সাথে মেলাতে পারে।

Q3. কেন FIND_IN_SET SQL কুয়েরিগুলোকে ধীর করে দেয়?

উত্তর:
কারণ FIND_IN_SET একটি ফাংশন যা ইনডেক্স ব্যবহার না করে সম্পূর্ণ স্ক্যান বাধ্য করে
এটি প্রতিটি সারি পরীক্ষা করে এবং মান তুলনা করার জন্য স্ট্রিং পার্স করে, ফলে ডেটার পরিমাণ বাড়ার সঙ্গে সঙ্গে প্রক্রিয়াকরণের সময় দ্রুত বৃদ্ধি পায়।

এই কারণেই এটি অনেক রেকর্ডযুক্ত টেবিলগুলিতে বড় পারফরম্যান্স সমস্যার সৃষ্টি করতে পারে।

Q4. সংখ্যা অনুসন্ধান করার সময়, “1” কি “10” এর সঙ্গে গুলিয়ে ফেলতে পারে?

উত্তর:
যেহেতু FIND_IN_SET সঠিক মিল সম্পাদন করে, এটি সাধারণত “1” এবং “10” কে ভিন্ন মান হিসেবে বিবেচনা করে।
তবে, যদি হোয়াইটস্পেস, কাস্টিং, বা ইনপুট ফরম্যাটিংয়ে পার্থক্য থাকে, তবে আচরণ আপনার প্রত্যাশার থেকে ভিন্ন হতে পারে।

-- Correct example
FIND_IN_SET('1', '1,2,10') -- => 1 (first position)

-- Commonly misunderstood example
FIND_IN_SET(1, '1,2,10') -- => also 1 (works, but is ambiguous)

প্রস্তাবনা: অনিচ্ছাকৃত আচরণ এড়াতে সর্বদা মানগুলোকে স্ট্রিং হিসেবে বিবেচনা করুন।

Q5. আমি কি WordPress-এ FIND_IN_SET ব্যবহার করতে পারি?

উত্তর:
আপনি meta_query এর মতো স্ট্যান্ডার্ড WordPress ফিচার ব্যবহার করে FIND_IN_SET ব্যবহার করতে পারবেন না, তবে $wpdb দিয়ে সরাসরি SQL চালিয়ে এটি ব্যবহার করতে পারেন।

global $wpdb;
$sql = $wpdb->prepare("
  SELECT * FROM {$wpdb->prefix}postmeta
  WHERE meta_key = %s AND FIND_IN_SET(%s, meta_value)
", 'your_meta_key', 'search_value');

$results = $wpdb->get_results($sql);

তবে, যদি আপনার ডিজাইন কাস্টম ফিল্ডের উপর ব্যাপকভাবে নির্ভরশীল হয়, তবে আপনাকে বিকল্পগুলোও বিবেচনা করা উচিত (যেমন একাধিক মেটা কী পরিচালনা করা)।

Q6. JSON কলামের সঙ্গে পার্থক্য কী? কি সেগুলো FIND_IN_SET এর চেয়ে বেশি সুবিধাজনক?

উত্তর:
MySQL 5.7+ এ JSON কলাম ব্যবহার করলে আপনি ডেটা গঠনযুক্ত রাখতে পারেন এবং JSON_CONTAINS() দিয়ে অনুসন্ধান করতে পারেন।
সঠিকতা, স্কেলেবিলিটি এবং নমনীয়তার দিক থেকে এটি সাধারণত FIND_IN_SET এর চেয়ে উত্তম।

-- JSON search example
SELECT * FROM users WHERE JSON_CONTAINS(tags_json, '"python"');

আধুনিক ডিজাইনে, FIND_IN_SET এর উপর JSON কলামকে অগ্রাধিকার দেওয়া ক্রমবর্ধমান সাধারণ হয়ে উঠেছে।

10. উপসংহার: FIND_IN_SET একটি “সুবিধাজনক ব্যতিক্রম” এবং আপনার স্কিমা পুনর্বিবেচনা করার একটি সুযোগ

এই প্রবন্ধে, আমরা MySQL এর FIND_IN_SET() ফাংশনকে কভার করেছি—মৌলিক সিনট্যাক্স এবং ব্যবহারিক উদাহরণ থেকে ফাঁদ এবং সুপারিশকৃত বিকল্প পর্যন্ত।

এটি হয়তো একটি ছোট ফাংশন মনে হতে পারে, তবে সঠিকভাবে ব্যবহার করলে এটি একটি শক্তিশালী টুল যা ডেটাবেস অপারেশনে আপনার সক্ষমতা বাড়ায়

FIND_IN_SET এর মূল বৈশিষ্ট্যসমূহের পর্যালোচনা

FeatureExplanation
✅ Flexible comma-separated searchingEnables “per-value” matching that can be difficult with LIKE
✅ Works well with legacy denormalized databasesCan solve problems without changing the schema
⚠ Performance issues because indexes can’t be usedCan slow down queries significantly on large tables
⚠ Sensitive to input and storage inconsistenciesWhitespace or full-width symbols can break matching

কখন এটি ব্যবহার করবেন (এবং কখন নয়)

ব্যবহার করার উপযুক্ত সময়:

  • ডেটাসেটটি ছোট এবং ব্যবহার সীমিত
  • লিগেসি সিস্টেম রিফ্যাক্টর করা কঠিন এবং আপনাকে দ্রুত সমাধান দরকার
  • আপনি অ্যাডমিন স্ক্রিন বা ব্যাচ প্রসেসিং-এ অস্থায়ী সমাধান চান

যে সময়ে এড়িয়ে চলা উচিত:

  • বড় ডেটাসেট যেখানে অনুসন্ধানের গতি গুরুত্বপূর্ণ
  • এমন ওয়ার্কফ্লো যা ঘন ঘন আপডেট, সমষ্টি বা পরিবর্তনশীল শর্ত প্রয়োজন
  • দীর্ঘমেয়াদী সম্প্রসারণ এবং রক্ষণাবেক্ষণের জন্য পরিকল্পিত ডিজাইন

FIND_IN_SET একটি “সুবিধাজনক ব্যতিক্রম”。 প্রকৃত সমাধান হল ভাল স্কিমা ডিজাইন

FIND_IN_SET মূলত গঠনগত সীমাবদ্ধতা থাকলে একটি সমাধান
যদি আপনি একটি নতুন স্কিমা ডিজাইন করছেন, তবে এই দুটি বিকল্প বিবেচনা করুন:

  • স্বাভাবিক করুন ডেটাবেসকে এবং একটি জাংশন টেবিলের মাধ্যমে অনেক-থেকে-অনেক সম্পর্কগুলি পরিচালনা করুন
  • যদি আপনার নমনীয়তা প্রয়োজন হয়, গঠনমূলক ডেটা সংরক্ষণের জন্য একটি JSON কলাম ব্যবহার করুন

যদি এই প্রবন্ধটি আপনাকে FIND_IN_SET কখন উপযোগী, তার সীমাবদ্ধতা, এবং কেন স্কিমা ডিজাইন পুনর্বিবেচনা করা প্রায়শই সর্বোত্তম সমাধান তা ভালভাবে বুঝতে সাহায্য করে, তবে তা একটি জয়।