Can the select query inside a from clause be a dynamic sql?
For example
DECLARE #sql NVARCHAR(MAX)
SET #sql='SELECT * table'
SELECT t.*, a+b AS total_sum
FROM
(
EXEC (#sql)
) t
If the above is not possible, how can we achieve this functionality?
Of course the above query result in Error when run in sql server.
Thank you for the help.
In order to use dynamic table in from clause , you must run command EXEC(#sql) outside :
In your above example :
DECLARE #sql NVARCHAR(MAX)
DECLARE #dynamicSql NVARCHAR(MAX)
SET #sql='SELECT * table'
SET #dynamicSql ='SELECT t.*, a+b AS total_sum
FROM
(
'+#sql+'
) t'
EXECUTE sp_executesql #dynamicSql
In SQL Server, a SQL statement is compiled the first time the database sees it. This means that anything that can change the code being generated can't be a parameter. Which in turn means that you can't use parameters for...
table names
join expressions
column names
where clauses
order by clause
In fact, you could say that you are more or less limited to using parameters for...
Literal values in comparisons MyColumn = #Param1
Literal values in select statements SELECT #Param2
Literal values in insert/update statements SET Column = #Param3
Top, limit, and fetch clauses SELECT TOP #Param4
As mentioned elsewhere, the work-around is to create your SQL as a string and then pass that string to sp_executesql.
Deep notes:
SQL is normally compiled into an intermediate language. This intermediate language can be viewed as XML. See "execution plans" for more information.
In SQL Server 2014, stored procedures can be converted into C++ code and then compiled to machine language. There are a lot of restrictions when doing this that are too much to discus here.
Related
I have a query I build into a NVARCHAR due to an issue between SQL Server and a linked Oracle server forcing me to use OpenQuery. It works fine and I get the results I need when I run exec (#OPENQUERYFULL).
My results are a single column of numbers I need for another query. I would like to be able to use those results as an "IN ()" statement or as a JOIN but what I have tried so far has failed.
Is there a way to use the results of an exec query directly in another query?
UPDATE:
To be clear I was trying to avoid using a temp table.
Declare a table variable and insert the results of the other SP into that variable:
declare #results table (
numbers int
);
GO
insert into #results(numbers)
exec otherSP
Then you perform your join on the table variable.
You can send the linked server query with OPENQUERY instead of 'exec' by building a dynamic query with OPENQUERY and a join. It just takes some annoying string escaping, eg:
declare #oracleSQL nvarchar(max) = 'select 1 a, ''hello'' b from dual';
declare #sql nvarchar(max) = concat(
N'
with q as
(
SELECT * FROM OPENQUERY (OracleSvr, N''', replace(#oracleSQL,'''','''''') ,N''')
)
select *
from q
cross join sys.objects o
')
print #sql
exec ( #sql )
But as you can see the resulting code is a bit complicated. So I would almost always just use a temp table.
Need help to figure ut why the remote query I execute on the server return 0 rows , but the same query returns over 900k rows in the target DB.
the string is less 8000 characters long so I won't post it here. but this is the sctructure basically:
declare #SQL varchar(MAX);
declare #D varchar(15);
declare #Per varchar(15);
declare #NextPer varchar(15);
declare #NextYPer varchar(15);
set #D = N'01-JUN-2019'
set #Per = N'2020004';
set #NextYPer = N'2021004'
set #NextPer = N'2020005'
set #SQL = N' SELECT ...... '
set #SQL = N'select * from openquery ([LK1], "'+#SQL+'")';
execute( #SQL);
print #SQL;
Note: the linked server works and is used on other openqueries with shorter strings successfully. I tried using EXECUTE (#SQL) AT and I still get 0 rows. When i exexute the print output directly on the Oracle DB , the query runs for about 15 min and gives results.
First off, OPENQUERY requires the second parameter to be a query string. A string in SQL Server is written between single quotes. From OPENQUERY documentation:
OPENQUERY ( linked_server ,'query' )
Not only that, the SQL that appears in that string, needs to have any single-quotes that appear in the query to be doubled. Suppose you had SQL you wanted to execute the following query:
SELECT * FROM some_table WHERE name='TT.';
You would write this as:
OPENQUERY(lks,'SELECT * FROM some_table WHERE name=''TT.''')
But if you have this in a dynamic SQL statement, this would become
DECLARE #s VARCHAR(MAX);
SET #s='SELECT * FROM OPENQUERY(lks,''SELECT * FROM some_table WHERE name=''''TT.'''''')';
So that's some explosion of single quotes for even the more trivial SQL queries. Count ye quotes, make sure the query itself is up to snuff (i.e. quotes have been properly doubled).
Thanks all for the input.
The root cause is simply the format of the Date parameter, which didn't run correctly on the linked server.
All I had to do is change my query to use this:
SO_BOOK_DATE < to_date(''#D'' , ''DD-MON-YYYY'')
instead of
SO_BOOK_DATE < ''#D'' .
I have this query in SQL Server:
select column
from table_53;
Now, I want to get this 53 from another table, so what I want to do is something like this:
select column
from table_(select id from table2);
Is there any way to do this in SQL Server?
This is definitely not the way SQL thinks and works. Maybe your suggested approach can be mimicked by way of writing stored procedures in which you create SQL-statements which are then evaluated. However, this will not be very efficient.
A better approach would be to store the values of all your individual separate tables into one master table and mark them in a separate column tblid with their number (e.g. 53). Then you can always filter them from this master table by looking for this tblid.
You need dynamic sql query here.
declare #sqlQuery = 'select column
from table_(';
set #sqlQuery = #sqlQuery + 'select id from table2)';
EXEC (#sqlQuery)
Note :- One of cons of using dynamic sql query is sql injection. I would suggest to have better table structure or try to used parameterized query.
Yes, you can, but using something like this:
DECLARE #ID INT;
DECLARE #QUERY NVARCHAR(MAX);
SELECT #ID = ID FROM TABLE_2;
--IF #ID EQUALS 53 THEN
SET #QUERY = 'SELECT COLUMN FROM TABLE_' + CAST(#ID AS NVARCHAR(10));
-- #QUERY EQUALS TO 'SELECT COLUMN FROM TABLE_53'
EXEC (#QUERY);
Is it possible to execute a sql statement containing variable?
DECLARE #SCHEMA varchar(40)
set #SCHEMA='X_SLF'
select * from #SCHEMA..Acc_tblCompany --// anyway to use this type of statement?
--below statement works
select * from X_SLF..Acc_tblCompany
--I don't want to do this following solution:
DECLARE #Sql nvarchar(80)
set #Sql=' select * from '+#SCHEMA+'..Acc_tblCompany'
Execute sp_executesql #Sql
Perhaps you could implement this as a case statement. It's not quite what you're asking for, but at least you can create the illusion to the caller that it's parameterized wrt schema
I have a stored procedure for selecting rows. I want to pass a parameter to filtering rows dynamically like this :
Create Procedure CustomerSelectAll
#FilterExpresion NVARCHAR(MAX)
DECLARE #CMD NVARCHAR(MAX)
SET #CMD = N'SELECT * FROM dbo.Customers '+#FilterExpresion;
EXEC(#CMD)
The above code works fine, but it is at risk for SQL injection, so I want to be able pass multiple columns with any WHERE statement such as:
exec CustomerSelectAll
#FilterExpresion = N' where Name = 'abc' and family = ''xyz'''
I am not aware if you can pass the entire where clause as parameter.But from the little amount of knowledge I have, I can suggest you use a sql parser to see if the where clause has just select statements and if the answer is affirmative then you can pass the where clause to your stored procedure. Hope this is of some help.