ایپدا  مقالات آموزشی مقالات SQLSERVER جاي دیتا درون جداول ديتابيس است، نه درون کدی که می نویسیم
جاي دیتا درون جداول ديتابيس است، نه درون کدی که می نویسیم

در اين نوشته مي خواهم روی این نکته تاکید و توصيه کنم که: حداکثر سعی خود را بکنید تا تمام داده هایی را که به دیتابیس مربوط می شود درون جدول ها ذخیره کنید.
می دانم که می گویید اینکه خیلی واضح است! اما اگر متوجه شويد که چه مقدار از دیتای اپلیکیشن تان در عوض آنکه درون جدول های دیتابیس شما _جایی که به آن تعلق دارند_ باشند درون کد قرار گرفته اند، حتما تعجب خواهید کرد!

مثال شماره 1
شرکتی 3 شیفت در روز تعریف می کند: شیفت 1 از 12:00 صبح–8 صبح، شیفت 2 از 8 صبح-4 عصر، شیفت 3 از 4 عصر-12 صبح. بنابراین اگر بخواهید یک متغیر از نوع DateTime را محاسبه کنید تا ببینید در کدام شیفت قرار گرفته می نویسید:

SELECT ..., CASE 
            WHEN Hour(SomeDate) <  8 THEN 1
            WHEN Hour(SomeDate) < 16 THEN 2
            ELSE 3
       END as ShiftNo
FROM ...

فوق العاده است، فقط الان دیتا را درون کد ذخیره کرده اید – نه درون یک جدول! بیایید با ساختن جدولی با نام "Shifts" دیتا را جایی ذخیره کنیم که به آنجا تعلق دارد:

Shifts


ShiftNo (PK) StartHour

EndHour

Description

1 0 7 Morning
2 8 15 Day
3 16 23 Night

و حالا به سادگي مي نويسيد:


 SELECT ...., Shift.ShiftNo, Shift.Description
FROM ...
INNER JOIN Shift
  ON Hour(SomeDate) BETWEEN Shift.StartHour and Shift.EndHour

به این ترتیب می توانید توضیحات، مدیران شیفت ها، تنظیم محاسبات و هر چیز دیگری که به یک شیفت مربوط می شود را هم به جدول اضافه کنید. علاوه بر این می توانید از این جدول Shift برای تهیه گزارش استفاده کنید و حالا دیگر اگر بخواهید تعداد شیفت ها را به 4 عدد تغییر دهید، باید دیتا را تغییر دهید و هیچ لازم نیست کد را دست کاری کنید. حتی از این هم بهتر اینکه می توانید یک فلگ "WeekEnd" (پايان هفته) یا ستون "WeekDay" (روز هفته) به جدول شیفت اضافه کنید تا امکان تعریف شیفت های مختلفی را برای روزهای مختلف هفته فراهم کنید؛ ستون های بیشتری برای موارد ديگر اضافه كنيد. حتي با اضافه كردن ستونهاي StartDate/EndDate به كليد اوليه اين جدول، مي توان تغييرات را از نظر تاريخي ارائه و بصورت مشخص مستند كرد.


