نظرات مطالب
مقایسه رکوردهای دو جدول
در ادامه مطلب جناب نصیری بازبینی پلن اجرائی دو دستور هم جالب توجه است.هر دو دستور یک پلان یکسان دارند ولی دستور Except فشرده‌تر و زیباتر است.
----SQL SERVER 2005 Method
USE AdventureWorks;
GO
SELECT ProductID
FROM Production.Product
EXCEPT
SELECT ProductID
FROM Production.WorkOrder;
GO

----SQL SERVER 2000 Method which works&nbspIN SQL SERVER 2005
USE AdventureWorks;
GO
SELECT ProductID
FROM Production.Product
WHERE ProductID
NOT IN (
SELECT ProductID
FROM Production.WorkOrder);
GO
تصویر پلان اجرائی دو کوئری :

مطالب
ایجاد ایندکس منحصربفرد در EF Code first
در EF Code first برای ایجاد UNIQUE INDEX ویژگی یا تنظیمات Fluent API خاصی درنظر گرفته نشده است و می‌توان از همان روش‌های متداول اجرای مستقیم کوئری SQL بر روی بانک اطلاعاتی جهت ایجاد UNIQUE INDEX‌ها کمک گرفت:
public static void CreateUniqueIndex(this DbContext context, string tableName, string fieldName)
{
      context.Database.ExecuteSqlCommand("CREATE UNIQUE INDEX [IX_Unique_" + tableName 
+ "_" + fieldName + "] ON [" + tableName + "]([" + fieldName + "] ASC);");
}
و این کل کاری است که باید در متد Seed کلاس مشتق شده از DbMigrationsConfiguration انجام شود. مثلا:
public class MyDbMigrationsConfiguration : DbMigrationsConfiguration<MyContext>
{
        public BlogDbMigrationsConfiguration()
        {
            AutomaticMigrationsEnabled = true;
            AutomaticMigrationDataLossAllowed = true;
        }

        protected override void Seed(MyContext context)
        {
            CreateUniqueIndex(context, "table1", "field1");
            base.Seed(context);
        }
}
روش فوق کار می‌کند اما آنچنان مناسب نیست؛ چون به صورت strongly typed تعریف نشده است و اگر نام جداول یا فیلدها را بعدها تغییر دادیم، به مشکل برخواهیم خورد و کامپایلر خطایی را صادر نخواهد کرد؛ چون table1 و field1 در اینجا به صورت رشته تعریف شده‌اند.
برای حل این مشکل و تبدیل کدهای فوق به کدهایی Refactoring friendly، نیاز است نام جدول به صورت خودکار از DbContext دریافت شود. همچنین نام خاصیت یا فیلد نیز به صورت strongly typed قابل تعریف باشد.
کدهای کامل نمونه بهبود یافته را در ذیل مشاهده می‌کنید:
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Objects;
using System.Linq;
using System.Linq.Expressions;
using System.Text.RegularExpressions;

namespace General
{
    public static class ContextExtensions
    {
        public static string GetTableName<T>(this DbContext context) where T : class
        {
            ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;
            return objectContext.GetTableName<T>();
        }

        public static string GetTableName<T>(this ObjectContext context) where T : class
        {
            var sql = context.CreateObjectSet<T>().ToTraceString();
            var regex = new Regex("FROM (?<table>.*) AS");
            var match = regex.Match(sql);
            string table = match.Groups["table"].Value;
            return table
                    .Replace("`", string.Empty)
                    .Replace("[", string.Empty)
                    .Replace("]", string.Empty)
                    .Replace("dbo.", string.Empty)
                    .Trim();
        }

        private static bool hasUniqueIndex(this DbContext context, string tableName, string indexName)
        {
            var sql = "SELECT count(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS where table_name = '" 
                      + tableName + "' and CONSTRAINT_NAME = '" + indexName + "'";
            var result = context.Database.SqlQuery<int>(sql).FirstOrDefault();
            return result > 0;
        }

