web-dev-qa-db-fra.com

Création d'une procédure stockée dans une base de données locale qui référence des tables dans un serveur lié

J'ai actuellement un serveur local lié à un serveur distant.

Est-il possible de créer une procédure stockée dans le serveur local, mais en interrogeant les données des tables dans le serveur lié. Je suis conscient qu'il peut y avoir des problèmes de performances, mais je suis réticent à créer le sp sur le serveur lié car cela nécessiterait d'obtenir des autorisations pour le faire.

Je crois que mon problème est la syntaxe mais je ne peux pas identifier exactement quoi,

USE [LOCALDB]  --my local database or should I reference linked server db here
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROC [dbo].[mystoredprocedure]
    DECLARE @linkedserv NVARCHAR(150)
    DECLARE @linkeddb NVARCHAR(150)

    SET @linkedserv = 'HOSTNAME\SERVER';
    SET @linkeddb = 'remotedb';

    SELECT (CASE LTRIM(RTRIM([COLUMN1]))
        WHEN '' Then ''
        WHEN 'THIS' THEN 'THAT'
        WHEN 'NOW' THEN 'NEVER'
        ELSE 'OTHER' END) [Options]
    INTO #TempTable
    FROM @[email protected] --is this an issue?
    FULL OUTER JOIN OtherTableOnLinkedServer ON TableOnLinkedServer.COUMN1 = 
    OtherTableOnLinkedServer.COLUMN0   

Les serveurs liés db et ses tables sont interrogés à plusieurs reprises tout au long du sp. Il serait donc très utile de trouver un raccourci pour les référencer,

À votre santé

5
edwardinchains

Vous ne pouvez pas paramétrer les noms d'entité dans une instruction T-SQL. Pour ce faire, vous devez (a) créer d'abord la table #temp, et (b) utiliser le SQL dynamique. Voici une approche:

CREATE PROCEDURE [dbo].[mystoredprocedure]
AS
BEGIN
  SET NOCOUNT ON;

  DECLARE @exec nvarchar(256),
    @linkedserv nvarchar(150),
    @linkeddb   nvarchar(150),
    @sql        nvarchar(max);

  SELECT @linkedserv = N'HOSTNAME\SERVER',
         @linkeddb   = N'remotedb';

  SELECT @exec = QUOTENAME(@linkedserv) + N'.'
               + QUOTENAME(@linkeddb) + N'.sys.sp_executesql';

  CREATE TABLE #TempTable([Options] varchar(64));

  SELECT @sql = N'SELECT (CASE LTRIM(RTRIM(ot.[COLUMN1]))
        WHEN ''''     THEN ''''
        WHEN ''THIS'' THEN ''THAT''
        WHEN ''NOW''  THEN ''NEVER''
        ELSE ''OTHER'' END) AS [Options]
    FROM dbo.TableOnLinkedServer AS t
    FULL OUTER JOIN dbo.OtherTableOnLinkedServer AS ot
      ON t.COLUMN1 = ot.COLUMN0;';

  INSERT #TempTable([Options]) EXEC @exec @sql;   

  SELECT * FROM #TempTable;
END
GO

Vous pouvez le faire tout à l'intérieur de SQL dynamique, donc si connaître les colonnes à l'avance est un défi, il existe un moyen. Mais c'est compliqué, en supposant que vous ayez réellement besoin d'une table #temp, car alors tout ce que vous faites avec #TempTable doit être fait à l'intérieur du SQL dynamique.

CREATE PROCEDURE [dbo].[mystoredprocedure]
AS
BEGIN
  SET NOCOUNT ON;

  DECLARE @exec nvarchar(256),
    @linkedserv nvarchar(150),
    @linkeddb   nvarchar(150),
    @sql        nvarchar(max);

  SELECT @linkedserv = N'HOSTNAME\SERVER',
         @linkeddb   = N'remotedb';

  SELECT @exec = QUOTENAME(@linkedserv) + N'.'
               + QUOTENAME(@linkeddb) + N'.sys.sp_executesql';

  SELECT @sql = N'SELECT (CASE LTRIM(RTRIM(ot.[COLUMN1]))
        WHEN ''''     THEN ''''
        WHEN ''THIS'' THEN ''THAT''
        WHEN ''NOW''  THEN ''NEVER''
        ELSE ''OTHER'' END) AS [Options]
    INTO #TempTable
    FROM dbo.TableOnLinkedServer AS t
    FULL OUTER JOIN dbo.OtherTableOnLinkedServer AS ot
      ON t.COLUMN1 = ot.COLUMN0;

  SELECT * FROM #TempTable;';

  EXEC @exec @sql;   
END
GO

Veuillez consulter l'article obligatoire d'Erland Sommarskog sur T-SQL dynamique pour vous assurer de ne pas finir par créer une vulnérabilité embarrassante à l'injection SQL.

8
Aaron Bertrand