PDA

View Full Version : یک کوئری search



m_amin_t
چهارشنبه 15 اردیبهشت 1389, 13:22 عصر
سلام
من توی دیتابیسم 2 تا جدول دارم که یکی جدول سوالات و یکی جدول پاسخ ها. حالا میخوام یه عملیات جستجو انجام بدم به صورتی که اگر عبارت جستجو توی متن سوال بود، متن سوال رو برگردونه و اگه عبارت جستجو توی متن جواب بود، متن سوال این جواب رو برگردونه. جدول سوالاتم شامل id و question هستش و جدول جواب ها شامل id و answer و questionId هستش.

محمد سلیم آبادی
چهارشنبه 15 اردیبهشت 1389, 13:31 عصر
کدی شبیه به این:

SELECT quistion FROM questions WHERE question LIKE '%'+@param+'%'
UNION ALL
SELECT question FROM answers a INNER JOIN questions q ON a.questionid = q.id WHERE answer LIKE '%' + @param + '%'

یا خیلی ساده تر:

SELECT question
FROM questions q
INNER JOIN answers a
ON q.id = a.questionid
WHERE q.question LIKE '%'+@param='@'
OR a.answer LIKE '%'+@param+'%';

m_amin_t
چهارشنبه 15 اردیبهشت 1389, 13:47 عصر
کدی شبیه به این:

SELECT quistion FROM questions WHERE question LIKE '%'+@param+'%'
UNION ALL
SELECT question FROM answers a INNER JOIN questions q ON a.questionid = q.id WHERE answer LIKE '%' + @param + '%'یا خیلی ساده تر:

SELECT question
FROM questions q
INNER JOIN answers a
ON q.id = a.questionid
WHERE q.question LIKE '%'+@param='@'
OR a.answer LIKE '%'+@param+'%';

این درست ولی اگه به فرض سوالی وجود داشت که هیچ جوابی نداشت (یعنی در جدول جواب ها سطری بهش اختصاص داده نشده بود) دیگه جواب نمیده. توی جدول جواب ها، فقط آیدی سوال وجود داره

محمد سلیم آبادی
چهارشنبه 15 اردیبهشت 1389, 14:02 عصر
این چطور؟

SELECT DISTINCT q.question
FROM questions q
LEFT OUTER JOIN answers a
ON q.id = a.questionid
WHERE q.question LIKE '%'+@param='@'
OR a.answer LIKE '%'+@param+'%';

m_amin_t
چهارشنبه 15 اردیبهشت 1389, 14:13 عصر
چطور میتونم ترتیب کلمات وارد شده در بخش عبارت جستجو رو از بین ببرم. یعنی مثلا کاربر در قسمت عبارت جستجو نوشته : "این است". من میخوام این کلمات رو از هم جدا کنم و هر ترتیبی از این کلمات رو جستجو کنم، یعنی هم عبارت "این است"، هم عبارت "است این"، و هم به این صورت : "%این%است%" و برعکس.

محمد سلیم آبادی
چهارشنبه 15 اردیبهشت 1389, 14:15 عصر
همگی عباراتی که جستجو میشن به سادگی همین دو کلمه هستند. یعنی فقط از دو کلمه تشکیل شدن یا اینکه متغیر هست و میتونه بیش از اینها باشه؟

m_amin_t
چهارشنبه 15 اردیبهشت 1389, 14:17 عصر
تعدادشون متغیره

محمد سلیم آبادی
چهارشنبه 15 اردیبهشت 1389, 14:19 عصر
حد اکثر این کلمات بیش از چهارتا است؟

m_amin_t
چهارشنبه 15 اردیبهشت 1389, 14:23 عصر
منظورتون اینه که تعداد کلمات رو باید محدود کنم؟

محمد سلیم آبادی
چهارشنبه 15 اردیبهشت 1389, 14:29 عصر
نه منظورم اینه که در عباراتی که می خواهین چستجو بشن ممکنه بیش از چهار کلمه وجود داشته باشه. اگر تعداد کلمات خیلی محدود باشن ممکنه بتونم با استفاده توابع مختلفی مثل PARSENAME , CHARINDEX و.. مساله را حل کنم. ولی بهتر هست یک جستجویی راجب Full-Text Search انجام بدین.

m_amin_t
چهارشنبه 15 اردیبهشت 1389, 14:51 عصر
تعداد کلمات که محدود نیستن، چیزی راجع به full text search نمیدونم ولی میگردم و سعی میکنم پیدا کنم. بازم ممنون از راهنماییتون

