Use SQL Statement With String - sql

I have a products table and i need to concat my string and my sql statements. Is there any way?
My purpose is that i want to define column names just one time in a string variable and i will use it alot of times. Otherwise my sql statements has alot of column name and it complex my code.
For example, i use this
DECLARE #MyStr NVARCHAR(MAX) = 'ProdId,ProdName'
SELECT TOP 10 #MyStr FROM Products
Result is here
But i need the result as this.

You'll need to use dynamic SQL here. I also suggest you fix your design and don't store delimited data, and ideally use a table type parameter. This would look like the following:
DECLARE #Columns table (ColumnName sysname);
INSERT INTO #Columns (ColumnName)
VALUES(N'Column1'),(N'Column2');
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SELECT #SQL = N'SELECT ' + STRING_AGG(QUOTENAME(ColumnName),N',') + #CRLF +
N'FROM dbo.Products;'
FROM #Columns;
PRINT #SQL; --Your best friend
EXEC sys.sp_executesql #SQL;
If you don't want to use a table type, you can use STRING_SPLIT:
SELECT #SQL = N'SELECT ' + STRING_AGG(QUOTENAME([Value]),N',') + #CRLF +
N'FROM dbo.Products;'
FROM STRING_SPLIT(#Columns,',');

Related

Dynamic SQL stored procedure and datetime

I have a simple query that I want to convert to dynamic SQL. I have 2 input parameters: a table and a datetime. And the output is the rowcount for the table and this specific datetime.
CREATE PROCEDURE [etl].[ROWCOUNT_TST2]
(#P_LOAD_TARGET nvarchar(250),
#P_LOAD_DATE DATETIME)
AS
BEGIN
DECLARE #SQL nvarchar(1000)
SET #SQL = 'SELECT COUNT(*) as Inserted FROM'+#P_LOAD_TARGET +' WHERE VALID_FROM ='''+ #P_LOAD_DATE+''' AND VALID_TO IS NULL'
EXEC (#SQL)
END;
GO
I tried different solutions. I tried the query with execute sp_executesql, I tied to add the the ''' before and after the #P_LOAD_DATE. I am probably missing something here.
When I execute the stored procedure with a table name and datetime like 2021-05-06 06:41:52.557, I get the following error:
Conversion failed when converting date and/or time from character string.
But why?
I even tried to add a conversion to datetime like this, but I still get the same error.
SET #SQL = 'SELECT COUNT(*) as Inserted FROM'+#P_LOAD_TARGET +' WHERE VALID_FROM = convert(datetime,'''+ #P_LOAD_DATE+''') AND VALID_TO IS NULL'
But when I execute SELECT convert(datetime, '2021-05-06 06:41:52.557') it works out fine. I am just confused right now and can't find the root of the problem.
Edit: valid_from is a datetime in the target table. So that is also not the reason for the problem
You need to properly and safely inject your dynamic object name and parametrise your parameter:
CREATE PROCEDURE [etl].[ROWCOUNT_TST2](#P_LOAD_SCHEMA sysname = N'dbo', --Always define your schema
#P_LOAD_TARGET sysname, --sysname is the data type for objects, a synonym of nvarchar(128) NOT NULL
#P_LOAD_DATE datetime) AS
BEGIN
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SET #SQL = N'SELECT COUNT(*) AS Inserted' + #CRLF +
N'FROM ' + QUOTENAME(#P_LOAD_SCHEMA) + N'.' + QUOTENAME(#P_LOAD_TARGET) + #CRLF +
N'WHERE VALID_FROM = #P_LOAD_DATE' + #CRLF +
N' AND VALID_TO IS NULL;';
--PRINT #SQL; --Your best friend.
EXEC sys.sp_executesql #SQL, N'#P_LOAD_DATE datetime', #P_LOAD_DATE;
END;

Creating a SQL statement based on existing table fields

Having a table populated with databases and table names, is it possible to create some dynamic query based on those fields? Something like:
DECLARE #mysearch NVARCHAR(MAX)= 'SELECT db_name, tbl_name FROM UserConfig where ID = 1';
SELECT * FROM [db_name]..[tbl_name]
Being db_name and tbl_name the result values of #mysearch query.
For clarification, database and table names from where I need to select data are in a table, not hardcoded.
Example:
SELECT * FROM MYDB..MyTable
But "MYDB" and "MyTable" are values stored somewhere else.
Thanks.
I am reading a lot through the lines here, but are you actually after this?
DECLARE #SQL nvarchar(MAX);
DECLARE #CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SELECT #SQL = N'SELECT *' + #CRLF +
N'FROM ' + QUOTENAME(db_name) + N'.dbo.' + QUOTENAME(tbl_name) + N';'
FROM UserConfig
WHERE ID = 1;
EXEC sp_executesql #SQL;
This assumes a single row would be returned for a single value of ID in the table UserConfig.

Select the store procedure parameter as aliases in select statement

I want to select the store procedure parameter as aliases in select statement in sql
example i have two parameter in store procedure
#programcode int,
#class int
Query where I want use those parameters as alias.
select programcode as #programcode from tbl_name
Why would you want a column alias to be a number?
In any case, you can write this as:
DECLARE #sql nvarchar(MAX);
SET #sql = N'
SELECT programcode AS [' + CAST(#programcode AS VARCHAR(MAX)) + ']
FROM tbl_name
';
EXEC sp_executesql #sql;
Numbers are not really recommended for column aliases, so they need to use escapes.
Try this query.
DECLARE #SqlText nvarchar(MAX);
SET #sqlText = N'SELECT programcode AS ' + CAST(#programcode AS VARCHAR(MAX)) + ' FROM tbl_name'
Exec (#sqlText)

SELECT INTO dynamic temp table using procedure with dynamic parameter

I can't find a full solution to my problem. I have an existing stored procedure that takes dynamic input as a parameter value. I need to execute this procedure (with a dynamic variable) and would like to somehow SELECT * INTO #mytable without having to declare the schema of the temp table.
I've tried using OPENROWSET but it doesn't allow me to specify the variable (only hard-code it):
select * into #table from openrowset('SQLNCLI', 'Server=localhost;Trusted_Connection=yes;', 'exec SERVER..MYSTOREDPROCEDURE #parameter = 123')
The only other way I'm aware of is wrapping it in a string and using EXEC(#sql), but I can't figure out how to "SELECT * INTO #table" from that.
What are my options? Can I create a UDF table function that can return a dynamic table? Doubtful...
I'm guessing here, but you'll need to do the whole thing in dynamic SQL. So, instead, something like:
DECLARE #SQL nvarchar(MAX);
DECLARE #param nvarchar(10) = 123;
SET #SQL = N'SELECT *' + NCHAR(10) +
N'INTO #table' + NCHAR(10) +
N'FROM OPENROWSET(''SQLNCLI'', ''Server=localhost;Trusted_Connection=yes;'', ''exec SERVER..MYSTOREDPROCEDURE #parameter = ' + QUOTENAME(#param,N'''') +N''');' + NCHAR(10) +
N'SELECT *' + NCHAR(10) + --Of course, I assume you're doing something more complex that a SELECT *.
N'FROM #table;';
PRINT #SQL;
EXEC sp_executesql #SQL;
I think I figured it out. I really only had to modify the temp variable names to put the temp table into the global scope. This works for me with my actual tables (I renamed them for the purposes of this post).
IF OBJECT_ID ('tempdb..##mytemptable') is not null drop table ##mytemptable
declare #id int = 112
declare #sql nvarchar(max) ='SELECT * INTO ##mytemptable FROM OPENROWSET(''SQLNCLI'', ''Server=localhost;Trusted_Connection=yes;'', ''exec SERVER..MyStoredProcedure #ID =' + convert(varchar(10), id) + ''')'
-- invokes and inserts into ##mytemptable
exec sp_executesql #sql
-- now I can query from the global scope
select * from ##mytemptable

Changing my statement to work in a SQL function

I wanted to create a view using my SQL statement but found out you can't use declare in a view. So I was trying to create a function so my view could just call it
This is the SQL statement
--Declare necessary variables
DECLARE #SQLQuery AS NVARCHAR(255)
DECLARE #Pivot AS NVARCHAR(255)
--Get unique values of pivot column
SELECT #Pivot = COALESCE(#Pivot + ',','') + QUOTENAME(Stage)
FROM
(SELECT DISTINCT Stage
FROM [dbo].[F_Work_Order_Summary]) AS Pivot
--Create the dynamic query with all the values for
--pivot column at runtime
SET #SQLQuery = N'SELECT *
FROM [dbo].[F_Work_Order_Summary]
PIVOT(SUM(Time_In_Stage)
FOR Stage IN (' + #Pivot + ')) AS P'
--Execute dynamic query
EXEC sp_executesql #SQLQuery
Was wonder if anyone could help or knows a better way to use this statement with a view.
Thanks