        private static void createUniqueIndex(this DbContext context, string tableName, string fieldName)
        {
            var indexName = "IX_Unique_" + tableName + "_" + fieldName;
            if (hasUniqueIndex(context, tableName, indexName))
                return;

            var sql = "ALTER TABLE [" + tableName + "] ADD CONSTRAINT [" + indexName + "] UNIQUE ([" + fieldName + "])";
            context.Database.ExecuteSqlCommand(sql);
        }

        public static void CreateUniqueIndex<TEntity>(this DbContext context, Expression<Func<TEntity, object>> fieldName) where TEntity : class
        {
            var field = ((MemberExpression)fieldName.Body).Member.Name;
            createUniqueIndex(context, context.GetTableName<TEntity>(), field);
        }
    }
}

توضیحات
متد GetTableName ، به کمک SQL تولیدی حین تعریف جدول متناظر با کلاس جاری، نام جدول را با استفاده از عبارات باقاعده جدا کرده و باز می‌گرداند. به این ترتیب به دقیق‌ترین نامی که واقعا جهت تولید جدول مورد استفاده قرار گرفته است خواهیم رسید.
در مرحله بعد آن، همان متد createUniqueIndex ابتدای بحث را ملاحظه می‌کنید. در اینجا جهت حفظ سازگاری بین SQL Server کامل و SQL CE از UNIQUE CONSTRAINT استفاده شده است که همان کار ایجاد ایندکس منحصربفرد را نیز انجام می‌دهد. به علاوه مزیت دیگر آن امکان دسترسی به تعاریف قید اضافه شده توسط view ایی به نام INFORMATION_SCHEMA.TABLE_CONSTRAINTS است که در نگارش‌های مختلف SQL Server به یک نحو تعریف گردیده و قابل دسترسی است. از این view در متد hasUniqueIndex جهت بررسی تکراری نبودن UNIQUE CONSTRAINT در حال تعریف، استفاده می‌شود. اگر این قید پیشتر تعریف شده باشد، دیگر سعی در تعریف مجدد آن نخواهد شد.
متد CreateUniqueIndex تعریف شده در انتهای کلاس فوق، امکان دریافت نام خاصیتی از TEntity را به صورت strongly typed میسر می‌سازد.
اینبار برای تعریف یک قید و یا ایندکس منحصربفرد بر روی خاصیتی مشخص در متد Seed، تنها کافی است بنویسیم:
context.CreateUniqueIndex<User>(x=>x.Name);
در اینجا دیگر از رشته‌ها خبری نبوده و حاصل نهایی Refactoring friendly است. به علاوه نام جدول را نیز به صورت خودکار از context استخراج می‌کند.
 
نظرات مطالب
تنظیمات کش توزیع شده‌ی مبتنی بر SQL Server در ASP.NET Core
- اگر با SQL Server کار کرده باشید، حتما دیده‌اید که سرعت اجرای یک کوئری در بار دوم و پس از آن، بسیار بسیار بیشتر از اجرای اول آن است. یکی از مهم‌ترین دلایل آن، به buffer cache مرتبط می‌شود که کارش کش کردن صفحات اطلاعات مرتبط با داده‌های کوئری‌های انجام شده‌است. هر زمانیکه در SQL Server اطلاعاتی از بانک اطلاعاتی خوانده می‌شود، این اطلاعات در RAM سرور هم کپی می‌شوند. نکته‌ی مهم اینجا است که SQL Server هرچقدر RAM را که بتواند برای این منظور مورد استفاده قرار می‌دهد و در این حالت اگر کسی با این نکته آشنایی نداشته باشد یا تصور می‌کند که SQL Server دچار نشتی حافظه شده‌‌است و یا پس از مدتی با کمبود RAM در سرور مواجه خواهد شد. اطلاعات بیشتر
اشتراک‌ها
دومین انقلاب فناوری اطلاعات و ارتباطات در راه است...

کلان‌داده در مسیر تغییر معرفت‌شناسانه جهان است، به گونه‌ای که ما را در مسیر دومین انقلاب فناوری اطلاعات و ارتباطات قرار داده است. 