m_amin_t
چهارشنبه 15 اردیبهشت 1389, 15:28 عصر
ممکنه یه مثال استفاده از FTS رو بنویسین؟

m_amin_t
چهارشنبه 15 اردیبهشت 1389, 15:31 عصر
اونجوری که من یه جستجوی کلی کردم متوجه شدم که FTS رو هاست باید فعال کنه وگرنه کاربردی نداره. درسته؟ آیا راه دیگه ای برای جستجو که کار منو راه بندازه وجود داره؟

محمد سلیم آبادی
چهارشنبه 15 اردیبهشت 1389, 21:57 عصر
اونجوری که من یه جستجوی کلی کردم متوجه شدم که FTS رو هاست باید فعال کنه وگرنه کاربردی نداره. درسته؟ آیا راه دیگه ای برای جستجو که کار منو راه بندازه وجود داره؟

بله امکانش هست، ابتدا این تابع را ایجاد کنید سپس کوئری را اجرا کنید:
کوئری


SELECT question
FROM questions
INNER JOIN dbo.fnParseList(' ', @param) AS f
ON question LIKE '%' + f.Data + '%'
GROUP BY question
HAVING COUNT(*) = (SELECT COUNT(*) FROM dbo.fnParseList(' ', @param));


تابع:



CREATE FUNCTION dbo.fnParseList
(
@Delimiter CHAR,
@Text TEXT
)
RETURNS @Result TABLE (RowID SMALLINT IDENTITY(1, 1) PRIMARY KEY, Data VARCHAR(8000))
AS

BEGIN
DECLARE @NextPos INT,
@LastPos INT

SELECT @NextPos = CHARINDEX(@Delimiter, @Text, 1),
@LastPos = 0

WHILE @NextPos > 0
BEGIN
INSERT @Result
(
Data
)
SELECT SUBSTRING(@Text, @LastPos + 1, @NextPos - @LastPos - 1)

SELECT @LastPos = @NextPos,
@NextPos = CHARINDEX(@Delimiter, @Text, @NextPos + 1)
END

IF @NextPos <= @LastPos
INSERT @Result
(
Data
)
SELECT SUBSTRING(@Text, @LastPos + 1, DATALENGTH(@Text) - @LastPos)

RETURN
END

m_amin_t
چهارشنبه 29 اردیبهشت 1389, 15:39 عصر
ممنون از لطفتون. امکانش هست یه توضیح کلی در موردش هم بدین که بفهمم چطور باید استفاده کنم و چطور کار میکنه؟

محمد سلیم آبادی
چهارشنبه 29 اردیبهشت 1389, 19:23 عصر
طریقه ی استفاده از آن را با Query پست قبلیم مشخص کردم. یعنی هنوز نتونستین ازش استفاده کنید؟
منطق کلی این هست: ابتدا کلمات موجود در رشته ای را که می خواهین به عنوان الگو در نظر بگیرین را از هم تفکیک می کنیم سپس JOIN می کنیم با داده های جدول و بعد گروه بندی می کنیم و در آخر سطرهایی که تعداد COUNT آنها برابر با 3 بود انتخاب می شوند و به این معنا هستند که هر سه کلمه را شامل می شوند.

m_amin_t
شنبه 01 خرداد 1389, 19:23 عصر
یه سوال دیگه! اگه یادتون باشه برای جستجو بین هر دو جدول سوالات و جواب ها از کوئری زیر استفاده کردین و به درستی هم جواب داد:




SELECT DISTINCT q.question
FROM questions q
LEFT OUTER JOIN answers a
ON q.id = a.questionid
WHERE q.question LIKE '%'+@param='@'
OR a.answer LIKE '%'+@param+'%';

در انتها این کوئری هم برای جستجو بین جدول سوالات استفاده شد:





SELECT question
FROM questions
INNER JOIN dbo.fnParseList(' ', @param) AS f
ON question LIKE '%' + f.Data + '%'
GROUP BY question
HAVING COUNT(*) = (SELECT COUNT(*) FROM dbo.fnParseList(' ', @param));


از روی کوئری بالا این کوئری رو هم برای جستجو بین جدول جواب ها به دست آوردم:

SELECT questions.id, questions.question
FROM questions INNER JOIN answers ON answers.questionID = questions.id
INNER JOIN dbo.fnParseList(' ', @param) AS f
ON answers.answer LIKE '%' + f.Data + '%'
GROUP BY questions.id, questions.question
HAVING COUNT(*) = (SELECT COUNT(*) FROM dbo.fnParseList(' ', @param))حالا سوالم اینه که چطور میشه کوئری اولی رو که جستجو بین هر دو جدول هستش رو به شیوه ی این دو کوئری آخر درآورد؟ چند تا شیوه رو امتحان کردم ولی جواب نگرفتم. اگه ممکنه راهنمایی کنید. ممنون

