Executing SQL statement stored as a field value - sql-server

Is it possible to execute a SQL statement that has been stored within a table as text.
I am trying to create a configuration table to drive a large number of SSRS subscriptions and don’t want to code any values directly into the report I want them all driven from a table for maintance.
E.G.
If part of one reports file name will always be the year of the previous month (2013 for example) but this needs to be generated at run time.
Can I stored this as a text field
CAST(YEAR(DATEADD(month, -1, GETDATE())) AS VARCHAR(4))
Then execute it and resolve the result into a SQL query?

If I understand your question correctly, then yes by using dynamic SQL. For example:
DECLARE #SQL NVARCHAR(4000)
DECLARE #YEAR VARCHAR(4)
SET #SQL = 'SELECT #yr = CAST(YEAR(DATEADD(month, -1, GETDATE())) AS VARCHAR(4))'
EXECUTE sp_executesql #SQL, N'#yr VARCHAR(4) OUTPUT', #yr=#YEAR OUTPUT
SELECT #YEAR
...returns 2013 into variable #YEAR.
Here I've hardcoded the query but it is a simple case to build the value of #SQL from a table's column value instead. You can then use the result from this query to build another dynamic query and so on.
Below is a subset of the above showing the SQL being taken from a table instead:
CREATE TABLE Dynamic (id INTEGER, text VARCHAR(4000) )
INSERT Dynamic values (1, 'CAST(YEAR(DATEADD(month, -1, GETDATE())) AS VARCHAR(4))')
SET #SQL = 'SELECT #yr = ' + (SELECT text FROM Dynamic WHERE id = 1)