در حالی که حجم داده‌ها هر لحظه بیشتر می‌شود، رقابت بین مراکز تحلیل داده‌ها جدی‌تر می‌شود. در سال ۲۰۱۷ هر روز حدود چهار اگزابایت داده تولید می‌شود که تا ۱۰ سال پیش غیرقابل تصور بود. بدین ترتیب نقش Data Scientistها به سرعت در حال تغییر است. فارغ‌التحصیلان برجسته جهان در رشته‌های جامعه‌شناسی، مدیریت، آمار، فیزیک و… به عنوان تحلیلگر و داده‌کاو در حال فعالیت در شرکت‌های مالی، تجاری و امنیتی هستند. بنا بر مطالعه استیون وبر (استاد مدرسه فناوری برکلی) با توجه به اهمیت کلان‌داده‌ها و توجه ویژه به داده‌کاوی، در نیمه دوم سال ۲۰۱۷ میلادی، فقط در ایالات متحده به بیش از ۸۵۰ هزار متخصص (Data scientist) دیگر نیاز است 

دومین انقلاب فناوری اطلاعات و ارتباطات در راه است...
مطالب
لینک‌های هفته سوم دی

وبلاگ‌ها ، سایت‌ها و مقالات ایرانی (داخل و خارج از ایران)

ASP. Net

  • ویدیویی درباره‌ی ASP.Net 4 (بهبودهای حاصل شده در web forms از جهت کار با اسکریپت‌ها خصوصا با تاکید بر jQuery و همچنین ذکر اینکه با آمدن ASP.Net MVC ، وب فرم‌ها کهنه نشده‌ و همچنان توسعه و بهبود داده خواهند شد)، یا مقاله‌ای در این مورد

طراحی و توسعه وب

PHP

اس‌کیوال سرور

سی شارپ

عمومی دات نت

مسایل اجتماعی و انسانی برنامه نویسی

متفرقه

مطالب
توابع Window و مساله های آماری running total و runnning average
مقدمه و شرح مساله
توسط ویژگی‌های جدیدی که در نسخه 2012 به بحث window افزوده شد می‌توانیم مسالهای running total و running average را به شکل بهینه ای حل کنیم.
ابتدا این دو مساله را بدون بکارگیری ویژگی‌های جدید، حل نموده و سپس سراغ توابع جدید خواهم رفت.

قبل از هر چیزی لازم است جدول زیر ساخته شود و داده‌های نمونه در آن درج شود:
create table testTable
(
day_nbr integer not null primary key clustered,
value integer not null check (value > 0)
);
insert into testTable
values (10, 7), (20, 15), (30, 3), (40, 9), (50, 17), (60, 25), (70, 10);

مساله running total بسیار ساده است، یعنی جمع مقدار سطر جاری با مقادیر سطرهای قبلی (بر اساس یک ترتیب معین)
running average هم مشابه به running total هست با این تفاوت که میانگین مقادیر سطرجاری وسطرهای قبلی محاسبه می‌شود.


و نتیجه به صورت نمودار:



راه حل در SQL Server 2000
توسط دو correlated scalar subquery در ماده SELECT می‌توانیم مقادیر دو ستون مورد نظر با محاسبه کنیم:
select *,
       runningTotal = (select sum(value)
                         from testTable
                        where day_nbr <= t.day_nbr),
       runningAverage = (select avg(value)
                           from testTable
                          where day_nbr <= t.day_nbr)
  from testTable t;



اگر به نقشه اجرای این query نگاه کنید گره(عملگر) inner join دو بار بکار رفته است (به وجود دو subquery)، که این عدد در روش توابع تجمعی window به صفر کاهش پیدا خواهد کرد



راه حل در SQL Server 2005

توسط cross apply به سادگی می‌توانیم دو subquery که در روش قبل بود را به یکی کاهش دهیم:
select *
  from testTable t
       cross apply (select sum(value) as runningTotal,
                           avg(value) as runningAverage
                      from testTable
                     where day_nbr <= t.day_nbr)d;


این بار تنها یک عملگر inner join در نقشه اجرای query مشاهده می‌شود:

 


