Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Melewati tipe tabel yang ditentukan pengguna antara database SQL Server

Ini adalah duplikat dari Dapatkah Anda membuat CLR UDT untuk memungkinkan jenis Tabel bersama di seluruh database?

Pada dasarnya, Tipe Tabel Buatan Pengguna tidak dapat dibagikan di seluruh database. UDT berbasis CLR bisa dibagikan di seluruh basis data, tetapi hanya jika kondisi tertentu telah terpenuhi, seperti Majelis yang sama dimuat ke kedua basis data, dan beberapa hal lainnya (detailnya ada di pertanyaan duplikat yang disebutkan di atas).

Untuk situasi khusus ini, ada cara untuk meneruskan info dari DB1 ke DB2 , meskipun itu bukan solusi yang elegan. Untuk menggunakan Tipe Tabel, konteks database Anda saat ini harus menjadi database tempat Tipe Tabel berada. Ini dilakukan melalui USE pernyataan, tetapi itu hanya dapat dilakukan dalam SQL dinamis jika perlu dilakukan dalam Prosedur Tersimpan.

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

PERBARUI

Menggunakan sp_executesql , baik dalam upaya untuk menghindari tabel sementara lokal dengan hanya meneruskan UDTT sebagai TVP, atau hanya sebagai sarana untuk melakukan kueri berparameter, tidak benar-benar berfungsi (meskipun sepertinya memang seharusnya demikian). Artinya, sebagai berikut:

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;

akan gagal pada "@TableTypeDB2 memiliki tipe data yang tidak valid", meskipun dengan benar menampilkan DB2 itu adalah Database "saat ini". Ini ada hubungannya dengan bagaimana sp_executesql menentukan tipe data variabel karena kesalahan yang dirujuk ke @TableTypeDB2 sebagai "variabel # 2", meskipun dibuat secara lokal dan bukan sebagai parameter input.

Faktanya, sp_executesql akan error jika satu variabel dideklarasikan (melalui parameter input daftar parameter ke sp_executesql ), walaupun tidak pernah direferensikan, apalagi digunakan. Artinya, kode berikut akan mengalami kesalahan yang sama karena tidak dapat menemukan definisi untuk UDTT yang terjadi dengan kueri tepat di atas:

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

(Terima kasih kepada @Mark Sowul karena telah menyebutkan sp_executesql tidak berfungsi saat meneruskan variabel)

NAMUN, masalah ini dapat diselesaikan (baik, selama Anda tidak mencoba untuk melewati TVP untuk menghindari tabel temp -- 2 kueri di atas) dengan mengubah database eksekusi sp_executesql sehingga prosesnya akan lokal ke DB di mana TVP lain ada. Satu hal yang menyenangkan tentang sp_executesql apakah itu, tidak seperti EXEC , itu adalah Prosedur Tersimpan, dan prosedur tersimpan sistem pada saat itu, sehingga dapat sepenuhnya memenuhi syarat. Memanfaatkan fakta ini memungkinkan sp_executesql untuk bekerja, yang juga berarti bahwa tidak perlu USE [DB2]; pernyataan dalam SQL Dinamis. Kode berikut berfungsi:

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. Cara tercepat untuk melakukan penyisipan massal bersarang dengan penggunaan scope_identity()?

  2. Izinkan karakter khusus SQL Server 2008

  3. Mengapa konversi dari DATETIME ke DATETIME2 tampaknya mengubah nilai?

  4. SQL Server ODBC Driver tidak memunculkan kesalahan

  5. Bagaimana Memetakan Kolom Input dan Output secara dinamis di SSIS?