why couldn't you?
Is it only one line of values per report?
I see 2 choices with SSRS.
1) everything in sql, you do dynamic sql.
declare #sql nvarchar(4000)
select #sql = 'select * from mytable where year = ' mavar'
from tablevalue where uniqueid = blablabla
exec sp_executesql #sql
second possibilty :
You make a first dataset in SSRS getting this value and then you evaluate the value of your condition and send it to a third dataset.
If you have multiple values, you can still imagine to get the value from a first dataset, evaluate them and send this to a subreport.
I don't know your application enought to determine the performance of this.
Until you are in SSRS, i recommand to try to find a solution in SSRS instead of Sql (but it's not a gold rule at all!!!)

Related

Create a view with changing table names

We have a set of tables that have a day of week suffix (Table_Mon, Table_Tue, etc.). I am trying to come up with a design where an application can pull a limited set of data out of these columns for whatever day it is currently. I was looking at using dynamic sql in a view but that is not an option. What is the correct solution so that an application can query the tables without needing to provide the day of week?
It is a poorly designed database schema. Ideally, there should be only one table with a column Week_Day and you should be able to query that table by just adding the appropriate WHERE clause.
Anyway, you will need to use dynamic sql, but instead of a view you should use a Stored Procedure. Something like...
CREATE PROCEDURE dbo.Get_Data
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Sql NVARCHAR(MAX)
,#TableName SYSNAME;
SET #TableName = N'TABLE_' + LEFT(DATENAME(WEEKDAY, GETDATE()) , 3);
SET #Sql = N' SELECT * FROM ' + QUOTENAME(#TableName)
Exec sp_executesql #Sql
END

How to use parameters for part of table name in stored procedure in SQL Server 2012

I am creating a procedure in SQL Server 2012 where table name that is created eventually has month and year as part of the table name, for example BA_Monthly_Report_Dec_2017.
This procedure will be run every month and only the last part of the table name will change.
I tried using parameters here but it's not working. Please help.
In SQL Server table names should be defined as static, if the query is static. If you want table name to be dynamic in that case you need to write dynamic query.
You can execute your dynamic query using sp_executesql
In your case you can write your query in SP as following.
DECLARE #Month VARCHAR(10) ='Dec'
DECLARE #Year INT = 2017
DECLARE #Query VARCHAR(MAX)
SET #Query = 'SELECT * FROM BA_Monthly_Report_' + #Month
+ '_' + CAST(#Year AS VARCHAR(4))
EXEC sp_executesql #Query

T-Sql - Convert datetime column name parameter from VARCHAR to time

I have a datetime column name [dbo].[Bus Station] that I want to pass it in T-SQL script as a parameter #StationName
DECLARE #CurrentTime TIME(0) = '20:53:00',
#StationName TIME(0), -- Datetime Column Name
#BusTime TIME(0);
SET #StationName = '[dbo].[Bus Station]'
SET #BusTime = (SELECT TOP 1 #StationName
FROM dbo.R1_pvt
WHERE #StationName >= CONVERT (time(0), #CurrentTime))
SELECT DateDiff(mi, #CurrentTime, #BusTime) % 60 As Minutes
How can I do it? :(
It appears that what you want to do is execute a dynamic SQL statement. This can be done, but you must be careful because depending on where the input comes from that's used to build the query, you could be susceptible to a SQL injection attack. On Microsoft's information page on this method, it says:
IMPORTANT: Before you call EXECUTE with a character string, validate
the character string. Never execute a command constructed from user
input that has not been validated.
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/execute-transact-sql
To execute a dynamic SQL statement, build your query in a string (varchar, typically) variable, and then execute it. That's done by either using the EXECUTE() command or by calling the sp_executesql system stored procedure.
-- variable to store the query
DECLARE #query varchar(500)
-- build the query
SET #query = 'SELECT TOP 1 ' + #StationName + ' FROM dbo.R1_pvt WHERE ' + #StationName + ' >= CONVERT(time(0), ''' + CAST(#CurrentTime as varchar) + ''' )'
-- execute the query
EXECUTE(#query);
In your case, you also want to return a value. This can be done and has been covered well elsewhere on this site. I suggest you take a look at this question on Stack Overflow:
Getting result of dynamic SQL into a variable for sql-server

Compare the results of a bunch of SQL statements and review results

I have a SQL Server table with 2 columns. Column 1 is Query_Name and column 2 is Query_Text. This query_text column contains a semi-simple SQL Select statement. I have 34 rows like this. These Select statements are not necessarily operating on the same SQL server. I want a way where I can run these 34 queries, compare their result, and notify the user via email if certain conditions apply. The email part, I got that. It is a SQL server agent task. But I am lost as to how to run these 34 queries and compare them.
This has to be dynamic. For instance, a stored procedure with 34 variables won't work. This 34 might be 40 tomorrow. I want to run the queries contained in the query_text column every night and compare them and email the user.
Any ideas?
EDIT 1:
The comparison part: It cannot be significantly different. What is significantly different is determined by my boss. For the sake of this question, let us just assume it cannot vary by more than 100. The output of these 34 queries are numbers (Their data type might be nvarchar, but the output is definitely numbers).
EDIT 2:
RUN 1 query that in turn runs all the queries in a given column.
DECLARE #QUERYCOLUMN nvarchar(50)
SET #QUERYCOLUMN = (SELECT QUERY_TEXT FROM TABLE_NAME)
EXEC(#QUERYCOLUMN)
Something in that fashion.
This dumps your queries into a table variable and loops through them executing the text then deleting it from the table variable. You should definately be aware of the dangers of executing dynamic SQL before adopting this or any other approach though.
DECLARE #Name VARCHAR(50), #Query VARCHAR(MAX)
DECLARE #Queries TABLE (Query_Name VARCHAR(50), Query_Text VARCHAR(MAX))
INSERT INTO #Queries(Query_Name, Query_Text)
SELECT Query_Name, Query_Text FROM MY_SOURCE_TABLE
WHILE EXISTS (SELECT 1 FROM #Queries)
BEGIN
SELECT TOP 1 #Name = Query_Name, #Query = Query_Text FROM #Queries
EXEC(#Query)
DELETE FROM #Queries WHERE Query_Name = #Name
END
This method assumes Query_Name is unique in your source data or else the results could be skewed.
This will allow you to iterate through the table and execute the statements contained in each entry.
You will need to alter the statement contained in #sSQL if you wish to output this into a table, but this will work for testing in SSMS for you.
I would suggest you use a simple incrementing ID of sorts (Identity is the easiest) to allow you determine when all entries have been accounted for.
DECLARE #QID INT, #sSQL NVARCHAR(MAX) = ''
SELECT #QID = MIN(QID) FROM [dbo].[QueryComparison]
WHILE #QID IS NOT NULL
BEGIN
SELECT #sSQL = Query_Text FROM [dbo].[QueryComparison] WHERE QID = #QID
EXEC sp_executesql #sSQL
SELECT #QID = MIN(QID) FROM [dbo].[QueryComparison] WHERE QID > #QID
END

Stored Procedure in sql for selecting columns based on input values

I am trying to code a stored procedure in SQL that does the following
Takes 2 inputs (BatchType and "Column Name").
Searches database and gives the batchdate and the data in the column = "Column name"
Code is as give below
ALTER PROCEDURE [dbo].[chartmilldata]
-- Add the parameters for the stored procedure here
(#BatchType nvarchar (50),
#Data nvarchar(50))
AS
BEGIN
-- Insert statements for procedure here
SELECT BatchDate,#Data FROM --Database-- WHERE BatchType = #BatchType
END
I am trying to select column from the database based on operator input. But I am not getting the output. It would be great if someone can give me a direction.
You may want to build out your SELECT statement as a string then execute it using sp_executesql.
See this page for more info:
https://msdn.microsoft.com/en-us/library/ms188001.aspx
This will allow you to set your query to substitute in your column name via your variable and then execute the statement. Be sure to sanitize your inputs though!
You'd need to use dynamic SQL, HOWEVER I would not recommend this solution, I don't think there is anything I can add as to why I wouldn't recommend it that isn't explained better in Erland Sommarskog in The Curse and Blessings of Dynamic SQL.
Nonetheless, if you had to do it in a stored procedure you could use something like:
ALTER PROCEDURE [dbo].[chartmilldata]
-- Add the parameters for the stored procedure here
(#BatchType nvarchar (50),
#Data nvarchar(50))
AS
BEGIN
-- DECLARE AND SET SQL TO EXECUTE
DECLARE #SQL NVARCHAR(MAX) = N'SELECT BatchDate = NULL, ' +
QUOTENAME(#Data) + N' = NULL;';
-- CHECK COLUMN IS VALID IN THE TABLE
IF EXISTS
( SELECT 1
FROM sys.columns
WHERE name = #Data
AND object_id = OBJECT_ID('dbo.YourTable', 'U')
)
BEGIN
SET #SQL = 'SELECT BatchDate, ' + QUOTENAME(#Data) +
' FROM dbo.YourTable WHERE BatchType = #BatchType;';
END
EXECUTE sp_executesql #SQL, N'#BatchType NVARCHAR(50)', #BatchType;
END
It would probably be advisable to change your input parameter #Data to be NVARCHAR(128) (or the alias SYSNAME) though, since this is the maximum for column names.

Resources