it-swarm.dev

كيفية استخدام متغير الجدول في بيان مزود ديناميكي؟

في الإجراء المخزن الخاص بي ، أعلنت عن متغيري جدول في أعلى الإجراء. الآن أحاول استخدام متغير الجدول هذا ضمن عبارة sql ديناميكية ولكنني أتلقى هذا الخطأ في وقت تنفيذ هذا الإجراء. أنا أستخدم SQL Server 2008.

هكذا يبدو الاستعلام الخاص بي ،

set @col_name =  'Assoc_Item_' 
              + Convert(nvarchar(2), @curr_row1);

set @sqlstat = 'update @RelPro set ' 
             + @col_name 
             + ' = (Select relsku From @TSku Where tid = ' 
             + Convert(nvarchar(2), @curr_row1) + ') Where RowID = ' 
             + Convert(nvarchar(2), @curr_row);

Exec(@sqlstat);

وأحصل على الأخطاء التالية ،

يجب أن تعلن متغير الجدول "RelPro". يجب أن تعلن متغير الجدول "TSku".

لقد حاولت أن تأخذ الجدول خارج كتلة سلسلة الاستعلام الديناميكي ولكن دون جدوى.

57
Ashar Syed

ينفذ EXEC في سياق مختلف ، وبالتالي فهو لا يعلم بأي متغيرات تم الإعلان عنها في سياقك الأصلي. يجب أن تكون قادرًا على استخدام جدول مؤقت بدلاً من متغير الجدول كما هو موضح في العرض التوضيحي البسيط أدناه.

create table #t (id int)

declare @value nchar(1)
set @value = N'1'

declare @sql nvarchar(max)
set @sql = N'insert into #t (id) values (' + @value + N')'

exec (@sql)

select * from #t

drop table #t
58
Joe Stefanelli

في SQL Server 2008+ ، من الممكن استخدام معلمات قيم الجدول لتمرير متغير الجدول إلى عبارة SQL ديناميكية طالما أنك لا تحتاج إلى تحديث القيم في الجدول نفسه.

لذلك من الرمز الذي قمت بنشره ، يمكنك استخدام هذا الأسلوب من أجل @TSku لكن ليس من أجل @RelPro

بناء جملة المثال أدناه.

CREATE TYPE MyTable AS TABLE 
( 
Foo int,
Bar int
);
GO


DECLARE @T AS MyTable;

INSERT INTO @T VALUES (1,2), (2,3)

SELECT *,
        sys.fn_PhysLocFormatter(%%physloc%%) AS [physloc]
FROM @T

EXEC sp_executesql
  N'SELECT *,
        sys.fn_PhysLocFormatter(%%physloc%%) AS [physloc]
    FROM @T',
  N'@T MyTable READONLY',
  @[email protected] 

يتم تضمين العمود physloc فقط لإظهار أن متغير الجدول المشار إليه في النطاق الفرعي هو بالتأكيد نفس النطاق الخارجي بدلاً من نسخة.

74
Martin Smith

ليس لديك لديك لاستخدام SQL الحيوي

update
    R
set
    Assoc_Item_1 = CASE WHEN @curr_row = 1 THEN foo.relsku ELSE Assoc_Item_1 END,
    Assoc_Item_2 = CASE WHEN @curr_row = 2 THEN foo.relsku ELSE Assoc_Item_2 END,
    Assoc_Item_3 = CASE WHEN @curr_row = 3 THEN foo.relsku ELSE Assoc_Item_3 END,
    Assoc_Item_4 = CASE WHEN @curr_row = 4 THEN foo.relsku ELSE Assoc_Item_4 END,
    Assoc_Item_5 = CASE WHEN @curr_row = 5 THEN foo.relsku ELSE Assoc_Item_5 END,
    ...
from
    (Select relsku From @TSku Where tid = @curr_row1) foo
    CROSS JOIN
    @RelPro R
Where
     R.RowID = @curr_row;
14
gbn

لا يمكنك القيام بذلك لأن متغيرات الجدول خارج النطاق.

يجب أن تقوم بتعريف متغير الجدول داخل عبارة SQL الديناميكية أو إنشاء جداول مؤقتة.