(نكته: طبعا" اين يك مثال بسيار ساده است، گو اينكه شيفت ها معمولا تا پاسي بعد از نيمه شب ادامه دارند (!)، اما در اينجا براي آنكه مفهوم اصلي را درك كنيد از آن استفاده كردم.)

مثال شماره 2

شركتي پاداش ها را بر اساس نوع كارمند پرداخت مي كند: مديران 10% حقوق ساليانه، كارمندان عادي 7% و سرپرست ها 5%. بنابراين براي محاسبه پاداش، خيلي ساده مي نويسيد:
SELECT ..., Salary * CASE EmpType WHEN 'Manager' THEN .10 
                                  WHEN 'Regular' THEN .07 
                                  WHEN 'Admin' THEN .05 
                                  ELSE 0 
                     END as Bonus
FROM ...

ضمنا" در گزارش پرسنل هميشه مي خواهيد اول از همه مديران را فهرست كنيد، بعد كارمندان عادي و پس از آن سرپرست ها را؛ نمي توانيد آنها را برحسب حروف الفبا مرتب كنيد، بنابراين مي نويسيد:
SELECT ...
FROM ...
ORDER BY CASE EmpType WHEN 'Manager' THEN 1 
                      WHEN 'Regular' THEN 2 
                      WHEN 'Admin' THEN 3
                      ELSE 4
         END ASC


خيلي خوب كار مي ده! اما شما يك جدول با عنوان EmployeeType (نوع كارمندان) داريد، درسته؟ اگر نداريد الان وقتش است كه ايجادش كنيد. حتي اگر چنين جدولي هم داشتيد، به خاطر داشته باشيد كه داده ها را در جدول قرار بدهيد، نه كد:

EmpType (PK)

BonusPct

Sort

'Manager'

.10

1

'Regular'

.07

2

'Admin'

.05

3


حالا يك join ساده به اين جدول آنچه كه نياز داريد را به شما تحويل مي دهد. ديگر در SELECT ي كه مي نويسيد نه به CASE هاي بيشتري احتياج است و نه به كدهاي دشوار-دشوار! به علاوه الان تغيير درصدها يا ايجاد انواع جديد كارمندان با ويرايش محتواي جداول ميسر است و به هيچ وجه نيازي به اصلاح كد نيست. خيلي ساده و روشن است، نه؟ البته هميشه هم نه!

مثال شماره 3

در يك شركت محصولات خاصي نبايد در گزارش هاي ساليانه نمايان شوند، زيرا داخلي هستند، تمام شده اند يا براي اهداف آزمايشي استفاده شدند. در گزارشها براي مقادير مشخصي استثناء قائل مي شويم و اين كار را به سادگي تمام انجام مي دهيم، مگر نه؟
SELECT ..
FROM ...
WHERE ProductTypeID Not IN (24,203,1,293)

خيلي ساده است و خوب هم جواب مي ده! اما فكر مي كنم بدانيد كه چه مي شود – چرا اين داده ها را در كد ذخيره كنيم وقتي بايستي در جدولي كه براي نوع محصول داريم نگهداري شوند؟ يك ستون ناقابل يا چند شاخص ديگر به جدول اضافه كنيد تا در بخش ديتا اين اقلام را مشخص كنند تا بتوانيد اين مقادير را از كدتان برداريد. حتي اگر نمي توانيد جدول ProductTypes (انواع محصولات) را ويرايش كنيد، با ساختن يك جدول جديد قادر خواهيد بود اين كار را انجام دهيد:

ProductTypeID (PK, FK)

Notes

24

'Testing'

203

'Converted to product type #12'

1

'Internal'

293

‘Testing’


به كمك چنين جدولي، با يك LEFT OUTER JOIN به اين جدول مي توانيد بفهميد چه زماني بايد براي يك مورد خاص استثناء قائل شد:
SELECT ...
FROM ...
LEFT OUTER JOIN ProductTypeExclusions PEX 
  ON ...
WHERE PEX.ProductTypeID is NULL 

حالا در بخش ديتايمان درباره اينكه چه نوع محصولاتي بايد مستثني شوند (و چرا) مستندسازي داريم و به آساني مي توانيم بدون كامپايل دوباره كد، تغييرات انجام دهيم و حتي با استفاده از اين جدول گزارش بنويسيم. مي توانيم به اين جدول دامنه تاريخ يا فاكتورهاي ديگري اضافه كنيم كه مشخص كنند ProductTypes (انواع محصولات) خاصي چه موقع در گزارشهايمان ظاهر شوند و يا حذف گردند.
به عنوان يك اثر جانبي خوب ديگر، عبارت SELECT به روشني به ما مي گويد كه چرا داريم اقلام خاصي را از گزارش مستثني مي كنيم و ديگر لازم نيست ندانيم ليست بزرگي از ID ها چه معني دارند!

مثال شماره 4

و سرانجام اينكه با دقت بيشتري جداول "look-up" را مطالعه كنيد. ما همه از آنها استفاده مي كنيم – اين جدولها روش فوق العاده اي براي ايجاد فهرستي از مقادير معتبر براي ستون هاي خاص هستند؛ و اغلب بيش از اين كاري انجام نمي دهند:

StatusCode (PK)

Description

A

Approved

P

Preliminary

R

Rejected

D

Deleted

H

Archived


اگر جدولي مانند جدول بالا در سيستم تان داريد دستتان را بالا ببريد! اما واقعا" اين جدول به خودي خود چه چيزي به ما مي گويد؟ معني واقعي 'Rejected' چيست؟ براي فهميدن اين مطلب معمولا" بايد به اپليكيشن يا كد T-SQL ي كه نوشتيم نگاه بيندازيم. در آنجا كدهايي مانند اينها نوشتيم:
... WHERE StatusCode IN ('A','H') ... هر چه كه معتبر باشد را بر مي گرداند
... IF StatusCode NOT IN ('P','R','A') THEN ... مواردي كه نمي توان ويرايش كرد
... WHERE StatusCode IN ('P','R') ... تمامي اشيائي را كه مي توان بازنگري كرد نشان مي دهد
... IF StatusCode IN ('P','R') THEN ... اجازه حذف آنرا مي دهد
و الي آخر... (توجه داشته باشيد كه اوضاع از اين هم بدتر مي شود وقتي از شناسه ها (ID) به عنوان PK اين جدول جستجو استفاده مي كنيم، اما شرح اين موضوع خود يك مقاله را در بر مي گيرد!) اين نيز يك مثال بسيار ساده است و ممكن است مفهوم قسمتي از اين كدها را متوجه نشويد، اما منظور اصلي را در مي يابيد.
اما ما درحقيقت اينجا چه مي كنيم؟ مقصود اين جدول Status چيست؟ آيا از آن به حد وافر بهره مي گيريم؟ آيا واقعا بايد ديتا(مقادير كد وضعيت) را با درون كدمان بگنجانيم؟ اگر بخواهيم وضعيت جديد اضافه كنيم چه اتفاقي مي افتد؟ بار ديگر جواب واضح است: سعي كنيد داده ها را تا حد امكان در جدول ها ذخيره كنيد و آنرا از كد بيرون بكشيد. ممكن است اين مثال در نگاه اول به آساني قابل درك نباشد، اما با دقت آنرا ملاحظه كنيد:

StatusCode (PK)

Description

IsValid

IsEditable

IsReviewable

IsDeletable

A

Approved

1

1

0

0

P

Preliminary

0

1

1

1

R

Rejected

0

1

1

1

D

Deleted

0

0

0

0

H

Archived

1

0

0

0


به ناگهان جدول StatusCodes (كد وضعيت ها) تعاريف بسيار روشني از اينكه معني حقيقي اين كدها چيست (خودش خود را به خوبي مستند مي كند!) و نحوه استفاده اپليكيشن و گزارشها از آنها را در خود دارد. اگر به ازاي هر يك از اعمال اصلي مختلفي كه برنامه مي تواند انجام دهد ستوني در اين جدول در نظر بگيريم، تقريبا هرگز لازم نخواهد شد هيچ ديتايي زا به كدمان اضافه كنيم، اما در عوض داده ها در جدول ها زندگي مي كنند! حالا با يك JOIN ساده به جدول Status مي توانيم بنويسيم:
...
WHERE IsValid =1 ...
IF isEditable = 0 THEN ...
... WHERE isReviewable = 1 ...
IF isDeleteable = 1 THEN ...

و غيره. اكنون مي توانيم كدهاي وضعيت را تغيير بدهيم، كدهاي جديد ايجاد كنيم و آنها را مجددا دسته بندي كنيم – همه اين كارها را در بخش ديتا انجام مي دهيم.

نتيجه گيري

تا آنجا كه به نظر مي رسد تمامي موارد بالا يك سري مطالب بديهي و روشنتر از روزند! با اين حال براي همه ما گاهي پيش مي آيد بيش از مقداري كه بايد در كدمان ديتا وارد مي كنيم، بعضي اوقات چون اين كار سريعتر است و معطلي كمتري دارد و برخي اوقات هم چون نمي توانيم نموداري را كه طراحي كرده ايم تغيير بدهيم، اما بيشتر اوقات به اين علت است كه از پيش براي پياده سازي، آن مقدار كه بايد برنامه ريزي نكرده ايم.
اميدوارم اين نوشته توانسته باشد ايده هايي درباره راههايي كه مي توان به وسيله آن ديتا را بيشتر در جايي كه بايد – درون جدول ها -- قرار داد ارائه كند. به اين ترتيب كد مختصرتر و قابل فهم تري خواهيد داشت و خواهيد ديد كه ناخودآگاه داده هايتان در واقع سيستم شما را به خوبي مستندسازي مي كنند و اين امكان را فراهم مي كنند كه هنگام انجام اصلاحات گسترده، تغييرات تنها در جدول ها اعمال شوند.

ضمیمه ها :



آیا برایتان مفید بود ؟     

دریافت مقاله :

درباره نویسنده

محسن کاویانی
از سال 1383 به صورت تخصصی وارد دنیای برنامه نویسی شده است و بعد از سه سال تخصص خود را در حوزه SQL Server افزایش داده و موفق به اخذ مدرک MCSE از مایکروسافت شده است. وی در این سالها در سمت های مشاور، مدرس و مدیر دیتابیس (DBA) در شرکتها و نهادهای دولتی و خصوصی بزرگ و کوچک مشغول به کار بوده است. برای دریافت روزمه ایشان اینجا را کلیک نمایید

نظرات

محسن کاویانی1394/12/11

تست
<br/>&lt;br/&gt;اینتر
<br/>&lt;br/&gt;سیستماتیک
خیلی اینتر کار رو بد خراب میکنه

پاسخ    

محسن کاویانی1394/12/12

این نظر بنده است

حذف     ویرایش
محسن کاویانی1394/12/11

نظر دوم
سر دوم نظر دوم

پاسخ    

محسن کاویانی1394/12/11

پاسخ در پاسخ نظر نوم

حذف     ویرایش
محسن کاویانی1394/12/11

پاسخ در پاسخ نظر نوم

حذف     ویرایش
محسن کاویانی1394/12/11

نظر سوم

پاسخ    

محسن کاویانی1394/12/12

sda

حذف     ویرایش

درباره IPDA

شرکت ایده پردازان دنیای داده که با نام تجاری ایپدا فعالیت می کند، شرکتی است نوپا اما با کوله باری از تجربیات و ایده های نوین اعضایی که هر کدام سابقه ی طولانی و موفق در زمینه ی فعالیت خود دارند


اطلاعات بیشتر