web-dev-qa-db-fra.com

y compris les paramètres dans OPENQUERY

Comment utiliser un paramètre dans sql openquery, tel que: 

SELECT * FROM OPENQUERY([NameOfLinkedSERVER], 'SELECT * FROM TABLENAME
where field1=@someParameter') T1 INNER JOIN MYSQLSERVER.DATABASE.DBO.TABLENAME
T2 ON T1.PK = T2.PK
69
gaponte69

Dans la documentation OPENQUERY , il est indiqué que:

OPENQUERY n'accepte pas les variables pour ses arguments.

Voir cet article pour une solution de contournement.

METTRE À JOUR:

Comme suggéré, j'inclus les recommandations de l'article ci-dessous.

Passer les valeurs de base

Lorsque l'instruction Transact-SQL de base est connue mais que vous devez transmettre une ou plusieurs valeurs spécifiques, utilisez un code similaire à l'exemple suivant: 

DECLARE @TSQL varchar(8000), @VAR char(2)
SELECT  @VAR = 'CA'
SELECT  @TSQL = 'SELECT * FROM OPENQUERY(MyLinkedServer,''SELECT * FROM pubs.dbo.authors WHERE state = ''''' + @VAR + ''''''')'
EXEC (@TSQL)

Passer la requête entière

Lorsque vous devez transmettre l'intégralité de la requête Transact-SQL ou le nom du serveur lié (ou les deux), utilisez un code similaire à l'exemple suivant:

DECLARE @OPENQUERY nvarchar(4000), @TSQL nvarchar(4000), @LinkedServer nvarchar(4000)
SET @LinkedServer = 'MyLinkedServer'
SET @OPENQUERY = 'SELECT * FROM OPENQUERY('+ @LinkedServer + ','''
SET @TSQL = 'SELECT au_lname, au_id FROM pubs..authors'')' 
EXEC (@OPENQUERY+@TSQL) 

Utiliser la procédure stockée Sp_executesql

Pour éviter les guillemets multicouches, utilisez un code similaire à l'exemple suivant:

DECLARE @VAR char(2)
SELECT  @VAR = 'CA'
EXEC MyLinkedServer.master.dbo.sp_executesql
N'SELECT * FROM pubs.dbo.authors WHERE state = @state',
N'@state char(2)',
@VAR
121
Garett

Vous pouvez exécuter une chaîne avec OPENQUERY une fois que vous l'avez construite. Si vous choisissez cette voie, pensez à la sécurité et veillez à ne pas concaténer le texte saisi par l'utilisateur dans votre code SQL!

DECLARE @Sql VARCHAR(8000)
SET @Sql = 'SELECT * FROM Tbl WHERE Field1 < ''someVal'' AND Field2 IN '+ @valueList 
SET @Sql = 'SELECT * FROM OPENQUERY(SVRNAME, ''' + REPLACE(@Sql, '''', '''''') + ''')'
EXEC(@Sql)
14
Tahbaza

Depuis la page MSDN :

OPENQUERY n'accepte pas les variables pour ses arguments

Fondamentalement, cela signifie que vous ne pouvez pas émettre de requête dynamique. Pour réussir ce que votre échantillon tente, essayez ceci:

SELECT * FROM 
   OPENQUERY([NameOfLinkedSERVER], 'SELECT * FROM TABLENAME') T1 
   INNER JOIN 
   MYSQLSERVER.DATABASE.DBO.TABLENAME T2 ON T1.PK = T2.PK 
where
   T1.field1 = @someParameter

Il est clair que si votre table TABLENAME contient une grande quantité de données, celles-ci s’appliqueront également sur le réseau et les performances risquent d’être médiocres. Par contre, pour une petite quantité de données, cela fonctionne bien et évite les frais généraux de construction de SQL (injection de SQL, guillemets) qui pourraient nécessiter une approche exec.

11
Neil Moss

En fait, nous avons trouvé un moyen de le faire:

DECLARE @username varchar(50)
SET @username = 'username'
DECLARE @Output as numeric(18,4)
DECLARE @OpenSelect As nvarchar(500)
SET @OpenSelect = '(SELECT @Output = CAST((CAST(pwdLastSet As bigint) / 864000000000) As numeric(18,4)) FROM OpenQuery (ADSI,''SELECT pwdLastSet
                                FROM  ''''LDAP://domain.net.intra/DC=domain,DC=net,DC=intra''''
                                WHERE objectClass =  ''''User'''' AND sAMAccountName = ''''' + @username + '''''
                          '') AS tblADSI)'
EXEC sp_executesql @OpenSelect, N'@Output numeric(18,4) out', @Output out
SELECT @Output As Outputs

Cela affectera le résultat de l'exécution OpenQuery, dans la variable @Output.

Nous avons testé la procédure Store dans MSSQL 2012, mais nous devrions utiliser MSSQL 2008+.