أود أن أقترح عليك قراءة هذه المقالة الممتازة في SQL الحيوية.

http://www.sommarskog.se/dynamic_sql.html

6
codingbadger

حسنًا ، اكتشفت الطريقة التي فكرت في مشاركتها مع الأشخاص الذين قد يواجهون نفس المشكلة.

دعني أبدأ بالمشكلة التي كنت أواجهها ،

كنت أحاول تنفيذ عبارة Sql ديناميكية تستخدم جدولين مؤقتين قمت بإعلانهما في الجزء العلوي من الإجراء المخزن الخاص بي ، ولكن نظرًا لأن هذا النص الثابت الديناميكي sql أنشأ نطاقًا جديدًا ، لم أستطع استخدام الجداول المؤقتة.

حل:

لقد قمت ببساطة بتغييرها إلى متغيرات عالمية مؤقتة وعملت على ذلك.

ابحث عن الإجراء المخزن أسفله.

CREATE PROCEDURE RAFCustom_Room_GetRelatedProducts
-- Add the parameters for the stored procedure here
@PRODUCT_SKU nvarchar(15) = Null

BEGIN - تمت إضافة NOCOUNT ON لمنع مجموعات النتائج الإضافية من - التدخل في عبارات SELECT. ضع NOCOUNT على ؛

IF OBJECT_ID('tempdb..##RelPro', 'U') IS NOT NULL
BEGIN
    DROP TABLE ##RelPro
END

Create Table ##RelPro
(
    RowID int identity(1,1),
    ID int,
    Item_Name nvarchar(max),
    SKU nvarchar(max),
    Vendor nvarchar(max),
    Product_Img_180 nvarchar(max),
    rpGroup int,
    Assoc_Item_1 nvarchar(max),
    Assoc_Item_2 nvarchar(max),
    Assoc_Item_3 nvarchar(max),
    Assoc_Item_4 nvarchar(max),
    Assoc_Item_5 nvarchar(max),
    Assoc_Item_6 nvarchar(max),
    Assoc_Item_7 nvarchar(max),
    Assoc_Item_8 nvarchar(max),
    Assoc_Item_9 nvarchar(max),
    Assoc_Item_10 nvarchar(max)
);

Begin
    Insert ##RelPro(ID, Item_Name, SKU, Vendor, Product_Img_180, rpGroup)

    Select distinct zp.ProductID, zp.Name, zp.SKU,
        (Select m.Name From ZNodeManufacturer m(nolock) Where m.ManufacturerID = zp.ManufacturerID),
        'http://s0001.server.com/is/sw11/DG/' + 
        (Select m.Custom1 From ZNodeManufacturer m(nolock) Where m.ManufacturerID = zp.ManufacturerID) +
        '_' + zp.SKU + '_3?$SC_3243$', ep.RoomID
    From Product zp(nolock) Inner Join RF_ExtendedProduct ep(nolock) On ep.ProductID = zp.ProductID
    Where zp.ActiveInd = 1 And SUBSTRING(zp.SKU, 1, 2) <> 'GC' AND zp.Name <> 'PLATINUM' AND zp.SKU = (Case When @PRODUCT_SKU Is Not Null Then @PRODUCT_SKU Else zp.SKU End)
End

declare @curr_row int = 0,
        @tot_rows int= 0,
        @sku nvarchar(15) = null;

IF OBJECT_ID('tempdb..##TSku', 'U') IS NOT NULL
BEGIN
    DROP TABLE ##TSku
END
Create Table ##TSku (tid int identity(1,1), relsku nvarchar(15));

