یک برنامه‌نویس
یک برنامه‌نویس
خواندن ۱۱ دقیقه·۵ سال پیش

مشکل عجیب در sql و راه حل جالب و کلک رشتی برای آن

سلام چند وقت پیش مشکل عجیبی موقع نام‌گذاری جدول‌های sql برام پیش اومد که خیلی طول کشید دلیلشو بفهمم و بعد با یه کلک جالب مشکلو حل کردم.

من دارم یه اپ اندرویدی می‌نویسم که توی اون سنارویی پیش اومد که کاربر یک نوشته(استرینگ) رو توی برنامه وارد می کنه و این نوشته توی جدولی از دیتابیس A داخل یک رکورد ذخیره می‌شه و همچنین توی دیتابیس B یک جدول ایجاد می‌شه که نام اسمش همین رشته‌ایه که کاربر وارد کرده.

خب یه عکس زشت (به بزرگی خودتون ببخشید دیگه?) آماده کردم که این سناریو رو نشون می‌ده.


این کار بعضی وقتا باعث ایجاد خطا در برنامه می‌شه. امّا چرا؟ دلیلش اینه که ما کنترلی روی ورودی کاربر نداریم و کاربر می‌تونه هر رشته‌ای وارد کنه ولی sql هر اسمی‌رو به عنوان نام جدول قبول نمی‌کنه!

-راه اوّل: خب یه راهی که به ذهن می‌رسه اینه که کاربر رو مجبور به وارد کردن ورودی معتبر برای نام جدول بکنیم که تجربه‌ی کاربری خوبی نیست.

- راه دوّم: یه راه بهتر که به ذهن می‌رسه اینه که بذاریم کاربر هر چیزی رو که می‌خواد به عنوان ورودی وارد کنه و ما بیایم و اون ورودی رو برای نام جدول معتبرسازی(validate) کنیم.

-یه راه سوّمی‌هم هست که جواب اصلی مسئله‌ی ماست (پایین‌تر بعد از راه دوّم توضیحش دادم??)


بررسی راه دوّم:

نام جدول‌ها در sql باید دارای یک سری شرایط باشه. مثلا نباید داخلش از کاراکتر اسپیس یا * یا ٪ و... استفاده کرد. شما می‌تونید از این لینک شرایط لازم برای نام جدول در sql رو مطالعه کنید.

خب من برای این کار تابعی با نام validateTableName نوشتم که یک استرینگ به عنوان ورودی می‌گیره، اون‌ رو برای نام جدول sql معتبرسازی می کنه و برمی‌گردونه. کار این تابع اینه که اگه کاراکتر نامعتبری داخل ورودی باشه یه سری کاراکتر درهم و برهم به جای اون کاراکتر قرار می‌ده. من دیگه وارد جزئیات این تابع نمی‌شم خودتون می‌تونید بخونید.

private static String[] specialChars = new String[]{&quot &quot, &quot!&quot, &quot\&quot&quot, &quot#&quot, &quot$&quot, &quot%&quot, &quot&&quot, &quot\'&quot, &quot(&quot, &quot)&quot, &quot*&quot, &quot+&quot, &quot,&quot, &quot-&quot, &quot.&quot, &quot/&quot, &quot:&quot, &quot&quot, &quot<&quot, &quot=&quot, &quot>&quot, &quot?&quot, &quot@&quot, &quot[&quot, &quot\\&quot, &quot]&quot, &quot^&quot, &quot_&quot, &quot`&quot, &quot{&quot, &quot|&quot, &quot}&quot, &quot~&quot}; public static String validateTableName(String input) { input = &quot_&quot+input; for (String s : specialChars) { input = input.replace(s, validateChar(s)); } return input; } private static String validateChar(String s) { String result; switch (s) { case &quot &quot: result = &quotSpace&quot break; case &quot!&quot: result = &quotExclamation&quot break; case &quot\&quot&quot: result = &quotDouble quote&quot break; case &quot#&quot: result = &quotNumber sign (hash)&quot break; case &quot$&quot: result = &quotDollar sign&quot break; case &quot%&quot: result = &quotPercent&quot break; case &quot&&quot: result = &quotAmpersand&quot break; case &quot\'&quot: result = &quotSingle quote&quot break; case &quot(&quot: result = &quotLeft parenthesis&quot break; case &quot)&quot: result = &quotRight parenthesis&quot break; case &quot*&quot: result = &quotAsterisk&quot break; case &quot+&quot: result = &quotPlus&quot break; case &quot,&quot: result = &quotComma&quot break; case &quot-&quot: result = &quotMinus&quot break; case &quot.&quot: result = &quotFull stop&quot break; case &quot/&quot: result = &quotSlash&quot break; case &quot:&quot: result = &quotColon&quot break; case &quot&quot: result = &quotSemicolon&quot break; case &quot<&quot: result = &quotLess than&quot break; case &quot=&quot: result = &quotEqual sign&quot break; case &quot>&quot: result = &quotGreater than&quot break; case &quot?&quot: result = &quotQuestion mark&quot break; case &quot@&quot: result = &quotAt sign&quot break; case &quot[&quot: result = &quotLeft bracket&quot break; case &quot\\&quot: result = &quotBackslash&quot break; case &quot]&quot: result = &quotRight bracket&quot break; case &quot^&quot: result = &quotCaret&quot break; case &quot_&quot: result = &quotUnderscore&quot break; case &quot`&quot: result = &quotGrave accent (backtick)&quot break; case &quot{&quot: result = &quotLeft brace&quot break; case &quot|&quot: result = &quotVertical bar&quot break; case &quot}&quot: result = &quotRight brace&quot break; case &quot~&quot: result = &quotTilde&quot break; default: return s; } result = &quotiii&quot + result + &quotabcسلام&quot + &quotjjj&quot return result; }

این تابع می‌تونه برای رفع مشکل ایجاد شده به درد بخوره امّا توی این سناریو یه راه بهتر به ذهنم رسید.

بررسی راه سوّم:

- و امّا اون راه چیه؟ همون طور که توی عکس بالا هم دیدید متنی که کاربر وارد می کنه داخل رکوردی از Database A => table1 ذخیره می‌شه و سپس یک جدول در دیتابیس B ایجاد می شه که نامش همین ورودی کاربره. خب چه کاریه؟ نام جدولی که توی دیتابیس B ساخته می‌شه رو بر اساس id ای که در Database A => table1 هست انتخاب می‌کنیم. با این کار، کاربر هر چیزی که بخواد به عنوان ورودی وارد می‌کنه، اون ورودی داخل رکوردی از Database A => table1 ذخیره می‌شه و ‌id متناظر با این رکورد برای نام جدول ساخته شده در دیتابیس B استفاده می‌شه?.

توجّه: نام جدول نمی‌تونه یه عدد باشه در صورتی که ‌id یک عدد هست که برای رفع این مشکل هم یک آندرلاین به اوّل id اضافه کردم?.

String tableName = &quot_&quot + id;


خیلی ممنون که وقت گذاشتید و این نوشته‌رو خوندید. اگر شما راه بهتری به ذهنتون می‌رسه حتما تو کامنتا بگید.

? و نظرم یادتون نره!

برنامه نویسیاندرویددیتابیسمهندسی نرم افزارsql
توسعه دهنده‌ی وب ، دانشجوی مهندسی کامپیوتر، همیشه کنجکاو
شاید از این پست‌ها خوشتان بیاید