سلام چند وقت پیش مشکل عجیبی موقع نامگذاری جدولهای sql برام پیش اومد که خیلی طول کشید دلیلشو بفهمم و بعد با یه کلک جالب مشکلو حل کردم.
من دارم یه اپ اندرویدی مینویسم که توی اون سنارویی پیش اومد که کاربر یک نوشته(استرینگ) رو توی برنامه وارد می کنه و این نوشته توی جدولی از دیتابیس A داخل یک رکورد ذخیره میشه و همچنین توی دیتابیس B یک جدول ایجاد میشه که نام اسمش همین رشتهایه که کاربر وارد کرده.
خب یه عکس زشت (به بزرگی خودتون ببخشید دیگه?) آماده کردم که این سناریو رو نشون میده.
این کار بعضی وقتا باعث ایجاد خطا در برنامه میشه. امّا چرا؟ دلیلش اینه که ما کنترلی روی ورودی کاربر نداریم و کاربر میتونه هر رشتهای وارد کنه ولی sql هر اسمیرو به عنوان نام جدول قبول نمیکنه!
-راه اوّل: خب یه راهی که به ذهن میرسه اینه که کاربر رو مجبور به وارد کردن ورودی معتبر برای نام جدول بکنیم که تجربهی کاربری خوبی نیست.
- راه دوّم: یه راه بهتر که به ذهن میرسه اینه که بذاریم کاربر هر چیزی رو که میخواد به عنوان ورودی وارد کنه و ما بیایم و اون ورودی رو برای نام جدول معتبرسازی(validate) کنیم.
-یه راه سوّمیهم هست که جواب اصلی مسئلهی ماست (پایینتر بعد از راه دوّم توضیحش دادم??)
نام جدولها در sql باید دارای یک سری شرایط باشه. مثلا نباید داخلش از کاراکتر اسپیس یا * یا ٪ و... استفاده کرد. شما میتونید از این لینک شرایط لازم برای نام جدول در sql رو مطالعه کنید.
خب من برای این کار تابعی با نام validateTableName نوشتم که یک استرینگ به عنوان ورودی میگیره، اون رو برای نام جدول sql معتبرسازی می کنه و برمیگردونه. کار این تابع اینه که اگه کاراکتر نامعتبری داخل ورودی باشه یه سری کاراکتر درهم و برهم به جای اون کاراکتر قرار میده. من دیگه وارد جزئیات این تابع نمیشم خودتون میتونید بخونید.
private static String[] specialChars = new String[]{" ", "!", "\"", "#", "$", "%", "&", "\'", "(", ")", "*", "+", ",", "-", ".", "/", ":", "", "<", "=", ">", "?", "@", "[", "\\", "]", "^", "_", "`", "{", "|", "}", "~"}; public static String validateTableName(String input) { input = "_"+input; for (String s : specialChars) { input = input.replace(s, validateChar(s)); } return input; } private static String validateChar(String s) { String result; switch (s) { case " ": result = "Space" break; case "!": result = "Exclamation" break; case "\"": result = "Double quote" break; case "#": result = "Number sign (hash)" break; case "$": result = "Dollar sign" break; case "%": result = "Percent" break; case "&": result = "Ampersand" break; case "\'": result = "Single quote" break; case "(": result = "Left parenthesis" break; case ")": result = "Right parenthesis" break; case "*": result = "Asterisk" break; case "+": result = "Plus" break; case ",": result = "Comma" break; case "-": result = "Minus" break; case ".": result = "Full stop" break; case "/": result = "Slash" break; case ":": result = "Colon" break; case "": result = "Semicolon" break; case "<": result = "Less than" break; case "=": result = "Equal sign" break; case ">": result = "Greater than" break; case "?": result = "Question mark" break; case "@": result = "At sign" break; case "[": result = "Left bracket" break; case "\\": result = "Backslash" break; case "]": result = "Right bracket" break; case "^": result = "Caret" break; case "_": result = "Underscore" break; case "`": result = "Grave accent (backtick)" break; case "{": result = "Left brace" break; case "|": result = "Vertical bar" break; case "}": result = "Right brace" break; case "~": result = "Tilde" break; default: return s; } result = "iii" + result + "abcسلام" + "jjj" return result; }
این تابع میتونه برای رفع مشکل ایجاد شده به درد بخوره امّا توی این سناریو یه راه بهتر به ذهنم رسید.
- و امّا اون راه چیه؟ همون طور که توی عکس بالا هم دیدید متنی که کاربر وارد می کنه داخل رکوردی از Database A => table1 ذخیره میشه و سپس یک جدول در دیتابیس B ایجاد می شه که نامش همین ورودی کاربره. خب چه کاریه؟ نام جدولی که توی دیتابیس B ساخته میشه رو بر اساس id ای که در Database A => table1 هست انتخاب میکنیم. با این کار، کاربر هر چیزی که بخواد به عنوان ورودی وارد میکنه، اون ورودی داخل رکوردی از Database A => table1 ذخیره میشه و id متناظر با این رکورد برای نام جدول ساخته شده در دیتابیس B استفاده میشه?.
توجّه: نام جدول نمیتونه یه عدد باشه در صورتی که id یک عدد هست که برای رفع این مشکل هم یک آندرلاین به اوّل id اضافه کردم?.
String tableName = "_" + id;
خیلی ممنون که وقت گذاشتید و این نوشتهرو خوندید. اگر شما راه بهتری به ذهنتون میرسه حتما تو کامنتا بگید.
? و نظرم یادتون نره!