PDA

View Full Version : درخواست مشورت در مورد یک راه حل



reza1357
جمعه 01 دی 1391, 05:26 صبح
سلام و درود فراوان

لطفا یک نگاهی به کد زیر بیندازید :


declare @P001 int= (select WG+Wy*30 from TblSettl where ID = 1)
declare @P002 int= (select MG + Sr + MS from TblSettl where ID = 1 )
declare @P004 int= (select Days*@P002/100 from TblSettl where ID = 1 )
declare @P005 int= (select Wy*@P001/100 from TblSettl where ID = 1 )
declare @P006 int= (select @P004+@P005 from TblSettl where ID = 1)

select @001 as Wk1 , @002 as F_M , @P004 as Days , @P005 as Wy , @P006 as DaysTotal,* from TblSettl where ID = 1)

مجبورم برای انجام یکسری محاسبات و استفاده از مقادیر،یک راه استفاده از روش فوق است و یک راه دیگرش هم استفاده از ساب کوری،کرسور و ...

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

برای پیاده سازی چنین ساختاری با توجه به اهمیت بودن سرعت چه پیشنهاد میکنید.

لطفا در این مورد راهنمایی کنید.

با تشکر

mehdi.mousavi
جمعه 01 دی 1391, 06:18 صبح
سلام.
چرا یک تابع تعریف نمی کنید و در درون اون تابع، این عملیات رو انجام نمیدید (فقط با یک بار Query).
فرضا:

SELECT
@Days = Days,
@Wy = Wy,
@Sr = Sr,
@Ms = MS,
@Wg = WG,
@Mg = MG
FROM
TblSettl
WHERE
ID = 1


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


DECLARE @P001 INT = @Wg + @Wy * 30;
DECLARE @P002 INT = @MG + @Sr + @Ms;
DECLARE @P004 INT = @Days * @P002 / 100;
DECLARE @P005 INT = @Wy * @P001 / 100;
DECLARE @P006 INT = @P004 + @P005


و در نهایت، Resultset نهایی رو تولید کنیم:

SELECT @P001 as Wk1,
@P002 as F_M,
@P004 as Days,
@P005 as Wy,
@P006 as DaysTotal

البته بسته به شرایط، شاید بد نباشه که نیم نگاهی نیز به Computed Column ها (که ممکنه Persisted بودن اونها Performance رو بسیار بالاتر نیز ببره) داشته باشید. بدین ترتیب که P001-P006 رو Computed Persisted Column تعریف کنید.

موفق باشید.

reza1357
جمعه 01 دی 1391, 09:48 صبح
سلام و تشکر از پاسختون


چرا یک تابع تعریف نمی کنید و در درون اون تابع، این عملیات رو انجام نمیدید (فقط با یک بار Query).
فرضا:


SELECT
@Days = Days,
@Wy = Wy,
@Sr = Sr,
@Ms = MS,
@Wg = WG,
@Mg = MG
FROM
TblSettl
WHERE
ID = 1



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

محمد سلیم آبادی
جمعه 01 دی 1391, 12:19 عصر
امید وارم که از اسکیول سرور نسخه 2008 (یا بالاتر اگه وجود داشته باشه) استفاده میکنید.
مشکلتون رو اگر درست متوجه شدم باشم اینه که دائما مقادیر ستون های بعدی به مقادیر ستون های قبلی ارجاع داده میشن(وابستن) که شما برای کوتاه شدن کدتون از اون کدها استفاده کردین.

به این کدی که پست کردین توجه کنید:

declare @P006 int= (select @P004+@P005 from TblSettl where ID = 1)
در اینجا اشتباهتون این هست که از کوئری استفاده کردین در صورتی که اصلا از مقادیر این کوئری استفاده نشده. یعنی اگه کد زیر هم مینوشتین درست بود:

declare @poo6 int = @poo4 + @poo5

در کل من اصلا سراغ اینجور روشها نمیرم که بخوام به مشکل خاصی برخورد کنم. دو تکنیک معرفی میکنم که میتونین ازش بهره ببرین. یکی cross apply هست که عالی عمل میکنه دومیم cte میباشه که اونم عالیه.
فعلا این کد رو امتحان کنین ببینین چطور جواب میده:

