PDA

View Full Version : select های تودرتو برای جستجوی تاریخ



farzane_fn
چهارشنبه 01 مهر 1388, 20:31 عصر
سلام دوستان عزیزم.از خدا می خوام همیشه پیروز باشید.سوالی که داشتم اینه: من یه برنامه دارم می نویسم توش یه جستجوی تاریخ دارم. فیلد های تاریخ هم به این صورت تعریف شده اند: یک فیلد اینتجر برای روز یک فیلد اینتجر برای ماه و یک فیلد اینتجر برای سال. حال می خواهیم از تاریخ a تا تاریخ b را جستجو کنیم. شش تا ادیت هم گذاشته ایم که سه تاش مربوط به تاریخ a است و سه تاش هم مربوط به تاریخ b . حال می خواستم کدی داشته باشم که این جستجو رو انجام بده. فکر می کنم از select های تودرتو باید استفاده کرد. ولی من بلد نیست.لطفا کمکم کنید.متشکرم

Saeed_m_Farid
پنج شنبه 02 مهر 1388, 10:37 صبح
...یک فیلد اینتجر برای روز یک فیلد اینتجر برای ماه و یک فیلد اینتجر برای سال. حال می خواهیم از تاریخ a تا تاریخ b را جستجو کنیم. شش تا ادیت هم گذاشته ایم که سه تاش مربوط به تاریخ a است و سه تاش هم مربوط به تاریخ b . حال می خواستم کدی داشته باشم که این جستجو رو انجام بده. فکر می کنم از select های تودرتو باید استفاده کرد...
سلام
اولاً : این طراحی برای جدول تون اشتباهه، بهتر بود به ساختار جدولتون دست نمی زدید و یه فیلد nvarchar یا datetime برای تاریخ می ذاشتید، به هر منظوری هم این کار رو کردید (مثلاً جستجوهای مجزا برای روز/ماه/سال)، توابع مربوط به رشته و زمان در SQL می تونه این قابلیت رو واستون ایجاد کنه ...
ثانیاً : این سوال شما ربطی به دلفی نداره، فقط Edit های رو فرمتون به دلفی مربوطه!
و در نهایت، با فرض به اینکه شما مجبورید این ساختار رو داشته باشید، مساله رو یه جوری حل می کنیم که قسمت عمده کار به دلفی مربوط باشه تا SQL، چون اینجا تالار دلفی هست.

پیش فرض ها :

یه جدول داریم بنام datetable که حداقل دارای فیلدهای iYear, iMonth, iDay هست.
شش تا Edit برای عناصر تاریخ : edtY1, edtM1, edtD1, edtY2, edtM2, edtD2.
اگه مقادیر درون Editها عددی نباشه، مقدار پیش فرض 0 رو جایگزین می کنیم.
بانک اطلاعاتی SQL Server هست.
از ADOQuery استفاده می کنیم.
باید از یه کوئری تک لایه (تودرتو نباشه) استفاده کنیم (تا پیچیدگی بیاد سمت دلفی)

نکته: چون تو رشته ها مثلاً 9 از 30 بزرگتره، و تو SQL توابع مستقیم برای تبدیل عدد با فرمت بندی وجود نداره (یعنی عدد 3 رو مثلاً به '03' تبدیل کنیم)، و متاسفانه فیلد شما int هست، و قرار نیست کار زیادی بر عهده SQL باشه؛ راهی که بنظر من میرسه برای مقایسه به هر دو طرف 10 عدد اضافه می کنیم (برای روز و ماه) که از نظر منطقی (و همچنین خروجی کوئری) تو نتیجه مقایسه تاثیری نداره، ولی تو سینتکس به ما کمک می کنه، نتیجه میشه کد زیر :
procedure TForm1.Button1Click(Sender: TObject);
var
dt1, dt2: String;
begin
dt1 := Format('%.4d/%.2d/%.2d',
[StrToIntDef(edtY1.Text, 0),
StrToIntDef(edtM1.Text, 0) + 10,
StrToIntDef(edtD1.Text, 0) + 10]);
dt2 := Format('%.4d/%.2d/%.2d',
[StrToIntDef(edtY2.Text, 0),
StrToIntDef(edtM2.Text, 0) + 10,
StrToIntDef(edtD2.Text, 0) + 10]);
with ADOQuery1 do begin
SQL.Text := 'SELECT * FROM datetable WHERE '+
'LTRIM(STR(iYear)) + ''/'' + ' +
'LTRIM(STR(iMonth + 10)) + ''/'' + ' +
'LTRIM(STR(IDay + 10)) ' +
'BETWEEN ' + QuotedStr(dt1) + ' AND ' +
QuotedStr(dt2);
//ShowMessage(SQL.Text);
Open;
end;
end;

