How to create a view where data resides in a view on remote Azure SQL Server - azure-sql-database

I'm trying to create a view of data that resides in remote Azure SQL Server. I can't seem to create a table or temp table in the view to store the results of the sp_exeucte_remote call because that is not allowed so I tried to use a function, but then I get an error complaining about the following error based on the provided function definition.
Invalid use of a side-effecting operator 'INSERT EXEC' within a function
CREATE OR ALTER FUNCTION [dbo].[fn_Test]()
RETURNS #Results TABLE
(
[ID] INT,
[$ShardName] VARCHAR(500)
)
AS
BEGIN
INSERT INTO #Results
EXEC sp_execute_remote N'MyExternalDatasource', N'SELECT 1'
RETURN;
END
How can one create a view of data that exists on a remote Azure SQL Server where that data also exists as a view? FYI - the server where I'm trying to create the view is also Azure SQL Server.

Why are you using a FUNCTION?
As per Microsoft Documentation you cannot call a Stored Procedure within a function.
Also, your remote execution is only returning 1 column and you haven't defined the destination column to insert to.
The fact that the remote object is a VIEW does not matter. If we assume that the VIEW on the remote database has columns also named ID and [$shardname] then why not just use something like:
CREATE TABLE #results ([ID] int, [$shardname] varchar(500))
INSERT #results ([ID], [$shardname])
EXEC sp_execute_remote N'ExternalSource', N'SELECT [ID], [$shardname] FROM RemoteTableName'

Related

sp_executesql with user defined table type not working with two databases [duplicate]