راه حل در SQL Server 2012
با اضافه شدن برخی از ویژگی‌های استاندارد به ماده OVER مثل rows و range شاهد بهبودی در عملکرد query‌ها هستیم.
یکی از کاربردهای توابع تجمعی window حل مساله running total و running average است.
به تصویر زیر توجه کنید، همانطور که در قبل توضیح دادم ما به سطرجاری و سطرهای پیشین نیاز داریم تا اعمال تجمعی (جمع و میانگین) را روی مقادیر بدست آمده انجام دهیم. در تصویر زیر سطرجاری و سطرهای قبلی به ازای هر سطری به وضوح قابل مشاهده است، مثلا هنگامی که سطر جاری برابر با روز 30 است ما خود سطر جاری (current row) و تمام سطرهای پیشین و قبلی (unbounded preceding) را نیاز داریم.


و اکنون query مورد نظر
select *, sum(value) over(order by day_nbr rows between unbounded preceding and current row) as runningTotal,
          avg(value) over(order by day_nbr rows between unbounded preceding and current row) as runningAverage
from testTable

در نقشه اجرای این query دیگر خبری از عملگر inner join نخواهد بود که به معنای عملکرد بهتر query است.
 

مطالب
خلاصه‌ای در مورد وضعیت فعلی MySQL

MySQL مدتی است که جزو یکی از محصولات شرکت اوراکل محسوب شده و توسعه دهندگان تجاری باید برای استفاده از آن هزینه کنند. این هزینه نیز اخیرا افزایش یافته و به حداقل 2000 دلار به ازای هر سرور رسیده است (+). این عدد واقعا رقم بالایی برای محصولی محسوب می‌شود که بسیاری از توسعه دهنده‌ها تصور می‌کنند رایگان است. استفاده از این محصول با توجه به مدل تجاری جدید آن فقط در پروژه‌های سورس باز رایگان است (بله فقط در پروژه‌هایی که با مجوز GPL منتشر شوند) و اگر شما یک سیستم تجاری کلاینت سرور را بر این اساس طراحی کنید حتما باید هزینه‌های مرتبط را نیز پرداخت نمائید (+).
توضیحی در مورد GPL و MySQL
MySQL AB offers a commercial license for organizations that do not want to release the source code for their application.
The change from the LGPL to the GPL for the client libraries was made in 2001 during the development of MySQL 4.0 to help MySQL AB more easily differentiate between a proprietary user who should buy a commercial license and a free software user who should use the GPL license.

MySQL با توجه به مجوز GPL آن در شرایط زیر رایگان خواهد بود:
- قصد توزیع مجدد آن‌را نداشته باشید.
- همچنین برنامه‌ی شما نیز به صورت سورس باز تحت مجوز GPL ارائه گردد.
و تنها زمانی در مورد MySQL باید هزینه کنید که:
-قصد توزیع مجدد آن‌را داشته باشید.
-برنامه‌ی شما سورس باز نبوده و قصد ندارید آن‌را تحت مجوز GPL ارائه دهید. (که عموما در مورد برنامه‌های تجاری به همین صورت است)

نکته‌ی دیگری را که باید به آن دقت داشت این است که برای واگذاری MySQL به شرکت اوراکل،‌ اتحادیه اروپا نیز با توجه به وجود بیش از 50 هزار توسعه دهنده‌ی اروپایی که از MySQL استفاده می‌کنند، شرکت اوراکل را موظف کرده است تا این dual licensing (تجاری و سورس باز) را تا سال 2015 حفظ کرده و ادامه دهد (+). به این معنا که شرکت اوراکل پس از سال 2015 هیچگونه تعهدی به ارائه‌ی نگارش سورس باز این محصول به هیچ نهاد و یا سازمانی ندارد.
البته این‌ها به معنای پایان دنیا نیست. هم اکنون چهار fork سورس باز از این محصول وجود دارند (Drizzle ، MariaDB ، OurDelta و Percona Server) ولی تنها آینده است که میزان موفقیت، پایداری و تداوم آن‌ها را مشخص خواهد کرد.