farzane_fn
پنج شنبه 02 مهر 1388, 12:43 عصر
سلام
اولاً : این طراحی برای جدول تون اشتباهه، بهتر بود به ساختار جدولتون دست نمی زدید و یه فیلد nvarchar یا datetime برای تاریخ می ذاشتید، به هر منظوری هم این کار رو کردید (مثلاً جستجوهای مجزا برای روز/ماه/سال)، توابع مربوط به رشته و زمان در SQL می تونه این قابلیت رو واستون ایجاد کنه ...
ثانیاً : این سوال شما ربطی به دلفی نداره، فقط Edit های رو فرمتون به دلفی مربوطه!
و در نهایت، با فرض به اینکه شما مجبورید این ساختار رو داشته باشید، مساله رو یه جوری حل می کنیم که قسمت عمده کار به دلفی مربوط باشه تا SQL، چون اینجا تالار دلفی هست.



پیش فرض ها :

یه جدول داریم بنام datetable که حداقل دارای فیلدهای iYear, iMonth, iDay هست.
شش تا Edit برای عناصر تاریخ : edtY1, edtM1, edtD1, edtY2, edtM2, edtD2.
اگه مقادیر درون Editها عددی نباشه، مقدار پیش فرض 0 رو جایگزین می کنیم.
بانک اطلاعاتی SQL Server هست.
از ADOQuery استفاده می کنیم.
باید از یه کوئری تک لایه (تودرتو نباشه) استفاده کنیم (تا پیچیدگی بیاد سمت دلفی)
نکته: چون تو رشته ها مثلاً 9 از 30 بزرگتره، و تو SQL توابع مستقیم برای تبدیل عدد با فرمت بندی وجود نداره (یعنی عدد 3 رو مثلاً به '03' تبدیل کنیم)، و متاسفانه فیلد شما int هست، و قرار نیست کار زیادی بر عهده SQL باشه؛ راهی که بنظر من میرسه برای مقایسه به هر دو طرف 10 عدد اضافه می کنیم (برای روز و ماه) که از نظر منطقی (و همچنین خروجی کوئری) تو نتیجه مقایسه تاثیری نداره، ولی تو سینتکس به ما کمک می کنه، نتیجه میشه کد زیر :
procedure TForm1.Button1Click(Sender: TObject);
var
dt1, dt2: String;
begin
dt1 := Format('%.4d/%.2d/%.2d',
[StrToIntDef(edtY1.Text, 0),
StrToIntDef(edtM1.Text, 0) + 10,
StrToIntDef(edtD1.Text, 0) + 10]);
dt2 := Format('%.4d/%.2d/%.2d',
[StrToIntDef(edtY2.Text, 0),
StrToIntDef(edtM2.Text, 0) + 10,
StrToIntDef(edtD2.Text, 0) + 10]);
with ADOQuery1 do begin
SQL.Text := 'SELECT * FROM datetable WHERE '+
'LTRIM(STR(iYear)) + ''/'' + ' +
'LTRIM(STR(iMonth + 10)) + ''/'' + ' +
'LTRIM(STR(IDay + 10)) ' +
'BETWEEN ' + QuotedStr(dt1) + ' AND ' +
QuotedStr(dt2);
//ShowMessage(SQL.Text);
Open;
end;
end;

دوست عزیزم سلام.راه حلتون رو مطالعه کردم.خیلی جالب بود.ازتون به خاطر راهنماییتون تشکر می کنم.ولی چشم به توصیه شما عمل می کنم و ساختار جدولم رو تغییر می دم.بازم اگه مشکلی برام پیش اومد با شما درمیون می زارم. بازم متشکرم

DlphIran
پنج شنبه 02 مهر 1388, 14:35 عصر
با يه خط اس كيو ال مي توني بين دو تاريخ رو جستجو كني ، خيلي ساده

