This is my first post to StackOverflow. I've been using this amazing resource for a number of years to answer hundreds of SQL and PowerShell questions, however this one has me stumped for a number of days.
I am using SQL Server 2014 SP2 and I am trying to do an update to DATABASE1, FIELD1, then FIELD2 then FIELD3 from multiple other database.
FIELD1 may exist in one of multiple other databases.
FIELD1 may not exist in ALL databases - which is where I have the problem.
Database Design Link
I have the following (anonymised) query and it appears to be working:
EXEC sp_MSforeachdb 'IF ''?'' IN (''DATABASE2'',''DATABASE3'',''DATABASE4'')
BEGIN
UPDATE DATABASE1.PARAMETER
SET B.[VALUE] = A.[FIELD1]
FROM DATABASE1.TABLE1 B
INNER JOIN ?.dbo.[TABLE2] A
ON A.JOINVALUE = B.JOINVALUE
WHERE B.COLUMN2 = ''SOMETHING''
AND COLUMN3= ''PF.T.FIELD1''
END ;'
Until I get to say FIELD8, as it exists in DATABASE1 but not in DATABASE2, DATABASE3 or DATABASE4. I then get the following error:
Msg 207, Level 16, State 1, Line 30
Invalid column name 'FIELD8'.
From my Google and StackOverflow searches, I've tried to use (for the first time) a:
IF EXISTS (SELECT COLUMN1 FROM Database2.Table2 WHERE Column1='Field8')
EXEC .......
But that's where I started to really struggle.
Hope the above makes sense.
Any tips or assistance would be greatly appreciated.
N.B. I have about 3,000 fields in Database1 which require updating. I've so-far built all my UPDATE statements dynamically.
You can create stored proc, that will search for columns and tables in system tables:
ALTER PROCEDURE dbo.check_table_exists
-- Add the parameters for the stored procedure here
#table_name nvarchar(255),
#column_name nvarchar(255)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
DECLARE #SQLString nvarchar(max),
#ParmDefinition nvarchar(500) = N'#table_name nvarchar(255), #column_name nvarchar(255)';
IF OBJECT_ID(N'tempdb..#check_column_exists') is not null DROP TABLE #check_column_exists
CREATE TABLE #check_column_exists (
db nvarchar(500) NULL,
column_exists bit NULL
)
SELECT #SQLString =
(
SELECT N'USE '+QUOTENAME([name]) +'; '+
'INSERT INTO #check_column_exists '+
'SELECT '''+[name]+''' as [db], '+
' COUNT(*) as column_exists ' +
'FROM sys.tables t ' +
'INNER JOIN sys.columns c ' +
' ON t.[object_id] = c.[object_id] ' +
'WHERE t.[name] = #table_name and c.[name] = #column_name; '
FROM sys.databases
WHERE [name] NOT IN (
'msdb',
'model',
'tempdb',
'master'
)
FOR XML PATH('')
) + 'SELECT [db] FROM #check_column_exists WHERE column_exists = 1; DROP TABLE #check_column_exists;'
EXEC sp_executesql #SQLString, #ParmDefinition, #table_name = #table_name, #column_name = #column_name
END
GO
You can change it to search only for columns and output the database and table name or whatever.
The output is:
db
-----------
DATABASE1
DATABASE4
...
etc
After that you can write this to table and use for dynamic SQL update query:
DECLARE #table_name nvarchar(255) = 'SomeTable',
#column_name nvarchar(255) = 'SomeField'
DECLARE #results TABLE (
db nvarchar(500)
)
INSERT INTO #results
EXEC dbo.check_table_exists #table_name, #column_name
--...Here goes building of dynamic SQL query to update data
First, sp_MSforeachdb is not reliable. For a working alternative, check here: Making a more reliable and flexible sp_MSforeachdb - Aaron Bertrand
Second, you can use system views to check if a column exists in a given table using sys.columns like so:
if exists (
select 1
from sys.columns c
where c.name = 'pilots_id' /* column name */
and c.object_id = object_id(N'pilots') /* table name */
)
begin
select 'Pilots_Id exists' /* do stuff */
end
rextester demo: http://rextester.com/UUXCB18567
Related
I'm trying to fetch the data in a specific table name by passing tableName as a parameter to the stored procedure.
CREATE PROCEDURE schemaName.spDynamicTableName
#tableName NVARCHAR(100)
AS
BEGIN
DECLARE #sql nvarchar(max)
SET #sql = 'SELECT * FROM ' + #tableName
EXECUTE sp_executesql #sql
END;
--> EXEC schemaName.spDynamicTableName 'Employee';
Now, how can I pass list of table names to a procedure so that procedure will iterate over the list of table names and fetch the data from all the tables?
Ok, let's start off with the problems you have in your current set up. Firstly it sounds like you have a design flaw here. Most likely you are using a table's name to infer information that should be in a column. For example perhaps you have different tables for each client. In such a scenario the client's name should be a column in a singular table. This makes querying your data significantly easier and allows for good use for key constraints as well.
Next, your procedure. This is a huge security hole. The value of your dynamic object is not sanitised nor validated meaning that someone (malicious) has almost 100 characters to mess with your instance and inject SQL into it. There are many articles out there that explain how to inject securely (including by myself), and I'm going to cover a couple of processes here.
Note that, as per my original paragraph, you likely really have a design flaw, and so that is the real solution here. We can't address that in the answers here though, as we have no details of the data you are dealing with.
Fixing the injection
Injecting Securely
The basic's of injecting a dynamic object name is to make it secure. You do that by using QUOTENAME; it both delimit identifies the object name and escapes any needed characters. For example QUOTENAME(N'MyTable') would return an nvarchar with the value [MyTable] and QUOTENAME(N'My Alias"; SELECT * FROM sys.tables','"') would return the nvarchar value "My Alias""; SELECT U FROM sys.tables".
Validating the value
You can easily validate a value by checking that the object actually exists. I prefer to do this with the sys objects, so something like this would work:
SELECT #SchemaName = s.[name],
#TableName = t.[name]
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.schema_id
WHERE s.[name] = #Schema --This is a parameter
AND t.[name] = #Table; --This is a parameter
As a result, if the FROM returns no values, then the 2 variables in the SELECT won't have a value assigned and no SQL will be run (as {String} + NULL = NULL).
The Solution
Table Type Parameter
So, to allow for multiple tables, we need a table type parameter. I would create one with both the schema and table name in the columns, but we can default the schema name.
CREATE TYPE dbo.Objects AS table (SchemaName sysname DEFAULT N'dbo',
TableName sysname); --sysname is a sysnonym for nvarchar(128) NOT NULL
And you can DECLARE and INSERT into the TYPE as follows:
DECLARE #Objects dbo.Objects;
INSERT INTO #Objects (TableName)
VALUES(N'test');
Creating the dynamic statement
Assuming you are using a supported version of SQL Server, you'll have access to STRING_AGG; this removes any kind of looping from the procedure, which is great for performance. If you're using a version only in extended support, then use the "old" FOR XML PATH method.
This means you can take the values and create a dynamic statement along the lines of the below:
SET #SQL = (SELECT STRING_AGG(N'SELECT * FROM ' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.[name]) + N';',' ')
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.schema_id
JOIN #Objects O ON s.name = O.SchemaName
AND t.name = O.TableName);
The Stored Proecure
Putting all this together, this will give you a procedure that would look like this:
CREATE PROC schemaName.spDynamicTableName #Objects dbo.Objects AS
BEGIN
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SET #SQL = (SELECT STRING_AGG(N'SELECT N' + QUOTENAME(t.[name],'''') + N',* FROM ' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.[name]) + N';',#CRLF) --I also inject the table's name as a column
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.schema_id
JOIN #Objects O ON s.name = O.SchemaName
AND t.name = O.TableName);
EXEC sys.sp_executesql #SQL;
END;
And then you would execute it along the lines of:
DECLARE #Objects dbo.Objects;
INSERT INTO #Objects (SchemaName,TableName)
VALUES(N'dbo',N'MyTable'),
(N'dbo',N'AnotherTable');
EXEC schemaName.spDynamicTableName #Objects;
This one accepts a comma delimited list of tables and guards against SQL injection with a simple QUOTENAME escape (not sure if this is quite enough though):
IF OBJECT_ID('dbo.spDynamicTableName') IS NOT NULL DROP PROC dbo.spDynamicTableName
GO
/*
EXEC dbo.spDynamicTableName 'Students,Robert--
DROP TABLE Students'
*/
CREATE PROC dbo.spDynamicTableName
#tableName NVARCHAR(100)
AS
BEGIN
DECLARE #sql nvarchar(max)
SELECT #sql = STRING_AGG('SELECT * FROM ' + QUOTENAME(value), ';')
FROM STRING_SPLIT(#tableName, ',')
--PRINT #sql
EXEC dbo.sp_executesql #sql
END;
GO
There are two ways you can do this: use a string that contains the names you want and are separated by a special character as:
Table1, Table2, Table3
and split it in the stored procedure (check this)
The second method: make a typo as follows:
CREATE TYPE [dbo].[StringList] AS TABLE
(
[TableName] [NVARCHAR(50)] NULL
)
Add a parameter for your stored procedure as StringList:
CREATE PROCEDURE schemaName.spDynamicTableName
#TableNames [dbo].[StringList] READONLY,
AS
BEGIN
END;
Then measure its length using the following code and make a repeat loop::
DECLARE #Counter INT
DECLARE #TableCount INT
SELECT #TableCount = Count(*), #Counter = 0 FROM #TableNames
WHILE #Counter < #TableCount
BEGIN
SELECT #TableName = Name
FROM #TableNames
ORDER BY Name
OFFSET #Counter ROWS FETCH NEXT 1 ROWS ONLY
SET #sql = 'SELECT * FROM ' + #TableName
EXECUTE sp_executesql #sql
SET #Counter = #Counter + 1
END
My procedure has two parameters:
#schemaName as sysname
#tableName as sysname
Inside the procedure, I want to copy data from table schemaName.tableName to the new temporary table # tmpTable1 .
My default schema in the database is schemaX, not dbo and I am not the dbo user.
Create procedure copy_data_to_temp
#schemaName as sysname,
#tableName as sysname
AS
Begin
Exec('select * into #tmpTable1 from ' + #schemaName + '.' + #tableName)
Select * from #tmpTable1 – does not work, because after dynamic SQL #tmpTable1 does not exist
END
I have tried:
-- Exec('Select * into Tdummy from ' + #schemaName + ’.’ + #tableName + ' where 1=2'’)
-- Select * into #tmpTable1 from Tdummy -- Gives error: Invalid object name 'Tdummy', when I am not dbo user and my default schema is schemaX not dbo.
-- Exec('Insert into #tmpTable1 select * from '+ #schemaName + '.' + #tableName)
There are 2 problems here. Firstly, what you have is dangerously open to Injection. That must be fixed. I cannot stress that more than anything in this answer. If you learn nothing else from this, learn to write secure dynamic statements.
Secondly, temporary objects only persist for the duration of the scope you define them in. For the above, that's the duration of the dynamic statement, and that is it.
This, however, has a strong "code smell" of being an XY Problem but I'll go on to answering this anyway.
You'll need to create a persisted object and then SELECT from that in the procedure, and then "clean up":
CREATE PROC dbo.copy_data_to_temp #SchemaName sysname, #TableName sysname AS
BEGIN
DECLARE #SQL nvarchar(MAX);
DROP TABLE IF EXISTS tempdb.dbo.tmpTable;
SELECT #SQL = N'SELECT * INTO tempdb.dbo.tmpTable FROM ' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.[name]) + N';'
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.schema_id
WHERE s.name = #SchemaName
AND t.[name] = #TableName;
EXEC sys.sp_executesql #SQL;
SELECT *
FROM tempdb.dbo.tmpTable;
--DROP TABLE tempdb.dbo.tmpTable;
END;
Of course, the SELECT ... INTO tmpTable ... FROM {dynamic object} followed by the SELECT ... FROM tmpTable might as well just be a SELECT ... FROM {dynamic object}, and why this looks like a XY Problem.
When using Dynamic SQL, you need to make sure you use it properly and safely. Rather than repeating myself, you can learn a lot from my article Dos and Don'ts of Dynamic SQL.
Declare the #temp table before using exec and then also add INSERT INTO
create table #temp
(
...
)
insert into #temp
Exec (...)
-- return results from exec
Select * from #temp
I am writing a stored proc that needs to search a database for all tables that have a certain column name. Once I get a list of tables that have that column I need to update a value in that column. So first I get a list of tables that have a certain column.
SELECT c.name AS 'ColumnName'
,t.name AS 'TableName'
FROM sys.columns c
JOIN sys.tables t ON c.object_id = t.object_id
WHERE c.name LIKE 'company'
ORDER BY TableName
Now that I have a list of tables that need to be updated I need to run a query similar to the following to update the data in each table.
update table1 set company = #newValue where company = #oldvalue
I'm not sure how to go about writing this part. My first thought was to write a dynamic update statement inside of a cursor like:
Declare #newValue
Declare #oldValue
SET #companyCursor = CURSOR FOR
SELECT t.name AS 'TableName'
FROM sys.columns c
JOIN sys.tables t ON c.object_id = t.object_id
WHERE c.name LIKE 'company'
OPEN #companyCursor;
FETCH NEXT FROM #companyCursor INTO #tableName;
WHILE ##FETCH_STATUS = 0
BEGIN
update #tableName set company = #newValue where company = #oldValue
FETCH NEXT FROM #companyCursor INTO INTO #tableName;
END
Is this a good strategy?
I really dislike cursors so even in cases like this where a cursor is a viable solution I like to leverage the system views to avoid looping. You still have to use dynamic sql because object names cannot be parameterized.
Please note that I am guessing the datatype for company here and you can change this easily. Make sure you change the variable definition both in your script AND in the dynamic sql. You entire script could be shortened to something like this.
declare #SQL nvarchar(max) = ''
, #newValue varchar(10) = 'new'
, #oldValue varchar(10) = 'old'
select #SQL = #SQL + 'Update ' + quotename(object_name(c.object_id)) + ' set company = #newValue where company = #oldValue;'
from sys.columns c
where c.name = 'company'
select #SQL
--uncomment the line below when you are satisfied the dynamic sql is correct.
--This dynamic sql is parameterized as much as possible
--exec sp_executesql #SQL, N'#newValue varchar(10), #oldValue varchar(10)', #newValue = #newValue, #oldValue = #oldValue
No the update at the end will not work. You need to use exec (#sql) like this:
declare #sql varchar(4000)
begin
set #sql = 'update ' + #tableName + 'set company = ' + #newValue + 'where company = ' + #oldValue
exec (#sql)
fetch next ...
end
This assumes that #newvalue and #oldvalue are being assigned values somewhere.
I have to check for value existence in a subset of tables in a subset of databases of a sql server instance. Beware I need to do this because I have 30 databases with same schema name and similar structure. Querying all databases separately is a waste of time.
The query generates correctly code for existing tables, but the additional check for column existence in table fails.
The column in some tables does not exist so the generated code must not include queries on tables without this column.
To solve this I need to realiably find a way to join sys.databases with sys.tables and then sys.columns. Or an alternative way to query all the required databases in a time saving manner.
SET NOCOUNT ON;
IF OBJECT_ID (N'tempdb.dbo.#temp') IS NOT NULL
DROP TABLE #temp
CREATE TABLE #temp
(
exist INT
, DB VARCHAR(50)
, tbname VARCHAR(500)
)
/*tables common root,
all tables i need to query start with this prefix and a number between 1 and 50
and some resulting tables do not exist
ex: dbo.Z_WBL_ASCHEDA23 exist in wbcto, while dbo.Z_WBL_ASCHEDA23 does not exist in db wbgtg
*/
DECLARE #TableName NVARCHAR(200)
SELECT #TableName = 'dbo.Z_WBL_ASCHEDA'
DECLARE #SQL NVARCHAR(MAX)
;WITH n(n) AS
(
SELECT 1
UNION ALL
SELECT n+1 FROM n WHERE n < 50
)
SELECT #SQL = STUFF((
SELECT CHAR(13)+'SELECT COUNT(1), ''' + db.name + ''', '''+
#TableName+CONVERT(VARCHAR, n.n)+''' FROM ' +#TableName+CONVERT(VARCHAR, n.n)
+ ' WHERE COALESCE(s_dettagli,'''') = ''CONTROLLATO'' '
+CHAR(13)
FROM sys.databases db
INNER JOIN n ON 1=1
INNER JOIN sys.tables t ON OBJECT_ID(db.name + '.' + #TableName+CONVERT(VARCHAR, n.n)) IS NOT NULL
INNER JOIN sys.columns c ON t.OBJECT_ID = c.OBJECT_ID and c.name = 's_dettagli'
/*join on columns not working, generates sql for tables without 's_dettagli' column and query fails*/
WHERE db.name like 'wb%' --check only databases starting with 'wb'
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
select #SQL
INSERT INTO #temp (exist, DB, tbname)
EXEC sys.sp_executesql #SQL
SELECT *
FROM #temp t
where exist <> 0
EDIT: adding some sql generated from query
SELECT COUNT(1), 'wb360', 'dbo.Z_WBL_ASCHEDA23' FROM wb360.dbo.Z_WBL_ASCHEDA23 WHERE COALESCE(s_dettagli,'') = 'CONTROLLATO'
SELECT COUNT(1), 'Wbbim', 'dbo.Z_WBL_ASCHEDA32' FROM Wbbim.dbo.Z_WBL_ASCHEDA32 WHERE COALESCE(s_dettagli,'') = 'CONTROLLATO'
the table of first query doesn't contain 's_dettagli' column
EDIT2: SOLUTION
EXEC sp_MSforeachdb '
IF ''?'' not like ''wb%''
RETURN
USE [?]
EXEC sp_MSforeachtable
#replacechar = ''!'',
#command1 = ''SELECT ''''?'''' AS db_name, ''''!'''' AS table_name, COUNT(*) FROM ! '',
#whereand = '' And Object_id In (
Select t.Object_id
From sys.objects t
INNER JOIN sys.columns c on c.Object_id = t.Object_id
Where t.name like ''''Z_WBL_ASCHEDA%''''
AND c.name = ''''s_dettagli'''' )'' '
Sys.columns can be joined to sys.tables using the object_id field (the object_id is the representation of the table itself).
sys.tables is run in the context of the database you are querying, hence you cannot see a table contained in another database. sys.databases can be run on any database on an instance and allow you to view other databases on the same instance. As such you don't need to join the table to the database (also the reason why there is no database_id field within sys.tables).
I hope that helps. Any clarification please let me know.
I would suggest alternative ways:
use registered Servers in SSMS and run the script on each database here
use exec sys.sp_MSforeachdb here
use sqlcmd and powershell to switch databases
I believe this script can help you :
SET NOCOUNT ON;
IF OBJECT_ID (N'tempdb.dbo.#Temp') IS NOT NULL
DROP TABLE #Temp
CREATE TABLE #Temp
(
exist INT
, DB VARCHAR(50)
, tbname VARCHAR(500)
)
DECLARE #SchemaName NVARCHAR(200)
DECLARE #TableName NVARCHAR(200)
DECLARE #ColumnName NVARCHAR(200)
DECLARE #SearchText NVARCHAR(200)
DECLARE #DBNameStartWith NVARCHAR(200)
DECLARE #SQL NVARCHAR(MAX)
SET #DBNameStartWith = 'wb'
SET #SchemaName = 'dbo'
SET #TableName = 'Z_WBL_ASCHEDA'
SET #ColumnName = 's_dettagli'
SET #SearchText = 'CONTROLLATO'
DECLARE #DatabaseName varchar(100)
DECLARE Crsr CURSOR FOR
SELECT name
FROM MASTER.sys.sysdatabases
WHERE name LIKE ''+#DBNameStartWith+'%'
OPEN Crsr
FETCH NEXT FROM Crsr INTO #DatabaseName
WHILE ##FETCH_STATUS = 0
BEGIN
IF ISNULL((SELECT COUNT(1) FROM SYS.TABLES T,SYS.COLUMNS C WHERE T.object_id=C.object_id AND T.name=#TableName AND C.name=#ColumnName),0)>0
BEGIN
SET #SQL = '
IF EXISTS (SELECT 1 FROM '+#DatabaseName+'.SYS.TABLES T,'+#DatabaseName+'.SYS.COLUMNS C WHERE T.object_id=C.object_id AND T.name='''+#TableName+''' AND C.name='''+#ColumnName+''')
BEGIN
SELECT COUNT(1),'''+#DatabaseName+''','''+#TableName+'''
FROM '+#DatabaseName+'.'+#SchemaName+'.'+#TableName+'
WHERE '+#ColumnName+'=''' +#SearchText+'''
END'
PRINT(#SQL)
INSERT INTO #Temp
EXEC sp_executesql #SQL
END
FETCH NEXT FROM Crsr INTO #DatabaseName
END
CLOSE Crsr
DEALLOCATE Crsr
SELECT * FROM #Temp
EDIT: Some of those who would offer help are unclear about the nature of the requirement, so I will try to state it as clearly as I can:
We need to instantiate a view of an underlying table, and this view must be able to be joined to another table; the difficulty is that the identity of the underlying table is not known until runtime of the ad hoc query doing the join.
We would like to do something like this:
select * from foo
inner join dynamicallyInstantiatedTable(condition) DT
on foo.zipcode = DT.zipcode
It doesn't seem possible to create a function that returns TABLE if the function uses dynamic SQL. This is not valid:
declare #tablename varchar(50);
-- <snip> code to determine the name of #tablename
declare #statement varchar(1000);
set #statement = 'select * from ' + #tablename;
exec( #statement);
The error:
Invalid use of a side-effecting operator 'EXECUTE STRING' within a
function.
If the table name is not known beforehand for whatever reason (e.g. tables are constantly being added and we must select against the most recent one, say), is it possible to do the select dynamically and return a table, either in a stored proc or function?
Here we go.
I don't use synonyms often, but CREATE SYNONYM supports dynamic SQL.
declare #tablename nvarchar(128);
-- <some code to set #tablename>
declare #sql nvarchar(500);
if object_id(N'dbo.TodaysData', N'SN') is not null
drop synonym dbo.TodaysData;
set #sql =
'create synonym dbo.TodaysData
for ' + #tablename;
execute(#sql);
select top 5
*
from
dbo.TodaysData as t
join
dbo.SomeOtherTable as s
on
s.FieldName = t.HeresHopingYourSchemaDoesntChange
Dynamic SQL in function. No.
is it possible to do the select dynamically and return a table, either
in a stored proc or function?
Perhaps I'm missing something (would not be a first) but this seems simple as a stored proc:
The Proc
create proc dbo.getRowsFrom #tablename varchar(50) as
exec('select * from ' + #tablename);
Use
exec dbo.getRowsFrom '<my table>';
Is that what you're looking for?
you should once explain your requirement with example.It is not clear to anybody.
I think everything thing can be done within single proc,no need of another proc or UDF.
declare #tblname varchar(500)
select #tblname=name from sys.objects
where type_desc ='USER_TABLE'
order by create_date DESC
declare #Sql varchar(max)=''
set #Sql='select * into #tmp from '+#tblname+' '
set #Sql=#Sql+' select * from #tmp drop table #tmp'
exec (#Sql)
Little detail given about your 'join' situation, but it might be easier to jump to your final joined results, rather than focusing on the input table in isolation.
Here I am joining my input table 'a' to a lookup table 'ref', and outputting joined results.
If tomorrow your have another input table 'b' - this proc will join that to the lookup table instead.
The only requirement is that the join column is consistent.
declare
#inputTableName nvarchar(128)
,#sqlExec nvarchar(max)
set #inputTableName = 'b';
if(not exists (select 1 from INFORMATION_SCHEMA.TABLES where table_schema = 'test' and TABLE_NAME = 'myView'))
begin
select #sqlExec = 'create view test.myView as
select I.*,R.[text] from test.[' + #inputTableName + '] I inner join test.ref R on I.col0 = R.col0'
end else begin
select #sqlExec = 'alter view test.myView as
select I.*,R.[text] from test.[' + #inputTableName + '] I inner join test.ref R on I.col0 = R.col0'
end
exec (#sqlExec)
select * from test.myView