محمد سلیم آبادی
شنبه 01 خرداد 1389, 19:46 عصر
اینو امتحان کردین؟



SELECT question
FROM questions
INNER JOIN dbo.fnParseList(' ', @param) AS f
ON question LIKE '%' + f.Data + '%'
GROUP BY question
HAVING COUNT(*) = (SELECT COUNT(*) FROM dbo.fnParseList(' ', @param))

UNION

SELECT question
FROM questions q
JOIN answers a
ON q.id = a.questionid
JOIN
(
SELECT a.answer
FROM answers a
INNER JOIN dbo.fnParseList(' ', @param) AS f
ON answer LIKE '%' + f.Data + '%'
GROUP BY answer
HAVING COUNT(*) = (SELECT COUNT(*) FROM dbo.fnParseList(' ', @param))
) D ON a.question = D.question;

m_amin_t
شنبه 01 خرداد 1389, 19:57 عصر
امتحان کردم ولی این پیغام خطا رو میده

محمد سلیم آبادی
شنبه 01 خرداد 1389, 23:30 عصر
قبل از UNION یک semicolon بود که حذفش کنید و خط یکی مونده به خاطر کوئری هم یک پرانتز جا افتاده است.
(می تونید به پست قبلیم نگاه کنید با رنگ قرمز مشخص کردم)

m_amin_t
یک شنبه 02 خرداد 1389, 00:07 صبح
قبل از UNION یک semicolon بود که حذفش کنید و خط یکی مونده به خاطر کوئری هم یک پرانتز جا افتاده است.
(می تونید به پست قبلیم نگاه کنید با رنگ قرمز مشخص کردم)

متاسفانه بازم اجرا نشد. پیغام خطا میده

محمد سلیم آبادی
یک شنبه 02 خرداد 1389, 05:53 صبح
پیغام میگه که نام ستون question معتبر نیست. چطور ممکنه؟! نام ستون هایتان همون هایی بودن که گفتین؟ یعنی جدول سوالات نامش questions هست که دارای دو ستون id و question --- جدول پاسخ ها هم اسمش answer هست با نام ستون های id و questionid و answer.

این کوئری را امتحان کنید، اگر بازم پیغام خطا داد بیایین کوئری را داخل SQL Server اجرا کنید تا دقیق تر پیغام خطا مشاهده بشه:


SELECT question
FROM questions q
INNER JOIN dbo.fnParseList(' ', @param) AS f
ON question LIKE '%' + f.Data + '%'
GROUP BY id, question
HAVING COUNT(*) = (SELECT COUNT(*) FROM dbo.fnParseList(' ', @param))

UNION

SELECT question
FROM questions q
JOIN
(
SELECT questionid
FROM answers a
INNER JOIN dbo.fnParseList(' ', @param) AS f
ON answer LIKE '%' + f.Data + '%'
GROUP BY questionid, answer
HAVING COUNT(*) = (SELECT COUNT(*) FROM dbo.fnParseList(' ', @param))
)D ON D.questionid = q.id;

محمد سلیم آبادی
یک شنبه 02 خرداد 1389, 11:25 صبح
درست شد. ممنون. چیزای زیادی یاد گرفتم ازتون

من هم از کمک کردن به شما چیزهای زیادی یاد میگیرم :لبخندساده:

m_amin_t
یک شنبه 02 خرداد 1389, 15:53 عصر
به یه مشکلی برخورد کردم. کوئری من هنگام کار با خود sql server یعنی وقتی کوئری رو مستقیما اجرا میکنم به درستی کار میکنه و نتایج مطلوب رو برمیگردونه. ولی وقتی از طریق یه textboxو از توی کد با sp کوئری موردنظر رو اجرا میکنم نتایج نامرتبط و بی مورد رو بر میگردونه!! به نظرتون مشکل از کجاست؟؟

محمد سلیم آبادی
یک شنبه 02 خرداد 1389, 16:58 عصر
نمی دونم مشکل از کجاست.
اگر تمایل دارین SP که دارین ازش استفاده می کنید را پست کنید تا شاید بتونم کمکی کنم.

m_amin_t
یک شنبه 02 خرداد 1389, 17:06 عصر
این پروسیجر:

ALTER PROCEDURE dbo.sp_SearchQAs
@param nvarchar

