mojtaba @ ۱۷ شهريور ۱۳۸۶-۱۲:۲۱

dynamically number rows in a SELECT

سلام. يك قرني بود كه به اينجا سر نزده بودم. راستش رو بگم بيش از اون درگيريم كه حتي ايميل هام رو هم چك كنم. اما مي خواهم نتيجه اين همه درگيري اين يك ساله رو كه خيلي مطالب مختلفي هم بهم ياد داد رو يواش يواش همينجا بنويسم. فكر كنم 10-20 تا مقاله بشه البته اگه حوصله كنم و بنويسم. خوب اين از اوليش :
خيلي وقت ها اتفاق مي افتد كه به شماره رديف انتخابي در يك SELECT‌ احتياج پيدا مي كنيم. چند تا روش مختلف وجود داره كه همه براي MS SQL 2000,2005 كار مي كنند.
1- اوليش اينه كه خيلي ساده يه ستون Sub Query كه شامل يك ()SUM است، به SELECT اضافه كنيد. اينطوري :
SELECT (SELECT SUM(1) FROM authors WHERE au_Id<=Ath.au_ID) AS Row_No,
Ath.au_lname  FROM authors Ath
البته مشكل اين نوع محاسبه اينه كه حتماً به يك ستون IDENTITY احتياج داره كه بر اساس اون رديف ها رو بشماره كه البته چون معمولاً در همه جدول ها يك همچين چيزي وجود داره مشكلي زيادي پيش نمي آد.ولي اين مسئله باعث كارآيي پايين اين Query‌ مي شه. چرا كه در هر رديف يك بار اين سرجمع حساب مي شه و براي جداول بزرگ احتمالاً با كارايي پاييني همراه خواهد بود.(البته امتحان نكردم  ولي بايستي اينطور باشه.)
 2 - اين دومي يه كمي دردسر داره ولي مطمئناً همه جا كار مي كنه. اون هم اين كه ابتدا يك جدول موقت با يك ستون IDENTITY ايجاد كنيد (1). بعد اطلاعات انتخابي رو در داخل جدول موقت بريزيد (2) بعد هم با يك انتخاب ازجدول اصلي و اين جدول مجازي ستون IDENTITY رو هم انخاب كنيد (3) كه همون شماره رديف تون خواهد بود.البته جدول موقت كه با يك علامت # قبل از اسمش معرفي ميشه در پايان اتصال به Sql server‌ يعني در بستن SQlConnection خود به خود پاك مي شه ولي براي احتياط كه به مشكلي نخوريد (در صورت بسته نبودن اتصال قبلي) در آخر، جدول موقت رو دستي پاك مي كنيم (4) اينجوري :
-- (1)
CREATE TABLE #RowNumber (
RowNumber int IDENTITY (1, 1),
emp_id char(9) )
-- (2)
INSERT #RowNumber (emp_id)
SELECT emp_id
FROM employee
WHERE job_id = 10
ORDER BY lname
-- (3)
SELECT RowNumber, e.emp_id, lname, fname, job_id
FROM #RowNumber r JOIN employee e
ON r.emp_id = e.emp_id
ORDER BY RowNumber
-- (4)
DROP TABLE #RowNumber
خوبي اين روش اينه كه در تمامي جداول مي شه ازش استفاده كرد و از لحاظ Performance هم مشكلي به نظر نمي آد داشته باشه مگر در اطلاعات واقعاً سنگين كه سرور به رم زيادي احتياج پيدا خواهد كرد.
3 - اين روش فقط در 2005 امكان پذيره چون بالاخره عمو بيل فهميده كه به يه همچين چيزي احتياجه و براي اون يك تابع داخلي گذاشته. تابع ()ROW_NUMBER به همبن منظورطراحي شده كه البته يك بخش OVER هم داره در اين بخش يك عبارت ORDER بايد نوشته شود كه چگونگي شماره رديف زدن رو مشخص مي كند و معمولاً مثل ORDER خود SELECT خواهد بود. اينطوري
SELECT Row_Number() OVER (ORDER BY emp_id) as Row_No, emp_id, lname, fname, job_id
FROM employee e
ORDER BY emp_id
روش بسيار عالي و با Performance بسيار عالي است.

نظر|   1

 
 ( Email | Home) @ ۱۳۸۶/۰۶/۱۸ 0۵:۳۷
It's very good Idea.thanks

:نام

:پست الکترونيک

:وب سايت

:پيام