PDA

View Full Version : یه سلکت به عنوان مرجع برای چند تا سلکت تو در تو



aghayex
چهارشنبه 08 تیر 1390, 15:38 عصر
با سلام خدمت دوستان
یه دستور سلکت دارم که شامل چند سلکت تو در تو هست و برای ارزیابی استفاده می کنم





select count(t) from (select t from t1 where d>@d)where d>10 and d<20
union all
select count(t) from (select t from t1 where d>@d)where d>20 and d<30
union all
select count(t) from (select t from t1 where d>@d)where d>30 and d<40
union all
select count(t) from (select t from t1 where d>@d)where d>40 and d<50


به نظر خودم با این دستور چهار بار به جدول t1 مراجعه می شه حالا سوالم اینکه که آیا راهی هست که بشه من این بخش (select t from t1 where d>@d) رو به عنوان یه جدول مجازی در همین دستور تعریف کنم و به صورت زیر در بیاد






(select t from t1 where d>@d) as tt1
select count(t) from tt1 where d>10 and d<20
union all
select count(t) from tt1 where d>20 and d<30
union all
select count(t) from tt1 where d>30 and d<40
union all
select count(t) from tt1 where d>40 and d<50


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

محمد سلیم آبادی
جمعه 10 تیر 1390, 03:18 صبح
زمانی که یک جدول یکسان در کوئری بارها بهش ارجاع داده میشه در این حالت بسیار ساده تر هست که از یک cte استفاده بشه.
یعنی بر اساس کدی که فرستادین دارین:

with MyCte
AS
(select t
from t1
where d>@d
)
select count(t) from MyCte
where d>10 and d<20
union all
select count(t) from MyCte
where d>20 and d<30
union all
select count(t) from MyCte
where d>30 and d<40
union all
select count(t) from MyCte
where d>40 and d<50;
با این کار در سرعت بهبودی حاصل نمیشه ولی کد خواناتر و ساده تر خواهد شد. در واقع برای پی بردن به این موضوع کافیه Execution Plan های هر دو کوئری (با derived table که همون کوئری اول و با cte) رو با هم مقایسه کنید. خواهید دید که یک plan یکسان برای هر دو کوئری تولید شده است.

از طرفی چرا بجای کوئری فوق از این کوئری استفاده نمی کنید؟

select count(t) from MyCte
where d > 10
and d < 50
and d not in (20, 30, 40)
and d > @d;

aghayex
جمعه 10 تیر 1390, 10:22 صبح
ممنون از جوابتون
در مورت علت زیاد ارجاع ها ، هر کدوم از سلکت ها مربوط به یک ماه میشن و در بعضی از حالات 12 ماه سال قرار می گیرن که 12 بار ارجاع به یک جدول در یک لحظه اون اگر تعداد رکوردها بالای 2000 باشه خیلی فشار به سیستم میاره حالا موندم چکار کنم

behrouzlo
جمعه 10 تیر 1390, 23:36 عصر
اگر به صورت زیر نوشته بشود خروجی برای شما قابل استفاده خواهد بود یا نه ؟

select Case When d > 10 And d < 20 Then COUNT(*) else 0 End,
Case When d > 20 And d < 30 Then COUNT(*) else 0 End,
Case When d > 30 And d < 40 Then COUNT(*) else 0 End,
Case When d > 40 And d < 50 Then COUNT(*) else 0 End,
from t1 where d>@d

محمد سلیم آبادی
شنبه 11 تیر 1390, 02:54 صبح
اگر به صورت زیر نوشته بشود خروجی برای شما قابل استفاده خواهد بود یا نه ؟

select Case When d > 10 And d < 20 Then COUNT(*) else 0 End,
Case When d > 20 And d < 30 Then COUNT(*) else 0 End,
Case When d > 30 And d < 40 Then COUNT(*) else 0 End,
Case When d > 40 And d < 50 Then COUNT(*) else 0 End,
from t1 where d>@d


اولش فکر کردم با روش درستی مساله رو حل کردین ولی دیدم که نه کوئری که نوشتین اصلا قابل اجرا نیست. شما بایستی به جای کد زیر کد بعدی رو می نوشتین:

case when d > 10 and d < 20 then count(*) else 0 end

count(case when d > 10 and d <20 then d end)

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

ممنون از جوابتون
در مورت علت زیاد ارجاع ها ، هر کدوم از سلکت ها مربوط به یک ماه میشن و در بعضی از حالات 12 ماه سال قرار می گیرن که 12 بار ارجاع به یک جدول در یک لحظه اون اگر تعداد رکوردها بالای 2000 باشه خیلی فشار به سیستم میاره حالا موندم چکار کنماگه دقیق متوجه منظورتون شده باشم. شما می تونید از تکینک های pivoting و unpivoting همزمان استفاده کنید.
یعنی کد زیر معادل کد اولی هست که پست کردین ولی بسیار موثر تر:

select d.i
from
(select count(case when d>10 and d<20 then d end),
count(case when d>20 and d<30 then d end),
count(case when d>30 and d<40 then d end),
count(case when d>40 and d<50 then d end)
from tablename where d>@d
)c(a,b,c,d)
cross apply
(values (a), (b), (c), (d)
)d(i);

behrouzlo
شنبه 11 تیر 1390, 10:04 صبح
اره حق با شما است من با برداشتی ذهنی قبل کوئری بالا را نوشتم و بر اساس دیتابیسی که در ذهنم بود که البته باید یک group by می خورد تا درست اجرا بشود

aghayex
دوشنبه 13 تیر 1390, 17:52 عصر
اگه من قبل از تابع count() یه فیلد داشته باشم انو چطور مثل توابع count زیر هم قرار بدم
مثلا خروجی مثل

10 فروردین
20 اردیبهشت
15 خرداد

کد برا ستون اعداد شد این :



SELECT d.i
FROM (SELECT COUNT(CASE WHEN tt > 10 AND tt < 20 THEN tt END) AS b, COUNT(CASE WHEN tt > 20 AND
tt < 30 THEN tt END) AS d,COUNT(CASE WHEN tt > 30 AND tt < 40 THEN tt END) AS f
FROM dbo.ttt
WHERE (tt > 10) AND (tt < 40)) AS c( b, d, f)
cross apply(values (b), (d), (f))d(i)


حالا اگه خروجی مثل مثال بالا داشته باشم cross apply گیر میده
ممنون

محمد سلیم آبادی
جمعه 17 تیر 1390, 19:51 عصر
متاسفم برای وقفه ای که پیش اومده.
اینکه به ترتیب ستون ها مربوط به چه ماه هایی میشن که مشخص هست. پس کافیه این اصلاح رو روی cross apply انجام بدین:

SELECT d.i, d.j
FROM (SELECT COUNT(CASE WHEN tt > 10 AND tt < 20 THEN tt END) AS b,
COUNT(CASE WHEN tt > 20 AND tt < 30 THEN tt END) AS d,
COUNT(CASE WHEN tt > 30 AND tt < 40 THEN tt END) AS f
FROM dbo.ttt
WHERE (tt > 10)
AND (tt < 40)
) AS c( b, d, f)

cross apply(values (b, 'FirstMonth'), (d, 'SecondMonth'), (f, 'ThirdMonth'))d(i,j) ;

فقط به جای اولین، دومین و سومین ماه که به صورت رشته نوشتم عبارات ثابت مورد نظر که با حروف فارسی هستند رو بنویسید.