نظرات مطالب
استفاده از Flashback Table در Oracle
با سلام
قابلیتی که اشاره کردید در SQL Server وجود ندارد (در SQL Server می‌توان آن را با Point In Time Restore هم انجام داد) به نظر می‌رسد که با استفاده از این حالت جدول شما حذف منطقی شده و از دسترسی عادی کاربران  خارج می‌گردد (این خوب و هم بد)
خوبی آن در این است که هر موقع خواستید می‌توانید اطلاعات آن را برگردانید
بدی آن هم در این است که فضای مربوط به این جدول هنگام حذف از دیسک آزاد نخواهد شد
مطالب
آموزش MDX Query - قسمت ششم – شروع کار با دستورات MDX

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

  1. نصب پایگاه داده ی Adventure Work DW 2008 و همچنین نصب پایگاه داده‌ی چند بعدی  Adventure Work DW 2008  روی SSAS
  2. مطاله قسمت‌های قبلی برای آشنایی با مفاهیم پایه .

در صورتیکه پیش شرایط فوق را نداشته باشید، احتمالا در ادامه با مشکلاتی مواجه خواهید شد؛ زیرا برای آموزش MDX Query ها از پایگاه داده‌ی Adventure Work DW 2008 استفاده شده است. 

دقت داشته باشید که MDX Query ‌ها تا حدودی شبیه T/SQL  می‌باشند؛ اما مطلقا از نظر مفهومی با هم شباهت ندارند. به عبارت دیگر ما در T/SQL  با یک مدل رابطه‌ای سرو کار داریم در حالیکه در MDX ‌ها با یک پایگاه داده چند بعدی کار می‌کنیم. به بیان دیگر در پایگاه داده‌های رابطه‌ای صحبت از جداول، ردیف‌ها، ستون‌ها و ضرب دکارتی مجموعه‌ها می‌باشد، اما در پایگاه داده‌های چند بعدی در خصوص Dimension,Fact,Cube,Tuple و ... صحبت می‌کنیم. البته ماکروسافت تلاش کرده‌است تا حد زیادی Syntax ‌ها شبیه به یکدیگر باشند.

نحوه‌ی نوشتن یک Select در MDX ‌ها به صورت زیر می‌باشد :

Select
{} On Columns ,
{} On Rows
From <Cube_Name>
Where <Condition>

در ادامه با اجرای هر کوئری، توضیحات لازم در خصوص آن ارایه می‌گردد و با پیگیری این آموزش‌ها می‌توانید مفاهیم، توابع و ... را در MDX Query ‌ها بیاموزید.

برای اجرای دستورات زیر باید Microsoft SQL Server Management Studio را باز نمایید و به سرویس SSAS متصل شوید. سپس پایگاه داده‌ی Adventure Works DW 2008R2 را انتخاب نمایید و از Cubes Adventure Works را انتخاب نمایید.

حال دکمه‌ی New Query را در بالای صفحه بزنید ( Ctrl + N )  

سپس در صفحه‌ی باز شده می‌توانید Cube یا SubCube ‌های آن Cube را انتخاب کرده و کمی پایین‌تر Measure Group را خواهیم داشت و در انتها Measure ‌ها و Dimension ‌ها قرار گرفته‌اند. (در هنگام نوشتن Select می‌توان از عمل Drag&Drop برای آسان‌تر شدن نوشتن MDX Query ‌ها نیز استفاده کنید)

متاسفانه هنوز در IDE مربوط به SQL Server کلیدی برای مرتب سازی دستورات MDX وجود ندارد و البته در نرم افزار هایی مانند SQL Toll Belt هم چنین چیزی قرار داده نشده است . بنابر این توصیه می‌شود در نوشتن دستورات MDX تمام تلاش خود را بکنید تا دستوراتی مرتب و خوانا را تولید کنید.

با اجرای دستور زیر اولین کوئری خود را در پایگاه داده‌ی چند بعدی بنویسید (برای اجرا کلید F5 مانند T/SQL کار خواهد کرد.)

Select
From [Adventure Works]

شاید تعجب کنید. کوئری فاقد قسمت Projection می‌باشد! در MDX ‌ها می‌توان هیچ سطر یا ستونی را انتخاب نکرد. اما چگونه؟ و خروجی نمایش داده شده چیست؟

