Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Предаване на дефиниран от потребителя тип таблица между база данни на SQL Server

Това е дубликат на Можете ли да създадете CLR UDT, за да позволите споделен тип таблица в базите данни?

По същество дефинираните от потребителя типове таблици не могат да се споделят между бази данни. UDT, базирани на CLR, могат да се споделя между базите данни, но само ако са изпълнени определени условия, като например зареждането на една и съща сглобка в двете бази данни и няколко други неща (подробностите са в дублирания въпрос, отбелязан по-горе).

За тази конкретна ситуация има начин да се предаде информацията от DB1 към DB2 , въпреки че не е елегантно решение. За да използвате тип таблица, текущият контекст на базата данни трябва да бъде базата данни, в която съществува типът таблица. Това става чрез USE израз, но това може да се направи само в динамичен SQL, ако трябва да се направи в рамките на съхранена процедура.

USE [DB1];
GO

CREATE PROCEDURE [dbo].[selectData]
    @psCustomList CustomList READONLY
AS
BEGIN
    -- create a temp table as it can be referenced in dynamic SQL
    CREATE TABLE #TempCustomList
    (
        [ID] [INT],
        [Display] [NVARCHAR] (100)
    );

    INSERT INTO #TempCustomList (ID, Display)
        SELECT ID, Display FROM @psCustomList;

    EXEC('
        USE [DB2];

        DECLARE @VarCustomList CustomList;

        INSERT INTO @VarCustomList (ID, Display)
            SELECT ID, Display FROM #TempCustomList;

        EXEC dbo.selectMoreData @VarCustomList;
     ');
END

АКТУАЛИЗАЦИЯ

Използване на sp_executesql , или в опит да се избегне локалната временна таблица чрез просто предаване на UDTT като TVP, или просто като средство за извършване на параметризирана заявка, всъщност не работи (макар че със сигурност изглежда, че трябва). Което означава следното:

USE [DB1];
GO
CREATE PROCEDURE dbo.CrossDatabaseTableTypeA
(
    @TheUDTT dbo.TestTable1 READONLY
)
AS
SET NOCOUNT ON;

EXEC sp_executesql N'
  USE [DB2];
  SELECT DB_NAME() AS [CurrentDB];

  DECLARE @TableTypeDB2 dbo.TestTable2;
  INSERT INTO @TableTypeDB2 ([Col1])
    SELECT tmp.[Col1]
    FROM   @TableTypeDB1 tmp;

  --EXEC dbo.CrossDatabaseTableTypeB @TableTypeDB2;
  ',
  N'@TableTypeDB1 dbo.TestTable1 READONLY',
  @TableTypeDB1 = @TheUDTT;
GO


DECLARE @tmp dbo.TestTable1;
INSERT INTO @tmp ([Col1]) VALUES (1), (3);
SELECT * FROM @tmp;

EXEC dbo.CrossDatabaseTableTypeA @TheUDTT = @tmp;

ще се провали при „@TableTypeDB2 има невалиден тип данни“, въпреки че правилно показва, че DB2 е "текущата" база данни. Има нещо общо с това как sp_executesql определя променливи типове данни, тъй като грешката се отнася до @TableTypeDB2 като "променлива # 2", въпреки че е създаден локално, а не като входен параметър.

Всъщност sp_executesql ще възникне грешка, ако се декларира една променлива (чрез параметъра за въвеждане на списъка с параметри към sp_executesql ), дори ако никога не се споменава, камо ли да се използва. Това означава, че следният код ще се сблъска със същата грешка да не може да намери дефиницията за UDTT, която се случва със заявката непосредствено по-горе:

USE [DB1];
GO
CREATE PROCEDURE dbo.CrossDatabaseTableTypeC
AS
SET NOCOUNT ON;

EXEC sp_executesql N'
  USE [DB2];
  SELECT DB_NAME() AS [CurrentDB];

  DECLARE @TableTypeDB2 dbo.TestTable2;
  ',
  N'@SomeVar INT',
  @SomeVar = 1;
GO

(Благодаря на @Mark Sowul, че спомена, че sp_executesql не работи при предаване на променливи)

ОБАЧЕ този проблем може да бъде заобиколен (е, стига да не се опитвате да подадете TVP, за да избегнете временната таблица -- 2 заявки по-горе), като промените базата данни за изпълнение на sp_executesql така че процесът да бъде локален за DB, в който съществува другият TVP. Едно хубаво нещо за sp_executesql е това, за разлика от EXEC , това е съхранена процедура и системна съхранена процедура, така че може да бъде напълно квалифицирана. Използването на този факт позволява sp_executesql да работи, което също означава, че няма нужда от USE [DB2]; израз в рамките на динамичния SQL. Следният код работи:

USE [DB1];
GO
CREATE PROCEDURE dbo.CrossDatabaseTableTypeD
(
    @TheUDTT dbo.TestTable1 READONLY
)
AS
SET NOCOUNT ON;

-- create a temp table as it can be referenced in dynamic SQL
CREATE TABLE #TempList
(
    [ID] [INT]
);

INSERT INTO #TempList ([ID])
   SELECT [Col1] FROM @TheUDTT;

EXEC [DB2].[dbo].sp_executesql N'
  SELECT DB_NAME() AS [CurrentDB];

  DECLARE @TableTypeDB2 dbo.TestTable2;
  INSERT INTO @TableTypeDB2 ([Col1])
    SELECT tmp.[ID]
    FROM   #TempList tmp;

  EXEC dbo.CrossDatabaseTableTypeB @TableTypeDB2;
  ',
  N'@SomeVariable INT',
  @SomeVariable = 1111;
GO



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Използване на INSERT INTO от SQL Server за промяна на данните на Salesforce

  2. SQL - безопасно понижаване на BIGINT до INT

  3. Сума от час и минути в SQL Server 2008

  4. Премахнете числата от string sql сървъра

  5. Изследване на опциите за изчакване на заключване с нисък приоритет в SQL Server 2014 CTP1