عنوان:

‫ساده‌ترین روش جهت استفاده از نام ستون‌ها در دستورات TSQL کدام است؟


نویسنده: هادی مزارعی
تاریخ: ۱۴۰۵/۰۶/۰۲ ۱۴:۲۷
آدرس: www.dntips.ir
در یک Stored Procedure یک Stored Procedure دیگر صدا زده می‌شود و نتیجه در یک جدول ذخیره خواهد شد.
INSERT INTO SummaryHistory EXEC dbo.qrySummary
اگرچه که این کد ساده‌ست ولی چالش در وجود ستون‌های متناظر در خروجی SP و جدول مقصد هستش (ممکن است ترتیب، نام ستون‌ها و یا حتی تعداد ستون‌ها تغییر کند). قصد دارم بجای خط بالا از شکل معمول دستور INSERT INTO با درج نام ستون‌ها استفاده کنم. ساده‌ترین روش برای این منظور کدام روش است؟ البته قصد استفاده از Table-Valued Function را ندارم مگر آنکه آخرین گزینه‌ی ممکن باشد.

نظرات

  • وحید نصیری در ۱۴۰۵/۰۶/۰۲ ۱۵:۵۴
    در موتور SQL Server، دستور INSERT INTO TargetTable (ColA, ColB) EXEC SP داده‌ها را صرفاً بر اساس ترتیب مکانی (Position) ستون‌ها نگاشت می‌کند، نه بر اساس نام ستون‌ها. یعنی حتی اگر نام ستون‌ها را در بخش INSERT INTO قید کنید، باز هم اولین ستون خروجی SP در اولین ستون لیست و دومی در دومی درج خواهد شد.
    ساده‌ترین، استانداردترین و پایدارترین راهکار برای حل این چالش بدون استفاده از TVF، استفاده از یک جدول موقت واسط (#Temp Table) است:
    -- ۱. جدول موقت با ساختار دقیق خروجی SP
    CREATE TABLE #TempSummary
    (
        -- اینجا دقیقاً ستون‌های خروجی dbo.qrySummary را تعریف کنید
        ColA INT,
        ColB NVARCHAR(100),
        ColC DATETIME
        -- ...
    );
    
    -- ۲. نتیجه SP را داخل جدول موقت بریزید
    INSERT INTO #TempSummary
    EXEC dbo.qrySummary;
    
    -- ۳. حالا با نام ستون‌ها به جدول اصلی INSERT کنید
    INSERT INTO SummaryHistory
    (
        TargetCol1,   -- ستون جدول مقصد
        TargetCol2,
        TargetCol3
        -- ستون‌های اضافی مقصد که می‌خواهید مقدار پیش‌فرض یا ثابت بگیرند را اینجا ننویسید
    )
    SELECT
        ColA,         -- از جدول موقت (می‌توانید ترتیب را عوض کنید)
        ColB,
        ColC
    FROM #TempSummary;
    
    -- پاک‌سازی
    DROP TABLE #TempSummary;
    در این حالت ترتیب قرارگیری ستون‌ها در خروجی SP دیگر اهمیتی ندارد چون در مرحله SELECT صراحتاً فیلدها را به ستون‌های جدول مقصد منتسب می‌کنید.

    البته:
    • ساختار #Temp، باید دقیقاً با خروجی فعلی SP مطابقت داشته باشد (تعداد، ترتیب و نوع داده). اگر SP عوض شود، #Temp را هم آپدیت کنید.
    • می‌توانید به جای #Temp از @Temp TABLE (...) استفاده کنید (محدودیت اندازه حافظه دارد).


    و یا یک روش جایگزین (Shared Temp Table): اگر امکان ویرایش کدهای dbo.qrySummary را دارید، می‌توانید به جای بازگرداندن یک SELECT ساده، داخل پروسیجر، خروجی را مستقیماً درون یک #TempTable از پیش تعریف‌شده بریزید. در SQL Server، پروسیجرهای فرزند، به جدول موقتی که در پروسیجر والد ساخته شده‌است، دسترسی دارند.

    + اگر ساختار SP خیلی متغیر است
    در این حالت می‌توانید با sys.dm_exec_describe_first_result_setساختار را داینامیک بگیرید (SQL Server خودش این ابزار بسیار خوب را برای کشف schema خروجی یک Stored Procedure دارد) و بر اساس آن، جدول موقت را بسازید؛ اما پیچیدگی آن زیاد می‌شود و برای اکثر موارد لازم نیست.
    SELECT
        name,
        column_ordinal,
        system_type_name
    FROM sys.dm_exec_describe_first_result_set
    (
        N'EXEC dbo.qrySummary',
        NULL,
        0
    )
    WHERE is_hidden = 0;