چطور میشه پستهای چندین موضوع رو فراخوانی کرد؟ مثلا بگوییم پستهایی که موضوع 2 و 3 رو حتما همزمان شامل میشن نمایش بده. یعنی اگر پستی موضوع 2 را داشت ولی شامل موضوع 3 نبود نمایش داده نشه؟[/font][/right]
[right][right][left][right][left][right][right][left][right][rtl]نمیدونم درست متوجه شدم یا نه، ولی حس میکنم Hesam Khaki عزیز یکم پیچوندش یا از CDbCriteria استفاده میکنیم و با تابع AddCondition شروط لازمرو اضافه میکنیم مثل زیر[/rtl]
عماد جان اگر بین اونها OR بود حق با شما بود، اما با AND اون جواب نمیده
من فرض رو بر این قرار دادم که بین جدول پست ها و جدول موضوعات، یک جدول میانی هست که post_id و category_id رو نگهداری میکنه، با این فرض فقط با select تو در تو میشه به اون جواب رسید
ضمنا AND کردن دو مقدار برای یک فیلد کلا بی معنی هست! مثل اینکه بگیم از جدول کاربران کسانی رو بده که نامشون حسام هست و (AND) نامشون عماد هست! خب مشخصه که پاسخی بر نمیگرده چون از دو مجموعه کاملا مجزا اشتراک گرفتیم. اگر بگیم حسام یا (OR) عماد، اجتماع گرفتیم و دیتابیس بهمون پاسخ های موجود رو برمیگردونه
من هم چند وقت پیش تو یه پروژه با همچین مساله ای مواجه شدم، راه حل معمول استفاده از select های تو در تو هست که من تا حد امکان ازشون استفاده نمیکنم بنابراین برای حل این مشکل از GROUP_CONCAT و REGEXP استفاده کردم و شرط رو به جای WHERE تو HAVING گذاشتم که کدش رو براتون میگذارم
با این فرض که ارتباط بین پستها و موضوعات همونطور که گفتید توسط یک جدول میانی با post_id و category_id انجام شده باشه میتونیم به صورت زیر عمل کنیم
[/rtl][/font]
$categoriesList=array(1,3,4); //example
$criteria= new CDbCriteria;
$criteria->with = array('categories');
$criteria->group='t.id'; //group by post_id
$criteria->having="CONCAT('#,',GROUP_CONCAT(category_id ORDER BY category_id),',#')
REGEXP '^#(,[1-9]*)*,".implode('(,[1-9]*)*,',$categoriesList)."(,[1-9]*)*,#$'";
آره روش آقا رضا رو بار اول بود میدیدم. تا حالا از regexp تو کوئری استفاده نکردم
روش select تو در تو بطور کلی توصیه نمیشه و حسابی به کارایی لطمه میزنه. منتها روشی که من گفتم منطق پشتش select تو در تو هست، ولی در عمل مثل همین کوئری کار میکنه که شما الان مثال زدی، یعنی یک InCondition ساده اضافه میشه به شرایط جستجوی دوم. سرعتش میشه مثل دو تا select زدن ساده روی جدول. تا الان هم تو دو تا پروژه برای جستجوی پیشرفته از همین متد استفاده کردم و زیر بار سنگین خوب جواب داده، تازه تا ۵،۶ تا شرط رو به همین روش با هم AND میکنه و پاسخ نهایی رو میده.
از لحاظ کارایی بعید نیست regex بهینه تر باشه ولی از لحاظ انعطاف و نگهداری و خوانایی کد به نظرم روش select بهتره
روش آقا حسام روش سرراست و روشنیه اما مشکل اینه که باید به تعداد موضوعات از دیتابیس کوئری بگیری و بعد اونها رو تو کوئری نهایی استفاده کنی
البته مشکلی نیست ولی فکر میکنم اگه تعداد موضوعات مورد جستجو زیاد بشه کارائیش کمی پایین بیاد
اما تو روش استفاده از GROUP_CONCAT همیشه یک کوئری میگیره و تعداد موضوعاتی که AND میشند تغییری تو تعداد کوئری ایجاد نمیکنه و شخصا فکر میکنم سریعتر باشه
در مورد قابل فهم بودن هم شاید در نگاه اول شلوغ به نظر بیاد ولی منطق خیلی ساده ای داره، به این صورت که id تمام موضوعات یک پست رو در قالب یک فیلد متنی ردیف میکنه و بعد با regular expression بررسی میکنه که آیا موضوعات مورد جستجو تو اونها هستند یا نه
البته آقا عماد sql ای که شما تو آخرین پستتون گذاشتین مساله مورد نظر رو حل نمیکنه چون موضوعات رو باهم OR میکنه ، نه AND
اینکه در همه حال نیاز به اجرای یک کوئری برای رسیدن به جواب هست خیلی جالبه، ولی راستش من ایده زیادی از regex ها ندارم، تو این روش آیا میشه اون string که الان hard code شده رو به صورت داینامیک هم در آورد؟ فرض کنید اینکه پست های ما باید شامل چه موضوعاتی باشند رو در زمان اجرا متوجه شیم ـ که فرض محتملی هم هست ـ میشه regexp مناسب رو نوشت و به دیتابیس فرستاد؟
اگه به کد دقت کنید میبینید که دقیقا همین کار انجام شده و موضوعات مورد جستجو رو به صورت آرایه دریافت میکنه و بعد متن REGEXP رو به صورت داینامیک از رو اون میسازه پس فقط کافیه مقدار اون آرایه رو از کاربر بگیرید
به عنوان مثال برای ایجاد متن جستجو برای پستهای با موضوعات 2 و 3 و 5 به صورت داینامیک به صورت زیر عمل میکنیم
[/rtl][/font]
$categoriesList=array(2,3,5); //mishe meghdare in array ro az user dar form search gereft
$searchString="'^#(,[1-9]*)*,".implode('(,[1-9]*)*,',$categoriesList)."(,[1-9]*)*,#$'"
[right][font=“Tahoma”]نه به اونکه چند روز اول که من خیلی اصرار داشتم که کاری که میخوامو انجام بدم و منتظر پاسخ بودم کسی جواب نمیداد، نه به الان که من نبودم و ماشاالله دوستان مارو مستفیض کردن با نکات جالبشون.
اولا باید بگم فعلا فرصت تست ندارم و سر فرصت همه گفته هارو بررسی کامل میکنم. دوم هم میخوام نکته کلیدی رو بگم و اون اینکه کمترین کوئری گرفتن و کمترین استفاده از حافظه و پردازنده مد نظرمه و نمیخوام پردازش و بار اضافی داشته باشم روی هیچ چیزی. این عادتمه که به شدت روی حذف اضافات تاکید دارم. به هر حال خوشحالم که بحث و پاسخها متنوع و در نوع خودش جالب بوده. به زودی نتیحه بررسی روی نظرات دوستان رو هم همینجا مینویسم.[/font][/right]