View Full Version : بدهکار و بستانکار و باقیمانده
raika17metal
جمعه 30 مهر 1389, 14:54 عصر
من یه جدول دارم که توش عملیات بانکی یه فرد ثبت میشه.
حال زمان گزارش گیری من به گزارشی مثل شکل زیر نیاز دارم :
http://www.irfreeup.com/images/9nci8nk86warmd3iksmj.png
تا اونجایی که من اطلاع دارم هنگام ذخیره سازی فقط باید برداشت و واریز ثبت بشه (باقی مانده نباید ثبت بشه).
حالا میخوام ببینم توی Query چطوری باید باقی مانده رو برای هر رکورد استخراج کنم؟!! درست مثل تصویر فوق.
حمیدرضاصادقیان
جمعه 30 مهر 1389, 18:44 عصر
سلام.دوست عزیز این مورد زیاد بحث شده بود. لطفا قبل از ارسال مطلب جستجو بفرمائید
لینک 1 (http://barnamenevis.org/forum/showthread.php?t=138784)
لینک 2 (http://barnamenevis.org/forum/showthread.php?t=158700)
لینک 3 (http://www.barnamenevis.org/forum/showthread.php?t=189122)
Rejnev
شنبه 01 آبان 1389, 13:09 عصر
select
0 [radif],
''[note],
price[variz],
0,
0[remaining]
from variz
union all
select
0,
'',
0[variz],
price[bardasht],
0[remaining]
from bardash
order by tarikh
اين كوئري يكسري ديتاي خام بهت ميده
بعد توي برنامه اي مثل C# يا وي بي يا ... با يك حلقه فور و يك متغير به سادگي باقيمانده و رديف رو محاسبه كن
---
سرعتش [B]بينهايت بالاست.
حمیدرضاصادقیان
شنبه 01 آبان 1389, 13:15 عصر
سلام.دوست عزیز این در یک جدول هست. نه دوتا جدول مختلف. در لینکهای بالا نیازی به حلقه هم نیست . خودش مانده رو حساب میکنه. شما اگر 10000000 رکورد داشته باشید بخواهید مانده اونا رو حساب کنید بازهم سرعتش بینهایت بالاست؟؟؟؟
Rejnev
شنبه 01 آبان 1389, 13:35 عصر
چه بهتر! اگه جدول دقيقا به همين شكل باشه كه راحت تره.
در اون پستها جمع رديفهاي قبلي رو هر بار ميگيريم با اين شرط كه idهاشون از فعلي كوچكتر باشه.
درسته كه sum سرعت بسيار بالايي داره. ولي اين كار اگه توي C# صورت بگيره شما فقط ميخواد رديف فعلي رو (واريز يا برداشت) به متغير مجموع اضافه كنيد و در باقيمانده بريزيد.
از لحاظ سرعت بسيار سريعتر از روش قبليست. مثل اينكه يك حلقه فور ساده رو اجرا كنيد. مثل اين حلقه:
for (i=0;i<1 000 000 000;i++)
{
//do nothing
}
//this run form me in 3 seconds (3 GHz cpu)
-------------
//after loading query in a generic list named 'lst' calculate Remaining using this code:
double rem=0;
for(i=0;i<lst.Count;i++)
{
rem+=lst[i].Variz-lst[i].Bardasht;
lst[i].Remaning=rem;
}
فرمولش شايد درست نباشه ولي الگوريتم مهم بود.
حمیدرضاصادقیان
شنبه 01 آبان 1389, 14:23 عصر
سلام.خوب از لحاظ الگوریتم وقتی کاری یک بار انجام میشه سرعت بیشتری داره یا کاری که 1000000 بار ؟!!!
Rejnev
شنبه 01 آبان 1389, 14:37 عصر
اين به مانند مقايسه sum در اس كيو ال و + در C# هست.
اگه فرضا يك ميليون ركورد داشته باشيم. با روش sql اي هر بار بايد sum مقادير ركورد هاي قبلي رو بگيريم. يعني 1 ميليون بار sum.
اما با اين روش، هر بار، به يك متغير مقداري رو اضافه ميكنيم و به قبلي ها كاري نداريم. توجه داريد كه عمل جمع جزو سريعترين اعمال در كامپيوتر است. پس نگراني از بابت حلقه(كه در اون شمارنده يك واحد با مقدار قبليش جمع ميشه) و جمع متغير باقيمانده نميمونه.
اگه فكر ميكنيد اين روش سر بار اضافي داره يا به سرعت قبلي نميرسه كافيه خودتون امتحانش كنيد.
با اين حساب كاري كه دوبار انجام ميشه(يك بار خوندن و يك بار هم محاسبه كردن) سريعتر از كاريه كه 1 ميليون بار انجام ميشه.
حمیدرضاصادقیان
شنبه 01 آبان 1389, 15:41 عصر
سلام.
در sql هم وقتی sum روی مقداری انجام میشه در صورت داشتن index روی اون فیلد این محاسبات در ramصورت می پذیره و مانند یک linked list اطلاعات خوانده شده و باهم جمع می شود.در اینجا یک بحث خوانایی کد هست که یکبار در یک کوئری این جمع انجام میشه ولی در روش فوق دوبار انجام میشه.یک بار 1000000 رکورد کش میشه یک بار دیگه 1000000 بار باید عمل جمل صورت بگیره.در ضمن یک بحث ترافیک شبکه هم هست. شما وقتی دارید روی یک SP کار انجام میدی و فقط نتیجه رو برمیگردونید و بار محاسباتی روی سیستم کلاینت نیز صورت نمیگیره.
درصورتی که اگر عمل تجمیع نیز صورت بگیره با روش استفاده از Sp شما فقط مثلا نیاز هست 1000 رکورد رو برگردونید ولی در روش شما یکبار 1000000 رکورد خوانده شده روش محاسبات انجام می شود و نهایتا 1000 رکورد به کاربر نمایش داده می شود که خود خواندن 1000000 رکورد در شبکه بار اضافی رو به کلاینت تحمیل میکنه.
صرف اینکه بگیم حلقه for سریعتر هست نمیشه یک مساله رو حل کرد.
موفق باشید
Rejnev
شنبه 01 آبان 1389, 16:43 عصر
فكر نميكنم در روش شما هم بشه 1000 ركورد از مثلا 1 ميليون ركورد رو برداشت.
اصلا اين الگوريتم طوريه كه حتما بايد از ابتدا انتخاب صورت بگيره. چون گردش حساب رو ميخوايم از ابتداي پديد اومدن حساب يك شخص محاسبه كنيم.
در ضمن اگه از چند جدول بخوايم محاسبه كنيم كار خيلي سخت ميشه.
دريافت، پرداخت، چك دريافتي پرداختي، درآمدها، هزينه ها و ... روي كوئري تاثير دارن.
براي اينها چيكار بايد كرد.
بايد يك ويو ساخت و همون يونيون رو اجرا كرد و رديف روي كوئري انداخت(rowNumber كه در 2000 نداريم) و در نهايت sum گرفت. اگه از 2000 استفاده كنيم قبلش بايد به تعداد ركوردها رديف و شماره سند ايجاد كنيم تا بتونيم با اين كوئري جوين كنيم و بعد شرط رو بر اساس شماره رديف بزنيم و سام بگيريم.
ولي با كمك سي شارپ تنها تا مرحله union گيري پيش ميريم و بقيه رو ميسپوريم به application.
حالا اگه بخوايم بين دو تاريخ گردش بگيريم بحثش فرق ميكنه. چون هر دو الگوريتم اينجا ميلنگه.
حمیدرضاصادقیان
شنبه 01 آبان 1389, 19:31 عصر
سلام.پس بهتره روی ساختار جداولتون یک بررسی کنید.اگر قرار باشه برای هر سندی یک جدول جداگانه در نظر گرفت که دیگه مصیبت میشه.من همون روشی که عرض کردم روی روی رکوردهای بالای 2-3 میلیون تست کردم و حدودا 4-5 ثانیه زمان برای محاسبه اش نیاز داره. یکی از اصول برنامه نویسی Client-Server این هست که شما بار رو روی Client نیاورده و حتی المقدور جواب رو به کاربر نمایش بدید. در ضمن مشکلات دیگه هم براتون پیش میاد.فرض کنید میخواهید همین کوئری رو اصلاح کنید.در روش شما مجبورید اگر 20 کاربر دارید هر 20 نسخه رو بروز کنید در روشی که من گفتم کافیه فقط دیتابیس بروز بشه. و هزاران دلیل دیگر.
Rejnev
شنبه 01 آبان 1389, 19:57 عصر
بر عكس اين جور موارد (موردي كه بنده گفتم) اگه بياد سمت كلاينت بهتره. بار از روي سرور هم برداشته ميشه. چون اين گزارش فقط حالت نمايشي داره و به راحتي هم قابل محاسبه ست و دليلي نداره سرور وقتش رو روي اين موارد بذاره.
در مورد ساختار جداول هم درسته كه اگه از كدينگ استفاده بشه ميشه تعداد جداول اسناد رو به حداقل رسوند(1) و گزارش رو خيلي راحت گرفت.
vBulletin® v4.2.5, Copyright ©2000-1404, Jelsoft Enterprises Ltd.