sql.Add('where ((dy=:a and dm>=:b and dd>=:c) or (dy=:d and dm>:e) or dy>:f)
and ((dy=:g and dm<=:h and dd<=:i) or (dy=:j and dm<:k) or dy<:l)');

parameters.ParamByName('a').Value:=edit4.text;
parameters.ParamByName('b').Value:=edit5.text;
parameters.ParamByName('c').Value:=edit6.text;
parameters.ParamByName('d').Value:=edit4.text;
parameters.ParamByName('e').Value:=edit5.text;
parameters.ParamByName('f').Value:=edit4.text;
parameters.ParamByName('g').Value:=edit3.text;
parameters.ParamByName('h').Value:=edit2.text;
parameters.ParamByName('i').Value:=edit1.text;
parameters.ParamByName('j').Value:=edit3.text;
parameters.ParamByName('k').Value:=edit2.text;
parameters.ParamByName('l').Value:=edit3.text;

farzane_fn
پنج شنبه 02 مهر 1388, 15:58 عصر
با يه خط اس كيو ال مي توني بين دو تاريخ رو جستجو كني ، خيلي ساده

sql.Add('where ((dy=:a and dm>=:b and dd>=:c) or (dy=:d and dm>:e) or dy>:f)
and ((dy=:g and dm<=:h and dd<=:i) or (dy=:j and dm<:k) or dy<:l)');

parameters.ParamByName('a').Value:=edit4.text;
parameters.ParamByName('b').Value:=edit5.text;
parameters.ParamByName('c').Value:=edit6.text;
parameters.ParamByName('d').Value:=edit4.text;
parameters.ParamByName('e').Value:=edit5.text;
parameters.ParamByName('f').Value:=edit4.text;
parameters.ParamByName('g').Value:=edit3.text;
parameters.ParamByName('h').Value:=edit2.text;
parameters.ParamByName('i').Value:=edit1.text;
parameters.ParamByName('j').Value:=edit3.text;
parameters.ParamByName('k').Value:=edit2.text;
parameters.ParamByName('l').Value:=edit3.text;
دوست عزیزم سلام.می تونین یه توضیح بدین که عبارتهای a,b,c,d...k,l چی هستن؟ و یه توضیح مختصر در مورد عملکرد این دستورات.در ضمن اگه ممکنه دستورات رو یه جوری بنویسین که به صورت اصلی خودش نمایش داده بشن ممنون می شم.به هر حال از شما تشکر می کنم.

delphiprog3000
جمعه 03 مهر 1388, 01:15 صبح
با سلام.

دوست من عکس فرم رو برات میزارم. از کامپوننت Solardate که تو همین سایت بگردی پیداش میکنی.

به انضمام کد دکمه جستجو که منطق جستجو بین تواریخ رو نشون میده.

کد دکمه:


procedure TAlarm_time_form.btn_searchClick(Sender: TObject);
begin
flag2:=true;
if (cmb_date2.Text<>'') then
begin
if flag2 then
Str1:=' date_meet like '+QuotedStr(cmb_date2.Text);
end;

if (cmb_date3.Text<>'') then
begin
if flag2 then
Str1:=' date_meet like '+QuotedStr(cmb_date3.Text);
end;

Flag1:=false;
if edt_name_meeter1.Text<>'' then
begin
Flag1:=true;
Str1:=' name_meeter like'+QuotedStr(edt_name_meeter1.Text);
end;
if (cmb_date2.Text<>'') and (cmb_date3.Text<>'') then
begin
if flag1 then
begin
Flag1:=true;
flag2:=true;
Str1:=str1+' and date_meet between'+QuotedStr(cmb_date2.Text) +'and ' +QuotedStr(cmb_date3.Text);
end
else begin flag2:=true; Str1:=' date_meet between'+QuotedStr(cmb_date2.Text)+ 'and ' +QuotedStr(cmb_date3.Text); end;
end;


if (edt_name_meeter1.Text<>'') or (cmb_date2.Text<>'') or (cmb_date3.Text<>'') then
begin
with DataModule1.Qry_Meeting do
begin
close;
SQL.Text:='select * from tbl_meeting where '+Str1;
open;
Active:=true;
Ds_Meeting.DataSet:=DataModule1.Qry_Meeting;
if Ds_Meeting.DataSet=DataModule1.Qry_Meeting then
begin
DataModule1.Qry_Meeting.Active:=true;
btn_save1.Enabled:=true;
btn_del1.Enabled:=true;
end
else
begin
btn_save1.Enabled:=false;
btn_del1.Enabled:=false;
end;
end;
end
else begin MessageDlgTranslated('چنین موردی یافت نشد!!!!',mtInformation,[mbok],mbok,0); DataModule1.Qry_customer.Close; end;
end;


امیدوارم مفید باشه
موفق باشید........

DlphIran
جمعه 03 مهر 1388, 10:51 صبح
a,b,c,... متغيرهايي هستن كه بطور غير مستقيم با دستور param واسطه بين فيلد و مقدار مورد نظر شما هستن.
يعني بجاي quotedstr ، ميايم و با param كار مي كنيم. دستورات هم بطور كامل نوشته شده اند فقط خط دستورات sql هستن كه براي اينكه خوانا بشه از And فرستادمش خط دوم كه بهتر متوجه بشين. اتفاقا خيلي هم اين خط ساده اس.
يه توضيح بدم كه اديتهاي 4,5,6 تاريخ اول براي جستجو و 1,2,3 تاريخ آخري براي تعيين محدوده جستجو هستن .