برای توضیح مطلب فوق باید در خصوص Default Measure کمی اطلاعات داشته باشید. در هنگام Deploy کردن پروژه در SSAS برای هر Cube یک Measure به عنوان Measure پیش فرض انتخاب شده. بنابر این در صورتیکه هیچ گونه Projection یا Where ایی اعمال نشده باشد، SQL Server به صورت پیش فرض مقدار Mesaure پیش فرض را بدون اعمال هیچ بعدی نمایش می‌دهد.

خروجی دستور بالا مشابه تصویر زیر می‌باشد. 

حال دستور زیر را اجرا می‌کنیم :

Select
From [Adventure Works]
Where [Measures].[Reseller Sales Amount]

تصویر خروجی به صورت زیر می‌باشد : 

شاید باز هم تعجب کنید. نوشتن نام یک شاخص به جای عبارت شرط؟! آیا خروجی عبارات شرطی نباید Boolean باشند؟

خیر. اگر چنین پرسش هایی در ذهن شما ایجاد شده باشد، به دلیل مقایسه‌ی MDX با T/SQL می‌باشد. در اینجا شرط Where بر روی ردیف‌های جدول مدل رابطه ای اعمال نمی‌شود و عملا بیانگر واکشی اطلاعات از مدل چند بعدی می‌باشد. با اعمال شرط فوق به SSAS اعلام کرده ایم که خروجی بر اساس شاخص [Measures].[Reseller Sales Amount] باشد. با توجه به این که شاخص انتخاب شده با شاخص پیش فرض یکی می‌باشد خروجی با حالت قبل تفاوتی نخواهد کرد.

برای درک بهتر، کوئری زیر را اجرا کنید :

Select
From [Adventure Works]
where [Measures].[Internet Sales Amount]

استفاده از این شرط سبب استفاده نشدن از شاخص پیش فرض می شود . به عبارت دیگر این کوئری دارای سرجمع مبلغ فروش اینترنتی می باشد.

دستور زیر را اجرا کنید :

Select
[Measures].[Reseller Sales Amount] on columns
From [Adventure Works]

با اعمال یک شاخص خاص در ستون ، عملا فیلترینگ انجام می شود 

استفاده از یک دایمنشن در ستون :

دستور زیر را اجرا کنید

Select
[Date].[Calendar].[Calendar Year] on columns
From [Adventure Works]

خروجی به شکل زیر خواهد بود 

همان طور که مشاهده می‌کنید خروجی دارای چندین ستون می‌باشد و دارای مقادیری در هر ستون. اما این مقادیر از کجا آمده اند؟

همواره این نکته را به خاطر بسپارید که در صورت عدم ذکر نام یک Measure در کوئری ، SSAS از Measure پیش فرض استفاده می‌کند. حال کوئری فوق میزان فروش نمایندگان ( Reseller Sales Amount ) را در هر سال نمایش می‌دهد.

سوال بعدی این می‌باشد که این سال‌ها از کجا آمده اند؟ خوب برای درک بهتر این مورد می‌توانیم مانند تصویر زیر به دایمنشن Date رفته و در ساختار سلسله مراتبی ، اعضای سطح [Date].[Calendar].[Calendar Year] را مشاهده کنیم. 

ایجاد سرجمع ستون‌ها :

کوئری زیر را اجرا نمایید

Select

{[Date].[Calendar].[Calendar Year],[Date].[Calendar]} on columns

From [Adventure Works]

بعد از اجرا تصویر زیر را خواهید دید : 

سوال اول این می‌باشد که کاربرد {} در انتخاب دایمنشن‌ها چیست؟ در پاسخ می‌توان گفت که اگر شاخص ها یا بعد ها ، مرتبط به یک سلسله مراتب باشند آنها را در یک {} قرار می دهیم ولی اگر سلسله مراتب متفاوت باشد، یا بعد و شاخص باشند باید در () قرار بگیرند .

خوب همان طور که مشخص است در ساختار سلسله مراتبی ابتدا سال و بعد یک سطح بالا‌تر را انتخاب کرده ایم این به معنی نمایش سرجمع در سطح بالا‌تر از سال می‌باشد(سرجمع تمامی سال ها).