Select @curr_row = (Select MIN(RowId) From ##RelPro);
Select @tot_rows = (Select MAX(RowId) From ##RelPro);

while @curr_row <= @tot_rows
Begin
    select @sku = SKU from ##RelPro where RowID = @curr_row;

    truncate table ##TSku;

    Insert ##TSku(relsku)
    Select distinct top(10) tzp.SKU From Product tzp(nolock) INNER JOIN 
    [INTRANET].raf_FocusAssociatedItem assoc(nolock) ON assoc.associatedItemID = tzp.SKU
    Where (assoc.isActive=1) And (tzp.ActiveInd = 1) AND (assoc.productID = @sku)

    declare @curr_row1 int = (Select Min(tid) From ##TSku),
            @tot_rows1 int = (Select Max(tid) From ##TSku);

    If(@tot_rows1 <> 0)
    Begin
        While @curr_row1 <= @tot_rows1
        Begin
            declare @col_name nvarchar(15) = null,
                    @sqlstat nvarchar(500) = null;
            set @col_name =  'Assoc_Item_' + Convert(nvarchar(2), @curr_row1);
            set @sqlstat = 'update ##RelPro set ' + @col_name + ' = (Select relsku From ##TSku Where tid = ' + Convert(nvarchar(2), @curr_row1) + ') Where RowID = ' + Convert(nvarchar(2), @curr_row);
            Exec(@sqlstat);
            set @curr_row1 = @curr_row1 + 1;
        End
    End
    set @curr_row = @curr_row + 1;
End

Select * From ##RelPro;

نهاية الذهاب

2
Ashar Syed

لا أعتقد أن هذا ممكن ( على الرغم من الرجوع إلى التحديث أدناه ) ؛ بقدر ما أعرف متغير الجدول موجود فقط ضمن النطاق الذي أعلن عنه. ومع ذلك ، يمكنك استخدام جدول مؤقت (استخدام بناء جملة create table وبادئة اسم الجدول الخاص بك بالرمز #) ، وسيكون ذلك متاحًا في النطاق الذي ينشئه ونطاق البيان الديناميكي .

استكمال: الرجوع إلى إجابة مارتن سميث عن كيفية استخدام معلمة الجدول القيمة لتمرير متغير الجدول في عبارة SQL ديناميكية. لاحظ أيضًا القيد المذكور: معلمات قيم الجدول للقراءة فقط.

1
Dr. Wily's Apprentice

فيما يلي مثال على استخدام استعلام T-SQL ديناميكي ثم استخراج النتائج إذا كان لديك أكثر من عمود واحد من القيم التي تم إرجاعها (لاحظ اسم الجدول الديناميكي):

DECLARE 
@strSQLMain nvarchar(1000),
@recAPD_number_key char(10),    
@Census_sub_code varchar(1),
@recAPD_field_name char(100),
@recAPD_table_name char(100),
@NUMBER_KEY varchar(10),

if object_id('[Permits].[dbo].[myTempAPD_Txt]') is not null 

    DROP TABLE [Permits].[dbo].[myTempAPD_Txt]

CREATE TABLE [Permits].[dbo].[myTempAPD_Txt]
(
    [MyCol1] char(10) NULL,
    [MyCol2] char(1) NULL,

)   
-- an example of what @strSQLMain is : @strSQLMain = SELECT @recAPD_number_key = [NUMBER_KEY], @Census_sub_code=TEXT_029 FROM APD_TXT0 WHERE Number_Key = '01-7212' 
SET @strSQLMain = ('INSERT INTO myTempAPD_Txt SELECT [NUMBER_KEY], '+ rtrim(@recAPD_field_name) +' FROM '+ rtrim(@recAPD_table_name) + ' WHERE Number_Key = '''+ rtrim(@Number_Key) +'''')      
EXEC (@strSQLMain)  
SELECT @recAPD_number_key = MyCol1, @Census_sub_code = MyCol2 from [Permits].[dbo].[myTempAPD_Txt]

DROP TABLE [Permits].[dbo].[myTempAPD_Txt]  
0
Gerald

استخدام جدول Temp يحل المشكلة لكني واجهت مشاكل في استخدام Exec ، لذلك ذهبت مع الحل التالي لاستخدام sp_executesql:

Create TABLE #tempJoin ( Old_ID int, New_ID int);

declare @table_name varchar(128);

declare @strSQL nvarchar(3072);

set @table_name = 'Object';

--build sql sting to execute
set @strSQL='INSERT INTO '[email protected]_name+' SELECT '[email protected]+' FROM #tempJoin CJ
                        Inner Join '[email protected]_name+' sourceTbl On CJ.Old_ID = sourceTbl.Object_ID'

**exec sp_executesql @strSQL;**
0
sfomate