select p001 as wk1, p002 as f_m, p004 as days, p005 as wy, p006 as daysTotals, ts.*
from (select * from TblSettl where ID = 1) as ts
cross apply (values (ts.wg+ts.wy*30)) as d1(p001)
cross apply (values(ts.mg+ts.sr+rs.ms)) as d2(p002)
cross apply (values(ts.days*d2.p002/100)) as d4(p004)
cross apply (values(ts.wy*d1.p001/100)) as d5(p005)
cross apply (values(d4.p004+d5.p005)) as d6(p006);

محمد سلیم آبادی
جمعه 01 دی 1391, 12:44 عصر
الان که پست های شماره 2و 3 رو مطالعه کردم متوجه شدم احتمالا مشکلتون رو دقیق متوجه نشدم. این مطالب برام زیاد مفهوم نیست:

بخاطر اینکه تعداد فیلدها مشخص نیستند و همچنین فرمول ها نیز توسط نرم افزار از طریق کد و بصورت پویا تولید می شوند.
هر فرمول هم حداقل یک فیلد و حداکثر n فیلد یا متغیر بستگی به فرمول دارد و نمیشه بصورت پویا فیلدها رو در کد فوق ایجاد کرد.
شما فرمودین تعداد فیلد ها از 1 تا n متغیر هست. خوب در دستور انتسابی که آقای مهدی موسوی در پست 2 ارسال کردن، شما تمام فیلد ها رو به متغیرهای از قبل تعریف شده انتساب بدین. که بعدا با مشکلی مواجه نشین.

در هر صورت به نظرم میرسه بایستی بیشتر شفاف سازی بشه.

reza1357
جمعه 01 دی 1391, 18:35 عصر
سلام و درود فراوان بر شما

تکنیک شما عالی بود مثلا 40 هزار رکورد کمتر از دو ثانیه محاسبه کرد از شما سپاسگزارم.
اگه امکان دارد در مورد cte توضیحی بدید کدهای فوق رو چطوری از این تکنیک پیاده سازی کنم؟

با تشکر

محمد سلیم آبادی
جمعه 01 دی 1391, 20:46 عصر
cte های غیر بازگشتی توضیح خاصی ندارن، به غیر اینکه این امکان رو مهیا میکنند تا به یک کوئری یک نام موقت بدیم تا در کوئری های بعدی ازش استفاده کنیم.
p001 و p002 رو میشه در یک select قرار داد و همچنین p004 و p005 را در یک سلکت دیگه. بر این اساس داریم:

;with ts as
(select * from TblSettl where ID = 1) ,
d1(p001, p002) as (select ts.wg+ts.wy*30, ts.mg+ts.sr+ts.ms from ts),
d4(p004, p005) as (select ts.days*d1.p002/100, ts.wy*d1.p001/100 from ts, d1),
d6(p006) as (select d4.p004+d5.p005 from d4)
select p001 as wk1, p002 as f_m, p004 as days, p005 as wy, p006 as daysTotals, ts.*
from ts,d1,d4,d6;

اگه توجه کرده باشین در کد در قسمت from به جداول قبلی مثل ts و d1 اشاره شده که اسامی با کاما جدا شدن، در واقع چون در هر جدول یک سطر وجود داره من اومدم اونها رو ضرب دکارتی کردم. ضرب دکارتی دو جدول که هر یک دارای یک سطر هستند چیزی جز یک سطر برنمی گرداند.

reza1357
جمعه 01 دی 1391, 23:14 عصر
تکنیک فعلی که استفاده کرده بودم همین cte است تنها مشکلی که دارم در پیچیدگی زمان تولید کد (یا پویا شدن) است و نمیشه از فرمولهای پیچیده در اون استفاده کرد.
فعلا از تکنیک cross apply بجای cte استفاده میکنم بنظر میرسه که در پویا کردنش بهتر و ساده تر از تکنیک cte است امیدوارم که به مشکل بر نخورم.

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