AS
SELECT id, question
FROM questions q
INNER JOIN dbo.fnParseList(' ', @param) AS f
ON question LIKE '%' + f.Data + '%'
GROUP BY id, question
HAVING COUNT(*) = (SELECT COUNT(*) FROM dbo.fnParseList(' ', @param))

UNION

SELECT id, question
FROM questions q
JOIN
(
SELECT questionid
FROM answers a
INNER JOIN dbo.fnParseList(' ', @param) AS f
ON answer LIKE '%' + f.Data + '%'
GROUP BY questionid, answer
HAVING COUNT(*) = (SELECT COUNT(*) FROM dbo.fnParseList(' ', @param))
)D ON D.questionid = q.id;
RETURNاینم جایی که صداش میکنم:

SqlDataAdapter objDataAdapter = new SqlDataAdapter();
objDataAdapter.SelectCommand = new SqlCommand("", new SqlConnection(connStr));
SqlParameter[] prms = new SqlParameter[1];
prms[0] = new SqlParameter("@param", SqlDbType.NVarChar);
prms[0].Value = txt_search.Text;
objDataAdapter.SelectCommand.CommandText = "sp_SearchQAs";
objDataAdapter.SelectCommand.CommandType = CommandType.StoredProcedure;
objDataAdapter.SelectCommand.Parameters.AddRange(p rms);
DataSet ds = new DataSet();
objDataAdapter.SelectCommand.Connection.Open();
objDataAdapter.Fill(ds);
objDataAdapter.SelectCommand.Connection.Close();

محمد سلیم آبادی
یک شنبه 02 خرداد 1389, 17:17 عصر
شاید نیاز باشه که قبل از param@ در کدها از کاراکتر N استفاده کنین یعنی:


dbo.fnParseList(' ', N'' + @param)

m_amin_t
یک شنبه 02 خرداد 1389, 17:24 عصر
شاید نیاز باشه که قبل از param@ در کدها از کاراکتر N استفاده کنین یعنی:


dbo.fnParseList(' ', N'' + @param)

این رو هم امتحان کردم ولی فرقی نکرد:گیج:

m_amin_t
یک شنبه 02 خرداد 1389, 17:27 عصر
درضمن این حالت برای جستجوی عبارت انگلیسی هم همینطوره یعنی اینجوری نیست که فقط برای عبارات فارسی مشکل دار باشه.

محمد سلیم آبادی
یک شنبه 02 خرداد 1389, 17:31 عصر
فکر می کنم مشکل به تابع Split بر میگرده. تا حالا این تابع را مستقل آزمایش کردین تا از صحتش مطمئن بشین؟

در این پست:
http://www.barnamenevis.org/forum/showpost.php?p=972467&postcount=15

قسمت اولیه ی multistatement TVF را به این شکل تغییر بدین:


CREATE FUNCTION dbo.fnParseList
(
@Delimiter CHAR,
@TEXT NVARCHAR
)
RETURNS @Result TABLE (RowID SMALLINT IDENTITY(1, 1) PRIMARY KEY, Data NVARCHAR(8000))

محمد سلیم آبادی
یک شنبه 02 خرداد 1389, 17:38 عصر
واقعیت اینه که من از صحت کامل اون تابع Parse مطمئن نیست و خودم ایجادش نکردم. بد نیست بخش آخر این مقاله را که مربوط به Splitting هست را بخوانید و از آن روش برای Parse کردن رشته استفاده کنید:
http://www.30sharp.com/ShowArticle.aspx?nid=13&did=212&AuthorID=11

m_amin_t
سه شنبه 04 خرداد 1389, 01:07 صبح
فهمیدم مشکل از کجاست! اگه توی پروسیجر پارامترش رو از

@param nvarcharبه

@param nvarchar(MAX)تغییر بدیم درست میشه!

m_amin_t
چهارشنبه 05 خرداد 1389, 09:27 صبح
سلام
وبسایت من توی عملیات جستجو تا وقتی که توی کامپیوتر خودم اجرا میشه، مشکلی با عبارات فارسی نداره و جستجو رو به درستی انجام میده. ولی وقتی سایت رو آپ میکنم دیگه عبارات فارسی رو به هیچ وجه پیدا نمیکنه. برای عبارات انگلیسی هیچ مشکلی وجود نداره ولی نمیدونم چرا برای فارسی ها اینجوریه. حتی از N'' هم استفاده کردم ولی در عمل سودی نداشت. چیزی به نظرتون میاد تا مشکل حل بشه؟!