Microsoft indique que sp_executesql (Transact-SQL): s’applique à: SQL Server (SQL Server 2008 jusqu'à la version actuelle), base de données Windows Azure SQL (version initiale à la version actuelle). ( http://msdn.Microsoft.com/en-us/library/ms188001.aspx )

6
Juan Medina
DECLARE @guid varchar(36);  select @guid= convert(varchar(36), NEWID() );
/*
    The one caveat to this technique is that ##ContextSpecificGlobal__Temp should ALWAYS have the exact same columns.  
    So make up your global temp table name in the sproc you're using it in and only there!
    In this example I wanted to pass in the name of a global temporary table dynamically.  I have 1 procedure dropping 
    off temporary data in whatever @TableSrc is and another procedure picking it up but we are dynamically passing 
    in the name of our pickup table as a parameter for OPENQUERY.
*/
IF ( OBJECT_ID('tempdb..##ContextSpecificGlobal__Temp' , 'U') IS NULL )
    EXEC ('SELECT * INTO ##ContextSpecificGlobal__Temp FROM OPENQUERY(loopback, ''Select *,''''' +  @guid +''''' as tempid FROM ' + @TableSrc + ''')')
ELSE 
    EXEC ('INSERT ##ContextSpecificGlobal__Temp SELECT * FROM OPENQUERY(loopback, ''Select *,''''' +  @guid +''''' as tempid FROM ' + @TableSrc + ''')')

--If this proc is run frequently we could run into race conditions, that's why we are adding a guid and only deleting
--the data we added to ##ContextSpecificGlobal__Temp
SELECT * INTO #TableSrc FROM ##ContextSpecificGlobal__Temp WHERE tempid = @guid

BEGIN TRAN t1
    IF ( OBJECT_ID('tempdb..##ContextSpecificGlobal__Temp' , 'U') IS NOT NULL ) 
    BEGIN
        -- Here we wipe out our left overs if there if everyones done eating the data
        IF (SELECT COUNT(*) FROM ##ContextSpecificGlobal__Temp) = 0
            DROP TABLE ##ContextSpecificGlobal__Temp
    END
COMMIT TRAN t1

-- YEAH! Now I can use the data from my openquery without wrapping the whole !$#@$@ thing in a string.
4
Ryan Maloney
SELECT field1 FROM OPENQUERY 
                   ([NameOfLinkedSERVER], 
                   'SELECT field1 FROM TABLENAME') 
                           WHERE field1=@someParameter T1 
                                 INNER JOIN MYSQLSERVER.DATABASE.DBO.TABLENAME           
                                 T2 ON T1.PK = T2.PK
2
Tuan Zaidi

Dans l'exemple suivant, je passe un paramètre de département à une procédure stockée (spIncreaseTotalsRpt) tout en créant une table temp à partir d'un OPENQUERY . La table Temp doit être globale (##). ) afin qu’il puisse être référencé en dehors de son intance. En utilisant exec sp_executesql, vous pouvez transmettre le paramètre department.

Remarque: soyez prudent lorsque vous utilisez sp_executeSQL. De plus, votre administrateur pourrait ne pas avoir cette option à votre disposition.

J'espère que ça aide quelqu'un. 

 IF OBJECT_ID('tempdb..##Temp') IS NOT NULL
/*Then it exists*/
    begin
       DROP TABLE ##Temp
    end 
 Declare @Dept as nvarchar(20) ='''47'''

 declare @OPENQUERY  as nvarchar(max)
set @OPENQUERY = 'Select ' + @Dept + ' AS Dept,  * into ##Temp from openquery(SQL_AWSPROD01,''' 

declare @sql nvarchar(max)= @openquery +  'SET FMTONLY OFF EXECUTE SalaryCompensation.dbo.spIncreaseTotalsRpts ' + '''' + @Dept + ''''  + ''')'
declare @parmdef nvarchar(25) 
DECLARE @param nvarchar(20) 

SET @parmdef = N'@Dept varchar(20)'
-- select @sql
-- Print @sql + @parmdef  + @dept
exec sp_executesql @sql,@parmdef, @Dept  
Select * from ##Temp

Résultats 

Augmentation de la charge Cnt 0 1 2 3 4 5 6 0,0000 1,0000 0,0000 0,0000 0,0000 0,0000 0,0000 0,0000

1
Carlos

Combinez le SQL dynamique avec OpenQuery. (Cela va à un serveur Teradata)

DECLARE 
    @dayOfWk    TINYINT = DATEPART(DW, GETDATE()),
    @qSQL       NVARCHAR(MAX) = '';

SET @qSQL = '
SELECT
    *
FROM
    OPENQUERY(TERASERVER,''
        SELECT DISTINCT
            CASE
                WHEN ' + CAST(@dayOfWk AS NCHAR(1)) + ' = 2
                THEN ''''Monday''''
                ELSE ''''Not Monday''''
            END
        '');';

EXEC sp_executesql @qSQL;
0
Mike

J'ai trouvé un moyen qui fonctionne pour moi. Cela nécessite l'utilisation d'une table de travail à laquelle un serveur lié a accès.

J'ai créé une table et l'ai renseignée avec les valeurs dont j'ai besoin, puis je la référence via un serveur lié.

SELECT * 
FROM OPENQUERY(KHSSQLODSPRD,'SELECT *
  FROM ABC.dbo.CLAIM A WITH (NOLOCK)
  WHERE A.DOS >= (SELECT MAX(DATE) FROM KHSDASQL01.DA_MAIN.[dbo].[ALLFILENAMES]) ')
0
Hannover Fist