I am trying to combine the SQL queries and getting the below error.
The name 'SELECT id,tbprojectnumber, importdatetime FROM [TestDatabase].[landing].[details]' is not a valid identifier.
DECLARE #Q1 varchar(5000)
SELECT #Q1 = 'SELECT id,tbprojectnumber, importdatetime'
DECLARE #Q3 varchar(5000)
SELECT #Q3 ='FROM [TestDatabase].[landing].[details]'
DECLARE #Q5 varchar(5000)
SELECT #Q5 = #Q1 +' '+#Q3
EXEC #Q5
when I am running query
SELECT id,tbprojectnumber, importdatetime
FROM [TestDatabase].[landing].[details]
I am able to get the results.
SET the variable value :
SET #Q5 = #Q1 +' '+#Q3
PRINT #Q5 -- Check before execution.
EXEC sp_executesql #Q5;
Use NVARCHAR() type while preparing dynamic queries.
For your sample data, you don't need to use two separate variable.
Related
How can I get the output of the below query in a variable without temp table?
DECLARE #Q1 NVARCHAR(300)
DECLARE #Q2 NVARCHAR(300)
DECLARE #Q3 NVARCHAR(300)
SET #Q1 = 'SELECT ' +' ' + #formfieldpath
SET #Q2 = 'FROM [TestDatabase].[details] WHERE id ' + '=''' + CAST(#id AS VARCHAR(10)) + '''';
SET #Q3 = #Q1 +' '+ #Q2
PRINT #Q3
EXEC sp_executesql #Q3
Tried 'How to get sp_executesql result into a variable?' and not able to get the results.
Assuming that you get a singleton value from your dynamic statement:
DECLARE #ID int, --Is set somewhere
#YourVariable nvarchar(30), --Use an appropriate data type
#formfieldpath sysname; --Is set somewhere
DECLARE #SQL nvarchar(MAX);
--I assume that the name [TestDatabase].[details] is wrong, as [TestDatabase] would be the name of the schema, not the database,
--and I ASSUME you haven't foolishy created a schema called "TestDatabase"
SET #SQL = N'SELECT #YourVariable = ' + QUOTENAME(#formfieldpath) + N' FROM dbo.Details WHERE id = #id';
--Use the correct datatype for #YourVariable
EXEC sys.sp_executesql #SQL, N'#id int, #YourVariable nvarchar(30) OUTPUT', #id, #YourVariable OUTPUT;
Never inject unsanitised values into a dynamic SQL statement. SQL injection is a huge problem that should have stopped existing over a decade ago. Dos and Don'ts of Dynamic SQL
I need to pass a table var to sp_executesql statement. Do you know how can I pass the table variable to sp_executesql?
Here is how I pass the regular variable (not table variable) to sp_executesql
EXEC sp_executesql #statement, N'#Status INT',#Status
Typically you don't pass a table variable to execute SQL with sp_executesql. You make a statement up out of text and execute that. Like so:
IF OBJECT_ID('tempdb..#People') IS NOT NULL
DROP TABLE tempdb..#People
CREATE TABLE #People (PersonId INT IDENTITY, PersonName VARCHAR(128));
INSERT INTO #People (PersonName) VALUES ('Brett'), ('John'), ('Mark'), ('Shawn'), ('Ryan'), ('Kevin');
DECLARE #SQL NVARCHAR(Max) = 'Select * from #People'
EXEC sp_executesql #Sql
UPDATE 1-27-17
IF OBJECT_ID('tempdb..#People') IS NOT NULL DROP TABLE tempdb..#People
IF OBJECT_ID('tempdb..#People2') IS NOT NULL DROP TABLE tempdb..#People2
CREATE TABLE #People (PersonId INT IDENTITY, PersonName VARCHAR(128));
CREATE TABLE #People2 (PersonId INT IDENTITY(7,1), PersonName VARCHAR(128));
SET NOCOUNT ON;
INSERT INTO #People (PersonName) VALUES ('Brett'), ('John'), ('Mark'), ('Shawn'), ('Ryan'), ('Kevin');
INSERT INTO #People2 (PersonName) VALUES ('Emily'), ('Beth'), ('Jane'), ('Hannah');
--I. getting an output for a single output variable dynamically
--Say I just want to get Ryan by his Id dynamically and output it
--I need to define one or many parameters OUTSIDE the scope of the Dynamic Sql
DECLARE #Output VARCHAR(8)
DECLARE #PersonId INT = 5
--I then need to associate the parameters as an array, for the purposes of explanation I will use DIFFERENT NAMES you may use the same
DECLARE #ParmDefinition NVARCHAR(500) = N'#PersonIdInside Int, #OutputInside varchar(8) OUTPUT'
--I then use the names ABOVE in the dynamic sql
DECLARE #SQL NVARCHAR(Max) = N'Select #OutputInside = PersonName from #People Where PersonId = #PersonIdInside'
-- I then do the following AFTER the sp_executesql 1. The Dynamic sql nvarchar, 2. The params nvarchar 3. one or many variables and how they associate
EXEC sp_executesql #Sql, #ParmDefinition, #PersonIdInside = #PersonId, #OutputInside = #Output OUTPUT
-- I have an output so now it should show what I want
SELECT #Output
-- II. getting a result set dymamically to another record set or table OUTSIDE the scope of the internal
-- Create another table, I use a #table for example purposes
IF OBJECT_ID('tempdb..#Output') IS NOT NULL DROP TABLE tempdb..#Output
CREATE TABLE #Output (PersonId INT IDENTITY, PersonName VARCHAR(8))
--Get a truncated list for an 'in' statement later of person Id's in a variable
DECLARE #People NVarchar(32) = N'1, 5, 10'
--I then use the #People ABOVE in the dynamic sql putting it together and then do an 'insert statement first'
DECLARE #SQL2 NVARCHAR(Max) = N'Insert Into #Output SELECT PersonName FROM (SELECT * FROM #People UNION SELECT * FROM #People2) as x Where PersonId in (' + #People + ')'
--execute yields nothing
EXEC sp_executesql #Sql2
-- or does it?
Select *
From #Output
-- !!! WARNING !!!
-- With dynamic sql you cannot nest multiple dynamic sql statements inside of procs. EG: Proc1 cannot call Proc2 and both of them have dynamic sql in them. Engine limitation.
DECLARE #query as varchar(200);
SET #query = 'SELECT COUNT(*) FROM table';
How can I execute #query, and additionally, is there way to store the query result directly when assigning the variable?
You can use sp_executesql with an output parameter to retrieve the scalar result.
DECLARE #query as nvarchar(200), #count int;
SET #query = N'SELECT #count = COUNT(*) FROM table';
EXEC sp_executesql #query,
N'#count int OUTPUT',
#count = #count OUTPUT
SELECT #count AS [#count]
You can do it like this:
exec (#query)
or, preferably, like this:
execute sp_executesql #query
For more info, check this MSDN article.
Try this :
declare #query as varchar(200)
select #query = COUNT(*) from table
I have a TSQL sproc that builds a query as and executes it as follows:
EXEC (#sqlTop + #sqlBody + #sqlBottom)
#sqlTop contains something like SELECT TOP(x) col1, col2, col3...
TOP(x) will limit the rows returned, so later I want to know what the actual number of rows in the table is that match the query.
I then replace #sqlTop with something like:
EXEC ('SELECT #ActualNumberOfResults = COUNT(*) ' + #sqlBody)
I can see why this is not working, and why a value not declared error occurs, but I think it adequately describes what I'm trying to accomplish.
Any ideas?
use sp_executesql and an output parameter
example
DECLARE #sqlBody VARCHAR(500),#TableCount INT, #SQL NVARCHAR(1000)
SELECT #sqlBody = 'from sysobjects'
SELECT #SQL = N'SELECT #TableCount = COUNT(*) ' + #sqlBody
EXEC sp_executesql #SQL, N'#TableCount INT OUTPUT', #TableCount OUTPUT
SELECT #TableCount
GO
You could instead have the dynamic query return the result as a row set, which you would then insert into a table variable (could be a temporary or ordinary table as well) using the INSERT ... EXEC syntax. Afterwards you can just read the saved value into a variable using SELECT #var = ...:
DECLARE #rowcount TABLE (Value int);
INSERT INTO #rowcount
EXEC('SELECT COUNT(*) ' + #sqlBody);
SELECT #ActualNumberOfResults = Value FROM #rowcount;
Late in the day, but I found this method much simpler:
-- test setup
DECLARE #sqlBody nvarchar(max) = N'SELECT MyField FROM dbo.MyTable WHERE MyOtherField = ''x''';
DECLARE #ActualNumberOfResults int;
-- the goods
EXEC sp_executesql #sqlBody;
SET #ActualNumberOfResults = ##ROWCOUNT;
SELECT #ActualNumberOfResults;
After executing your actual query store the result of ##ROWCOUNT in any variable which you can use later.
EXEC sp_executesql 'SELECT TOP 10 FROM ABX'
SET #TotRecord = ##ROWCOUNT into your variable for later use.
Keep in mind that dynamic SQL has its own scope. Any variable declared/modified there will go out of scope after your EXEC or your sp_executesql.
Suggest writing to a temp table, which will be in scope to your dynamic SQL statement, and outside.
Perhaps put it in your sqlBottom:
CREATE TABLE ##tempCounter(MyNum int);
EXEC('SELECT #ActualNumberOfResults = COUNT(*) ' + #sqlBody +
'; INSERT INTO ##tempCounter(MyNum) VALUES(#ActualNumberOfResults);');
SELECT MyNum FROM ##tempCounter;
You can use output variable in SP_EXECUTESQL
DECLARE #SQL NVARCHAR(MAX);
DECLARE #ParamDefinition NVARCHAR(100) = '#ROW_SQL INT OUTPUT'
DECLARE #AFFECTED_ROWS INT;
SELECT
#SQL = N'SELECT 1 UNION ALL SELECT 2'
SELECT #SQL += 'SELECT #ROW_SQL = ##ROWCOUNT;';
EXEC SP_EXECUTESQL #SQL, #ParamDefinition, #ROW_SQL=#AFFECTED_ROWS OUTPUT;
PRINT 'Number of affected rows: ' + CAST(#AFFECTED_ROWS AS VARCHAR(20));
Ouput:
SQL2.sql: Number of affected rows: 2
Thanks Jesus Fernandez!
The only problem with the answers that create temporary tables (either using "DECLARE #rowcount TABLE" or "CREATE TABLE ##tempCounter(MyNum int)") is that you're having to read all the affected records off disk into memory. If you're expecting a large number of records this may take some time.
So if the answer is likely to be large the "use sp_executesql and an output parameter" solution is a more efficient answer. And it does appear to work.
I have a number of stored procedures structured similarly to this:
DECLARE #sql NVARCHAR(MAX)
DECLARE #mdx NVARCHAR(MAX)
CREATE table #result
(
[col1] NVARCHAR(50),
[col2] INT,
[col3] INT
)
SET #mdx = '{some dynamic MDX}'
SET #sql = 'SELECT a.* FROM OpenQuery(LinkedAnalysisServer, ''' + #mdx + ''') AS a'
INSERT INTO #result
EXEC sp_executesql #sql
SELECT * FROM #result
This works quite well when results exist in the cube. However, when the OpenQuery results are empty, the INSERT fails with this error:
Column name or number of supplied
values does not match table
definition.
My question is, what is the best way to handle this scenario? I'm using the results in a static report file (.rdlc), so the explicit typing of the temp table is (I'm pretty sure) required.
Use TRY/CATCH in your stored procedure, you'll notice there is a specific error number for your problem, so check the error number and if it is that, return an empty result set. As you already have the table defined that'll be easier.
PseudoCode looks something like this:
SET #mdx = '{some dynamic MDX}'
SET #sql = 'SELECT a.* FROM OpenQuery(LinkedAnalysisServer, ''' + #mdx + ''') AS a'
BEGIN TRY
INSERT INTO #result
EXEC sp_executesql #sql
END TRY
BEGIN CATCH
IF ERROR_NUMBER <> 'The error number you are seeing'
BEGIN
RAISERROR('Something happened that was not an empty result set')
END
END CATCH
SELECT * FROM #result
You'll want to check for that particular error, so that you don't just return empty result sets if your SSAS server crashes for example.
There is another solution to this issue, similar to the accepted answer, which involves using an IF statement instead of TRY...CATCH.
http://www.triballabs.net/2011/11/overcoming-openquery-mdx-challenges/
IF (SELECT COUNT(*)
FROM OPENQUERY("SSAS1",
'SELECT [Measures].[Target Places] ON COLUMNS
FROM [ebs4BI_FactEnrolment]
WHERE [DimFundingYear].[Funding Year].&[17]')) > 0
EXEC sp_executesql N'SELECT CONVERT(varchar(20),
"[DimPAPSCourse].[Prog Area].[Prog Area].[MEMBER_CAPTION]")
as ProgArea,
convert(float, "[Measures].[Target Places]") as Target
FROM OPENQUERY("SSAS1",
''SELECT [Measures].[Target Places] ON COLUMNS,
[DimPAPSCourse].[Prog Area].[Prog Area] ON ROWS
FROM [ebs4BI_FactEnrolment]
WHERE [DimFundingYear].[Funding Year].&[17]'')'
ELSE
SELECT '' as ProgArea, 0 as Target
WHERE 1=0