استفاده از دایمنشن و Measure در سطر و ستون مجرا :

کوئری زیر را اجرا نمایید

Select
{[Date].[Calendar].[Calendar Year],[Date].[Calendar]} on columns,
[Product].[Product Categories].[Category] on rows
From [Adventure Works]

خروجی مشابه شکل زیر می‌باشد 

در مثال فوق از بعد‌ها در ستون و همزمان، نمایش نوع دسته بندی محصولات در ردیف‌ها استفاده شده است. به عبارت دیگر نتیجه عبارت است از فروش نماینگان فروش ( Reseller Sales Amount ) براساس هر سال به تفکیک نوع دسته بندی محصول فروخته شده.

(کسانی که چنین گزارشی را با استفاده از T/SQL نوشته اند، احتمالا از آسانی نوشتن این گزارش توسط MDX ‌ها شگفت زده شده اند.)

قراردادن فیلد سرجمع در ردیف :

برای این منظور کوئری زیر را اجرا نمایید

Select
{[Date].[Calendar].[Calendar Year],[Date].[Calendar]} on columns,
{[Product].[Product Categories].[Category],[Product].[Product Categories]}on rows
From [Adventure Works]

خروجی به صورت زیر می‌باشد 

نحوه‌ی نمایش سرجمع در ردیف، مشابه نمایش سرجمع در ستون می‌باشد.

استفاده از تابع non empty  :

برای حذف ستون هایی که کاملا دارای مقدار null می‌باشند به صورت زیر عمل می‌کنیم :

Select
non empty {[Date].[Calendar].[Calendar Year],[Date].[Calendar]} on columns ,
{[Product].[Product Categories].[Category],[Product].[Product Categories]} on rows
From [Adventure Works]

خروجی به صورت زیر می‌باشد:

انتخاب دو دایمنشن در سطر و ستون و مشخص نمودن یک Measure خاص برای کوئری :

برای این کار به صورت زیر عمل خواهیم کرد:

Select
{[Date].[Calendar].[Calendar Year],[Date].[Calendar]} on columns,
{[Product].[Product Categories].[Category],[Product].[Product Categories]} on rows
From [Adventure Works]
Where [Measures].[Internet Sales Amount]

در اینجا با اعمال شرط Where عملا از SSAS خواسته‌ایم خروجی برای شاخص مشخص شده واکشی شود.

در بالا میزان فروش اینترنتی برای دسته بندی محصولات و در سال‌های مختلف ارائه و همچنین سرجمع ستون و سطر نیز نمایش داده شده است. 

در صورتیکه بخواهیم ستون و سطرهایی را که دارای مقدار null در تمامی آن سطر یا ستون می‌باشند، حذف کنیم به صورت زیر عمل می‌کنیم:

Select
non empty {[Date].[Calendar].[Calendar Year],[Date].[Calendar]} on columns,
non empty {[Product].[Product Categories].[Category],[Product].[Product Categories]} on rows
From [Adventure Works]
Where [Measures].[Internet Sales Amount]

اگر در یک دایمنشن فقط یک سلسله مراتب باشد یا اصلا سلسله مراتبی وجود نداشته باشد، می‌ توان از نام خود دایمنشن استفاده کرد

Select
[Sales Channel] on columns
From [Adventure Works]

و دقت داشته باشید دایمنشنی که دارای بیش از یک سلسله مراتب باشد، حتما باید در  Select مشخص شود که از کدام سلسله مراتب می خواهیم استفاده کنیم .در غیر این صورت  با خطا مواجه خواهیم شد.

Select
[Product] on columns
From [Adventure Works]

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

Select
[Product].[Category] on columns
From [Adventure Works]

Select
[Product].[Category].[all]   on columns
From [Adventure Works]
--
Select
[Product].[Category].[All] on columns
From [Adventure Works]
--
Select
[Product].[Category].[(all)] on columns
From [Adventure Works]
--
Select
[Product].[Category].[all products] on columns
From [Adventure Works]

