Run complex update query on remote server using OPENROWSET - sql

Could you please help me with below task. I need to run below query on remote server
UPDATE prod
SET prod.count = ( SELECT SUM(Inv) FROM cost WHERE pID = prod.ID)
WHERE (( SELECT COUNT(id) FROM Cost WHERE pID = prod.ID ) > 0)
I have tried to use OPENROWSET but do not have enough experience working with it and all online examples with OPENROWSET that I saw use only one table. Can you please give me an idea how to modify this query to use OPENROWSET or ideas of any other solutions?

You can use direct linked server or OPENQUERY (linked_server_name ,'your query').
Best way to to this is to create procedure on target instance and use only easy exec on linked server to run procedure.
exec LinkedServer.TargetDB.TargerSc.NewProcedure
Openrowset is used to "open row set" - primary to access remote data, to modify remote data is openquery.

Related

SQL simple query on multiple linked servers & databases

I have this simple SQL query in SSMS select * from dbo.table1 where sucode = 'a002'
I am trying to learn how to run this on all linked servers on databases ending in %live
I've never done this before and what I have seen online hasn't really helped.
I know I need to have QUOTENAME(d.name, '''') ....WHERE NAME like '%live' for the database name and possibly the same for the server? Or maybe an OPENQUERY for the server? Or a link?
If anyone has a template they use or any advise that would be hugely appreciated.
You can use undocumented stored procedure MS_ForeachDb to execute the query against each database. You can use sys.servers to get the list of linked servers and run them against each linked server.
Read MS_ForeachDB
Read about sys.servers
SELECT 'SELECT * FROM OPENQUERY(' + name + ',''EXECUTE master.sys.sp_MSforeachdb ''USE [?];select * from dbo.table1 where sucode = ''a002'''')'
FROM sys.servers WHERE is_linked = 1; -- avoid pulling from local server
Note: Using undocumented procedures is not recommended. Read more on this using undocumented procedures bad practice

SQL reporting invalid syntax when run in Power BI

I have written an SQL script which runs fine when executed directly in SQL Management Studio. However, when entering it into Power BI as a source, it reports that it has an incorrect syntax.
This is the query:
EXEC "dbo"."p_get_bank_balance" '2'
However, the syntax is apparently incorrect? See Picture:
Any help is much appreciated.
EDIT ***
When the double quotes are removed (as per Tab Alleman's suggestion):
I found time ago the same problem online on power bi site:
http://community.powerbi.com/t5/Desktop/Use-SQL-Store-Procedure-in-Power-BI/td-p/20269
You must be using DirectQuery mode, in which you cannot connect to data with stored procedures. Try again using Import mode or just use a SELECT statement directly.
In DirectQuery mode, PowerBI automatically wraps your query like so: select * from ( [your query] ), and if you attempt this in SSMS with a stored procedure i.e.
select * from (exec dbo.getData)
You get the error you see above.
The solution is you have to place your stored procedure call in an OPENQUERY call to your local server i.e.
select * from OPENQUERY(localServer, 'DatabaseName.dbo.getData')
Prerequisites would be: enabling local server access in OPENQUERY with
exec sp_serveroption #server = 'YourServerName'
,#optname = 'DATA ACCESS'
,#optvalue = 'TRUE'
And then making sure you use three-part notation in the OPENQUERY as all calls there default to the master database
With "Import" data connectivity mode Stored Procedures work
With "Direct Query" data connectivity mode, the query syntax must be like below:
declare #sqlCommand varchar(100) = 'dbo.p_get_bank_balance'
declare #p1 int = 2
exec #sqlCommand #p1 = #p1
Remerber: max one data source connection with Direct Query. If you want to call much SP, only one can be in Direct Query mode, the others in Import mode
Try using Import instead of Direct Query. It may be showing error cause you are using Temp table in it. Create query using sub query and remove Temp table and try it. Or you can use as Import instead of Direct Query it will work.

Encrypted query in sql server

I want to execute a query in our client's server using remove access. If I execute a query something like this Update abc set col1=12 where id = 2 they will understand what we are doing. So I want some method for encryption and decryption like this:
In our server I encrypt a query like this:
encrypt(Update abc set col1=12 where id = 2)
So I get output like:
0x0100CF465B7B12625EF019E157120D58DD46569AC7BF4118455D12625EF019E157120D58DD46569AC7BF4118455D
And I execute a this encrypted query on client's machine like this:
decrypt(0x0100CF465B7B12625EF019E157120D58DD46569AC7BF4118455D12625EF019E157120D58DD46569AC7BF4118455D)
So our client can't understand what we have executed.
you can create a simple decrypt function like this..
create proc exec_decrypt(#sql_str varbinary(8000))
as
begin
declare #qry varchar(8000);
select #qry=cast(#sql_str as varchar(8000));
exec(#qry);
end
which accepts a varbinary string and converts to varchar and then execute it..
You can generate the encrypted query by using the satament below
select CAST('UPDATE users set name =''alex''' as varbinary(8000))
then execute the proc exec_decrypt in client place by passing the output of the above query as the parameter for the procedure..
Ex: exec_decrypt 0x55504441544520757365727320736574206E616D65203D27616C657827
Hope this will work for you.. Please note that client should not have any permission on the
proc exec_decrypt
The only way I have found to ensure that no one can view your queries is to put them in a function or procedure using 'with encryption'. Run the below code to see for yourself. Dynamic SQL suggested in the earlier answer doesn't fully solve your problem.
create procedure dbo.dummy_drop_me with encryption as select t.* from sys.dm_exec_requests r cross apply sys.dm_exec_sql_text (r.sql_handle) t where r.session_id = ##spid
go
exec dbo.dummy_drop_me
go
select t.* from sys.dm_exec_requests r cross apply sys.dm_exec_sql_text (r.sql_handle) t where r.session_id = ##spid
go
exec ('select t.* from sys.dm_exec_requests r cross apply sys.dm_exec_sql_text (r.sql_handle) t where r.session_id = ##spid')
The only way I have found to keep someone from capturing your functions and procedures is to create them in their own database on a server where no one has access. Then, attach a copy of the database to the servers where you need them.
In my opinion, With Encryption is generally counter-productive as there are a number of Sql Server decryption tools. ie dbForge's DB Decryptor. I just used this to decrypt a database's T-SQL, so I could export DACPAC's and BACPAC's for use in Azure DevOps automated deployments. With Encryption causes DACPAC and BACPAC exports to fail. This means, if you implement With Encryption you cannot use DACPAC to create update scripts for DB Patches or direct updates, you cannot use Visual Studio Sql Server Tools projects, which makes DB development harder. You have not secured anything, just made it harder for Dev's and Op's to do their jobs.

Insert Data From One Server To Another?

If I want to run this sort of query in SQL Server, how can I do the same query from one server I am connected to to another?
I tried adding "[ServerName1]." before "[DatabaseName1].[dbo]..." and "[ServerName2]." before "[DatabaseName2].[dbo]..." but that didn't seem to work.
INSERT INTO [DatabaseName1].[dbo].[TableName]
([FieldName])
SELECT [FieldName] FROM [DatabaseName2].[dbo].[TableName]
Is this possible?
Yes you would use the server-name before the whole rest of object-name like:
myserver.mydatabase.dbo.mytable
However you first have to set up linked servers. Look up linked servers in BOL.
If you have adhoc distributed queries enabled you can use OPENDATASOURCE. Setting up a linked server is another option. Not sure of the pros and cons of each approach.
INSERT INTO [DatabaseName1].[dbo].[TableName]
SELECT FieldName
FROM OPENDATASOURCE('SQLNCLI',
'Data Source=Server\InstanceName;Integrated Security=SSPI')
.DatabaseName2.dbo.TableName
The best way to do this would be to create a "linked server" between the two. You will need appropriate permissions to do this.
Then it's just a matter of accessing the databases using your linkedserver name.
Ex: [linkedserver].databasename.dbo.tablename
To create a linkedserver, go to server objects->right click on linked servers->click on 'new linked server'.
In SSMS, Go to Query -> 'SQLCMD Mode'
DECLARE #VERSION VARCHAR(1000)
:CONNECT Soruce_Server_Name
SELECT ##VERSION AS [SQL_VERSION]
INTO
:CONNECT Destination_Server_Name
[MSSQLTips].[dbo].[TEST]
Now on the Destination Server, execute your select command to check your output. For E.g.
SELECT * FROM [CloverInfotech_DB].[dbo].[TEST]

SQL - How to insert results of Stored_Proc into a new table without specifying columns of new table?

Using SQL Server 2005, I'd like to run a stored procedure and insert all of the results into a new table.
I'd like the new table to have its columns automatically configured based upon the data returned by the stored procedure.
I am familiar with using the SELECT ... INTO syntax:
SELECT * INTO newtable FROM oldtable
Is this possible?
Edit for clarification: I'm hoping to accomplish something like:
Select * INTO newtable FROM exec My_SP
The only way to do this is w/ OPENROWSET against the local server:
SELECT * INTO #temp
FROM OPENROWSET (
'SQLOLEDB'
, 'Server=(local);TRUSTED_CONNECTION=YES;'
, 'SET FMTONLY OFF EXEC database.schema.procname'
) a
But this is kind of a last-ditch-gotta-do-it-damn-the-consequences kind of method. It requires elevated permissions, won't work for all procedures, and is generally inefficient.
More info and some alternatives here: http://www.sommarskog.se/share_data.html
This seems like a horrible design. You're really going to create a new table to store the results of a stored procedure, every time the stored procedure is called? And you really can't create the table in advance because you have absolutely no idea what kind of output the stored procedure has? What if the stored procedure returns multiple resultsets? What if it has side effects?
Okay, well, if that's what you really want to do...
One way to accomplish this is to use your local server as a linked server and utilize OPENQUERY. First you need to make sure your local server is configured for data access:
EXEC sp_serveroption 'local server name', 'DATA ACCESS', true;
Then you can do something like this:
SELECT * INTO dbo.newtable
FROM OPENQUERY('local server name', 'EXEC yourdb.dbo.yourproc;');
PS How are you going to write code that is going to perform SELECT INTO into a new table name every time (because you can only do SELECT INTO once)? Dynamic SQL? What happens if two users run this code at the same time? Does one of them win, and the other one just gets an error message?
A variation of the same is
create table somename
select * from wherever;