I'm using SQL Server 2008.
How can I pass Table Valued parameter to a Stored procedure across different Databases, but same server?
Should I create the same table type in both databases?
Please, give an example or a link according to the problem.
Thanks for any kind of help.
In response to this comment (if I'm correct and that using TVPs between databases isn't possible):
What choice do I have in this situation? Using XML type?
The purist approach would be to say that if both databases are working with the same data, they ought to be merged into a single database. The pragmatist realizes that this isn't always possible - but since you can obviously change both the caller and callee, maybe just use a temp table that both stored procs know about.
I don't believe it's possible - you can't reference a table type from another database, and even with identical type definitions in both DBs, a value of one type isn't assignable to the other.
You don't pass the temp table between databases. A temp table is always stored in tempdb, and is accessible to your connection, so long as the connection is open and the temp table isn't dropped.
So, you create the temp table in the caller:
CREATE TABLE #Values (ID int not null,ColA varchar(10) not null)
INSERT INTO #Values (ID,ColA)
/* Whatever you do to populate the table */
EXEC OtherDB..OtherProc
And then in the callee:
CREATE PROCEDURE OtherProc
/* No parameter passed */
AS
SELECT * from #Values
Table UDTs are only valid for stored procs within the same database.
So yes you would have to create the type on each server and reference it in the stored procs - e.g. just run the first part of this example in both DBs http://msdn.microsoft.com/en-us/library/bb510489.aspx.
If you don't need the efficency you can always use other methods - i.e. pass an xml document parameter or have the s.p. expect a temp table with the input data.
Edit: added example
create database Test1
create database Test2
go
use Test1
create type PersonalMessage as TABLE
(Message varchar(50))
go
create proc InsertPersonalMessage #Message PersonalMessage READONLY AS
select * from #Message
go
use Test2
create type PersonalMessage as TABLE
(Message varchar(50))
go
create proc InsertPersonalMessage #Message PersonalMessage READONLY AS
select * from #Message
go
use Test1
declare #mymsg PersonalMessage
insert #mymsg select 'oh noes'
exec InsertPersonalMessage #mymsg
go
use Test2
declare #mymsg2 PersonalMessage
insert #mymsg2 select 'oh noes'
exec InsertPersonalMessage #mymsg2
Disadvantage is that there are two copies of the data.
But you would be able to run the batch against each database simultaneously.
Whether this is any better than using a table table is really down to what processing/data sizes you have - btw to use a temp table from an s.p. you just access it from the s.p. code (and it fails if it doesn't exist).
Another way to solve this (though not necessarily the correct way) is to only utilize the UDT as a part of a dynamic SQL call.
USE [db1]
CREATE PROCEDURE [dbo].[sp_Db2Data_Sync]
AS
BEGIN
/*
*
* Presumably, you have some other logic here that requires this sproc to live in db1.
* Maybe it's how you get your identifier?
*
*/
DECLARE #SQL VARCHAR(MAX) = '
USE [db2]
DECLARE #db2tvp tableType
INSERT INTO #db2tvp
SELECT dataColumn1
FROM db2.dbo.tblData td
WHERE td.Id = ' + CAST(#YourIdentifierHere AS VARCHAR) '
EXEC db2.dbo.sp_BulkData_Sync #db2tvp
'
EXEC(#SQL)
END
It's definitely not a purist approach, and it doesn't work for every use case, but it is technically an option.

How to execute sql query when debugging a stored procedure

I'm debugging a stored procedure on SQL Server 2008 and I have this:
INSERT INTO #tempTable (ID, Name)
SELECT ID, Name FROM dbo.MYTABLE WHERE dbo.MYTABLE.Old >= 15
How can I view the data into #tempTable on Debug time?
In SQL Server Management Studio, you can't execute query directly while debugging stored procedure, and that's still not implemented(I think). You can only view the local variables value in Local Debug Window.
There are some work around to see temp table values while in Debugging mode:-
1) In the stored procedure, after insert data into #temptable, add this line of code to get temptable values in xml table varriable where you want to see temptable values. Then you can check the values in Local Debug window in xml format
--inserting data into temp table
INSERT INTO #tempTable (ID, Name)
SELECT ID, Name FROM dbo.MYTABLE WHERE dbo.MYTABLE.Old >= 15
--to see records of temp table
DECLARE #temptable XML
SET #temptable = (SELECT * FROM ##temptable FOR XML AUTO)
2) You can convert local temp table(#temptable) to global temptable(##temptable), so when you insert date in temp table, you can open new query window, and able to see global temp table records using select query.
This blog post describes how to access a temporary table from another session:
http://web.archive.org/web/20180409190701/http://sqlblog.com:80/blogs/paul_white/archive/2010/08/14/viewing-another-session-s-temporary-table.aspx
Alternative you can use two ## in the table name to make the table globally accessible from other sessions: ##tempTable (The table might be locked for reading while your insert is running)
Even though SQL Server Management Studio has some debugging functions , but I find them pretty useless.
I don't think there are any debugging tools out there for SQL Server like Visual Studio, which will give you a step by step information at runtime.
The way normally developers debug sql server code is to use print statement, for stored procedures take the sp definition out declare a variable for each parameter that procedure expects , hardcode the values for variables and execute smaller logical blocks of code to see what's going on where.

How can i get all my sql server managment studio activite on my database as a executable tsql log?

We have a large Database (Many Table, SP, Function and...) and our database programers are over 10 person. All of theme can use the database on our main server computer or on his local system.
Our requirements:
we want each db programmer can apply his definitions (create table, triger, sp, fn &...) and modifications (on tables, sp, trigers, fn &...) by SQL SERVER MANAGMENT STUDIO (or your suggest tool) and get all of this activities as a TSQL Script at the end of each day.
So, we want a automatic log of our db programers activities as a TSQL script (sequence of sub tsql queries). for example:
My Activities:
My first activity>> I open my Customer table as design mode, by right
click on table and click Design. then i change datatype of ID field
from INT to BigInt. then save
My second activity>> I change
PR_Customer_Insert stored procedure and i execute it.
Now i want an executable log like this:
-- UserName: Ram
-- 2013-02-10 10:20:35
Alter Table ALTER TABLE Customer ALTER COLUMN Id TYPE bigint;
Go
-- UserName: Ram
-- 2013-02-10 10:45:00
Drop Sp DROP PROCEDURE dbo.PR_Customer_Insert;
-- UserName: Ram
-- 2013-02-10 10:45:00
Create sp CREATE PROCEDURE PR_Customer_Insert
#id int,
#name nvarchar(30) AS
INSERT INTO Customer
(
#id,
#name
)
GO
We know compare tow database is a solution but we want access to SSMS Query Pipeline...
My Questions:
Is there any way for this request (an automatically generated log that is an executable TSQL script)?
What is the best solutions for generate this scripts automatically???
What do you think about this idea in a team work on database?
Thanks...
Possible use DDL triggers, but on a certain database
Simple example:
--Create table EvtLog
CREATE TABLE EvtLog
(
LoginName NVARCHAR(100),
PostTime DATETIME,
EventType NVARCHAR(100),
TSQLCommand NVARCHAR(2000)
)
GO
--Create the DDL trigger
CREATE TRIGGER trPreventTblChange
ON DATABASE
FOR DROP_TABLE, CREATE_TABLE, ALTER_TABLE,
DROP_PROCEDURE, CREATE_PROCEDURE, ALTER_PROCEDURE
AS
DECLARE #Data XML
SET #Data = EventData()
INSERT EvtLog (LoginName, PostTime, EventType, TSQLCommand)
SELECT #Data.value('(/EVENT_INSTANCE/LoginName)[1]', 'nvarchar(100)'),
#Data.value('(/EVENT_INSTANCE/PostTime)[1]', 'nvarchar(100)'),
#Data.value('(/EVENT_INSTANCE/EventType)[1]', 'nvarchar(100)'),
#Data.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'nvarchar(2000)');
GO
Set up a database DDL trigger and use the EVENTDATA Function to find out more information about what was done and insert that into a table that you can query at the end of the day
Example
CREATE TRIGGER [LogDDL] ON DATABASE
FOR DDL_DATABASE_LEVEL_EVENTS
AS
DECLARE #xml XML;
SELECT #xml = EVENTDATA();
INSERT ChangeLog
(
ObjectName,
SQL
)
VALUES
(
#xml.value('(/EVENT_INSTANCE/ObjectName)[1]', 'sysname'),
#xml.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'nvarchar(max)')
);

SQL Server - Pass image to stored procedure, invalid local var type

I have two tables that contain document content: one for temporary staging, other for permanent storage. The content is stored as type image (cannot change this since it's current functionality).
I need a stored procedure that does the following:
Pass in a TempDocumentID that exists in temp document table.
With that TempDocumentID, select image content from temp document table.
Exec existing stored procedure that takes an image parameter to insert into permanent document table.
My problem is two-fold:
I can't declare a local variable of type 'image' to fill from the select statement of temp table. It throws error 'The text, ntext, and image data types are invalid for local variables.'
I don't know of a way to exec stored proc with direct results from select statement of temp table.
Here is my SQL Fiddle example: http://sqlfiddle.com/#!3/09384/5
Thanks,
Greg
Try this, it doesn't get an error in SQL Fiddle. I believe it will pass the result from the sub-query:
CREATE PROCEDURE MoveDocumentFromTemp
(
#TempDocumentID numeric(18,0)
)
AS
BEGIN
EXEC InsertDocumentContentFinal (SELECT TempContent
FROM DocumentContentTemp (NOLOCK)
WHERE TempDocumentID = #TempDocumentID)
END
You should be able to use VARBINARY(MAX) with SQL Server 2005 and later.
CREATE PROCEDURE MoveDocumentFromTemp
(
#TempDocumentID numeric(18,0)
)
AS
BEGIN
DECLARE #ContentToMove varbinary(max)
SELECT #ContentToMove = cast(TempContent as varbinary(max))
FROM DocumentContentTemp (NOLOCK)
WHERE TempDocumentID = #TempDocumentID
EXEC InsertDocumentContentFinal #ContentToMove
END
GO
For SQL Server 2000, you'll just have to include the INSERT code from MoveDocumentFromTemp directly into your wrapper stored procedure.

Select Values From SP And Temporary Tables

I have a Stored Procedure in MSSQL 2008, inside of this i've created a Temporary Table, and then i executed several inserts into the temporary Table.
How can i select all the columns of the Temporary Table outside the stored procedure? I Mean, i have this:
CREATE PROCEDURE [dbo].[LIST_CLIENTS]
CREATE TABLE #CLIENT(
--Varchar And Numeric Values goes here
)
/*Several Select's and Insert's against the Temporary Table*/
SELECT * FROM #CLIENT
END
In another Query i'm doing this:
sp_configure 'Show Advanced Options', 1
GO
RECONFIGURE
GO
sp_configure 'Ad Hoc Distributed Queries', 1
GO
RECONFIGURE
GO
SELECT *
INTO #CLIENT
FROM OPENROWSET
('SQLOLEDB','Server=(local);Uid=Cnx;pwd=Cnx;database=r8;Trusted_Connection=yes;
Integrated Security=SSPI',
'EXEC dbo.LIST_CLIENTS ''20110602'', NULL, NULL, NULL, NULL, NULL')
But i get this error:
Msg 208, Level 16, State 1, Procedure LIST_CLIENTS, Line 43
Invalid object name '#CLIENT'.
I've tried with Global Temporary Tables and It doesn't work.
I know that is the scope of the temporary table, but, how can i get the table outside the scope of the SP?
Thanks in advance
I think there is something deeper going on here.
One idea is to use a table variable inside the stored procedure instead of a #temp table (I have to assume you're using SQL Server 2005+ but it's always nice to state this up front). And use OPENQUERY instead of OPENROWSET. This works fine for me:
USE tempdb;
GO
CREATE PROCEDURE dbo.proc_x
AS
BEGIN
SET NOCOUNT ON;
DECLARE #x TABLE(id INT);
INSERT #x VALUES(1),(2);
SELECT * FROM #x;
END
GO
SELECT *
INTO #client
FROM OPENQUERY
(
[loopback linked server name],
'EXEC tempdb.dbo.proc_x'
) AS y;
SELECT * FROM #client;
DROP TABLE #client;
DROP PROCEDURE dbo.proc_x;
Another idea is that perhaps the error is occurring even without using SELECT INTO. Does the stored procedure reference the #CLIENT table in any dynamic SQL, for example? Does it work when you call it on its own or when you just say SELECT * FROM OPENROWSET instead of SELECT INTO? Obviously, if you are working with the #temp table in dynamic SQL you're going to have the same kind of scope issue working with a #table variable in dynamic SQL.
At the very least, name your outer #temp table something other than #CLIENT to avoid confusion - then at least nobody has to guess which #temp table is not being referenced correctly.
Since the global temp table failed, use a real table, run this when you start your create script and drop the temp table once you are done to make sure.
IF OBJECT_ID('dbo.temptable', 'U') IS NOT NULL
BEGIN
DROP TABLE dbo.temptable
END
CREATE TABLE dbo.temptable
( ... )
You need to run the two queries within the same connection and use a global temp table.
In SQL Server 2008 you can declare User-Defined Table Types which represent the definition of a table structure. Once created you can create table parameters within your procs and pass them a long and be able to access the table in other procs.
I guess the reason for such behavior is that when you call OPENROWSET from another server it firstly and separately requests the information about procedure output structure (METADATA). And the most interesting thing is that this output structure is taken from the first SELECT statement found in the procedure. Moreover, if the SELECT statement follows the IF-condition the METADATA request ignores this IF-condition, because there is no need to run the whole procedure - the first met SELECT statement is enough. (By the way, to switch off that behavior, you can include SET FMTONLY OFF in the beginning of your procedure, but this might increase the procedure execution time).
The conclusions:
— when the METADATA is being requested from a temp table (created in a procedure) it does not actually exists, because the METADATA request does not actually run the procedure and create the temp table.
— if a temp table can be replaced with a table variable it solves the problem
— if it is vital for the business to use temp table, the METADATA request can be fed with fake first SELECT statement, like:
declare #t table(ID int, Name varchar(15));
if (0 = 1) select ID, Name from #t; -- fake SELECT statement
create table #T (ID int, Name varchar(15));
select ID, Name from #T; -- real SELECT statement
— and one more thing is to use a common trick with FMTONLY (that is not my idea) :
declare #fmtonlyOn bit = 0;
if 1 = 0 set #fmtonlyOn = 1;
set fmtonly off;
create table #T (ID int, Name varchar(15));
if #fmtonlyOn = 1 set fmtonly on;
select ID, Name from #T;
The reason you're getting the error is because the temp table #Client was not declared before you ran the procedure to insert into it. If you declare the table, then execute the list proc and use direct insert -
INSERT INTO #Client
EXEC LIST_CLIENTS