برای به دست آوردن سرجمع کل روی یک صفت از دایمنشن، باید از سه حالت آخر استفاده کرد. حالت اول خطا دارد و خروجی خالی نمایش داده می شود .

در صورتی که بخواهیم از یک دایمنشن تمامی Member ‌های آن را واکشی کنیم به صورت زیر عمل خواهیم کرد

Select
{[Product].[Category].members} on columns
From [Adventure Works]

استفاده از Members روی یک خصوصیت در دایمنشن به معنی دریافت سرجمع آن صفت و سپس تک تک اجزای آن  صفت می‌باشد.

اگر از یک صفت واکشی اطلاعات انجام شود در سطح اعضای آن، در آن صورت دیگر سرجمع نمایش داده نمی شود و فقط جمع هر عضو در آن صفت نمایش داده می شود .

Select
[Product].[Category].[Category].members
-- dimension.hierarchy.level.members
on columns
From [Adventure Works]

اگر بخواهیم دو ستون را داشته باشیم که هر دو برای یک دایمنشن می‌باشند باید از {} استفاده کرد . دستور اول خطا خواهد داشت.

Select
[Product].[Category].[Category].members,[Product].[Category].[All Products] on columns
From [Adventure Works]

در دستور دوم با استفاده از {} خروجی نمایش داده می‌شود که عبارت است از تمامی اعضای سطح [Product].[Category].[Category]. به همراه سرجمع تمامی محصولات.

Select
{[Product].[Category].[Category].members,[Product].[Category].[All Products]} on columns
From [Adventure Works]

یک راه کوتاه‌تر برای انتخاب تمامی اعضا و سرجمع آنها

Select
{[Product].[Category].[Category],[Product].[Category]}
on columns
From [Adventure Works]

می توان از کلمات Members, All X استفاده نکرد.

انتخاب اولین دسته بندی محصول البته این ترتیب بر اساس Key Columns  در   SSAS می باشد .

Select
[Product].[Category].&[1]
on columns
From [Adventure Works]

انتخاب دقیق یک عضو در خروجی

Select
[Product].[Category].[Bikes]
on columns
From [Adventure Works]

انتخاب دو عضو از یک دایمنشن

Select
{[Product].[Category].[Bikes],[Product].[Category].[Clothing]}
on columns
From [Adventure Works]

واکشی تمامی دسته بندی محصولات بر اساس Measure پیش فرض :

Select
[Product].[Product Categories].members
on columns
From [Adventure Works]

در صورتیکه بخواهیم دو Dimension مختلف را در یک ستون یا سطر بیاوریم باید از Join استفاده کنیم. بنابر این دو دستور زیر با خطا روبرو می‌شوند

Select
[Product].[Product Categories],[Product].[Category]
on columns
From [Adventure Works]

Go

Select
{[Product].[Product Categories],[Product].[Category]}
on columns
From [Adventure Works]

تعریف Axis : به هر کدام از ستون یا سطر یک محور یا Axis گفته می‌شود.

با بررسی مثال فوق به نتایج زیر خواهیم رسید.

1. امکان استفاده از دو سلسله مراتب مختلف از یک دایمنشن در یک  Axis وجود ندارد . مگر اینکه آنها را باهمدیگر  CrossJoin کنیم .

2. امکان استفاده از دو سلسله مراتب مختلف از یک دایمنشن در دو Axis مختلف وجود دارد .

ترتیب انتخاب Axis ‌ها به صورت زیر می‌باشد:

1. Columns

2. Rows

 برای مشخص شدن موضوع کوئری زیر را اجرا کنید

Select
[Product].[Product Categories].members
on rows
From [Adventure Works]

نمی‌توانیم ردیفی را واکشی کنیم بدون اینکه ستونی برای کوئری مشخص کرده باشیم.

البته می‌توان ستون خالی ایجاد نماییم مانند مثال زیر :

Select
{} on columns,
[Product].[Product Categories].members
on rows
From [Adventure Works]

البته در این صورت خروجی فقط نام دسته بندی محصولات خواهد بود زیرا هیچ ستونی مشخص نشده . 

در مقالات بعدی به ادامه‌ی مطالب MDX Query خواهیم پرداخت.