Dynamically insert data into a temp table with like as variable - sql-server

I am trying to dynamically insert data into a temp table passing like data as a variable:
DECLARE #data NVARCHAR(MAX)
SET #data = 'INSERT INTO #coco ' + '([' + #val + '])' + ' SELECT [USER_ID] FROM [dbo].[Sheet1$] WHERE [Standard_Name] LIKE ' + #val
EXEC sp_executesql #data
#val is a column name selected from table Sheet1$ and few column name has space between them. While executing, I am getting error, like for column name "Acrobat Reader":
Incorrect syntax near 'Acrobat'.
Also if I am adding data using hardcoded one by one in a column its adding data to one column while other column its adding NULL.
Any suggestion how I can overcome this?

Parametrise your SQL, and this problem "goes away":
DECLARE #data;
SET #data = N'INSERT INTO #Coco (' QUOTENAME(#val) + N')' + NCHAR(10) +
N'SELECT [USER_ID]' + NCHAR(10) +
N'FROM dbo.[Sheet1$]' + NCHAR(10) +
N'WHERE [Standard_Name] = #val;'; --As this doesn't contain a %, there's no need for LIKE
EXEC sp_executesql #data,
N'#val = sysname', --guessed datatype
#val = #val;
Note the comments I made in the SQL though.
Afraid, I've no idea what your second statement means. You'll need to explain further.

Related

How do i insert or update a record based on data whicha has a apostohphe in a dynamic sql?

Here the #Data has a value with apostophe(')s . how do i update or insert a data based on the data value which is having apostophe in a dynamic sql
suppose #data has one value abc and another value abc's it throwing error for the second one
SET #SQL = ' Update '+ #ProcessCode + '_abc SET IS_IGNORING = 1 where Column_Name = '''+ #Column_Name +''' and [DATA] = ''' + #Data + ''' and Table_name = '''+ #Table_Name + ''''
Generally what i found is a manual process of adding one more apostophe but i am not really sure how to use that in a dynamic sql where not all data in the table is same, few of the data records has got this type of apostophe(')
Parameterized your query using sp_executesql
Example:
SET #SQL = 'Update ' + #ProcessCode + '_abc '
+ 'SET IS_IGNORING = 1 '
+ 'where Column_Name = #Column_Name '
+ 'and [DATA] = #Data '
+ 'and Table_name = #Table_Name '
EXEC sp_executesql #SQL,
N'#Column_Name varchar(100), #Data varchar(100), #Table_Name varchar(100)',
#Column_Name, #Data, #Table_Name
Do read up more on dynamic query and SQL Injection
You might find convenient to use parameterized queries, so you can replace static values with placeholders and then bind values to those placeholders before executing the query. It has certain advantages like better performance and helps to avoid SQL-injection attacks.
More info here: https://techcommunity.microsoft.com/t5/sql-server-blog/how-and-why-to-use-parameterized-queries/ba-p/383483

SQL Server Concatenate JSON For Dynamic Queries

I have a dynamic (I am passing parameters in a stored procedure) query in a stored procedure which results in a JSON string. Similar to this:
#PropertyPK uniqueidentifier (Stored Procedure Parameter)
#search_term Varchar(50)
#limit int
#offset int
Declare #test Varchar(1000)
SELECT #test = '
SELECT Cast((
SELECT *
FROM Contacts
Where Address like ''%' + #search_term + '%''' + ' Order By '
+ #sort_by + ' ' + #sort_order + ' OFFSET '
+ Cast(#offset as varchar) +
' ROWS
FETCH NEXT '
+ Cast(#limit as varchar) +
' ROWS ONLY
For JSON Path, INCLUDE_NULL_VALUES )
as varchar(max))'
EXEC(#test)
I have been asked to return results from 2 queries in a JSON format but in one string. Basically run one query into a variable and the second into another and concatenate them together and then deliver the results.. Can someone help me putting the result JSON from the above query into a variable so I can do the same with my second query and concatenate them? Can I do anything after the Exec(#test) to get the result into a variable?
Thank you..
The latest query you've posted isn't dynamic either, so I'm unsure why you're using EXEC. As i mentioned in the comments, therefore, this is as simple as using SET:
DECLARE #PropertyPK uniqueidentifier; --SP parameter
DECLARE #JSON nvarchar(MAX);
SET #JSON = (SELECT *
FROM Contacts
WHERE PropertyPK = #PropertyPK
FOR JSON PATH, INCLUDE_NULL_VALUES);
There's no need for #PropertyPK to be cast as a varchar to a dynamic SQL statement; just use proper parametrised SQL.
This is based on guesswork and the OP's latest (but clearly incomplete) question. If this isn't correct, this should get you on the right path, however, having information drip fed makes the question difficult to answer properly.
DECLARE #PropertyPK uniqueidentifier,
#SearchTerm varchar(50),
#Limit int,
#Offset int,
#SortBy sysname, --objects have the data type sysname, aka nvarchar(128)
#SortOrder nvarchar(4); --Guess datatype as it was missing in your sample
DECLARE #JSON nvarchar(MAX);
DECLARE #SQL nvarchar(MAX);
SET #SQL = N'SET #JSON = (SELECT {Columns}' + NCHAR(10) + --Replace {Columns} with an actual list of the required columns (NOT *)
N' FROM dbo.Contacts' + NCHAR(10) +
N' WHERE Address LIKE #Search' + NCHAR(10) +
N' AND PropertyPK = #PropertyPK' + NCHAR(10) + --I ASSUME that WHERE is still needed
N' ORDER BY ' + QUOTENAME(#SortBy) + N' ' + CASE #SortOrder WHEN N'ASC' THEN N'ASC' WHEN N'DESC' THEN 'DESC' END + NCHAR(10) + --The CASE stops invalid sort orders
N' OFFSET #Offset FEETCH NEXT #Limit ROWS ONLY' + NCHAR(10) +
N' FOR JSON PATH, INCLUDE_NULL_VALUES);';
PRINT #SQL; --Your best friend
EXEC sp_executesql #SQL,
N'#JSON nvarchar(MAX) OUTPUT, #Search varchar(50), #PropertyPK uniqueidentifier, #Offset int, #Limit int',
#JSON = #JSON OUTPUT,
#Search = #SearchTerm,
#PropertyPK = #PropertyPK,
#Offset = #Offset,
#Limit = #Limit;
One of the biggest things you need to note here is I have made the SQL SAFE. Your SQL was wide open to SQL injection, which is a huge security flaw. If you don't know/understand SQL injection, I suggest reading about it now. SQL like you have above is a huge problem, and raw string concatenation is an awful idea waiting to be exploited.

Querying a column that contains comma separated values

I'm trying to figure out why my where clause is returning all rows.
I'm querying a column that contains csv's using a variable that also contains csv's. I've built a stored function to split the variable on csv and return a table with one row that contains what I'd like to have on the right side of the LIKE operator.
Example:
The stored function:
ALTER Function [dbo].[storedFunction]
(#Fields VARCHAR(MAX),
#Field_Name VARCHAR(MAX) = '')
RETURN #Tbl_Fields Table (FIELD Varchar(max))
AS
BEGIN
DECLARE #FIELD varchar(max) = REPLACE(#Fields, ',', '%''' + ' AND ' +
#Field_Name + ' Like ' + '''%');
INSERT INTO #Tbl_Fields
SELECT '''%' + #FIELD + '%'''
RETURN
END
Using the stored function:
BEGIN
DECLARE #variable varchar(max) = 'variable1, variable3';
END
SELECT field
FROM storedFunction(#variable, 'main_csv_field');
returns '%variable1%' AND main_csv_field Like '%variable3%'
My simplified query:
BEGIN
DECLARE #variable varchar(max) = 'variable1, variable3';
END
SELECT main_csv_field
FROM table
WHERE (main_csv_field LIKE (SELECT field
FROM storedFunction(#variable, 'main_csv_field');
returns
variable1,variable2,variable3,variable4,...
variable2,variable4,...
variable1,variable3,...
My problem is this last query returns all of the rows in the table regardless of value matching. Were I to copy and paste the value returned from the stored function I would get the data that I need.
How/what is the difference here?
Thanks to #Obie and #AllanS.Hansen I knew where to start looking to fix this. Its pretty rough, but I wanted to post a solution before I got too far down the rabbit hole:
DECLARE variable1 varchar(max) = '' --around 9 passed from code
DECLARE #query nvarchar(max);
DECLARE #column_list varchar(max) = 'column1, column2, etc'
--one of each of the tests per variable passed from code
DECLARE #variable1_test nvarchar(max) = (SELECT CASE WHEN #variable = '' THEN '%' ELSE (SELECT * from dbo.stored_function(#variable, 'column_name')) END);
END;
SET #query = ' SELECT ' + #column_list + '
FROM table_name
WHERE variable LIKE ''' + #variable_test + ''' '
EXECUTE sp_executesql #query;
print(#query); --This is just to see the resulting query, which helped me a ton
Exciting! Now I have to test it.

I want to write one common stored procedure to insert data in any table of my database

I have 6 table with different fields. I want to access table name dynamically. is there any idea to do it?
My code is below this is simple procedure which I want to make dynamic to use in c#. how to do it?
Create procedure [dbo].[Insert_Data] (#Id int,#FeesHead nchar(20),#Fees int,#Remarks nchar(20))
as
begin
Insert into FeesHead(ID,FeesHead,Fees,Remarks)values(#Id,#FeesHead,#Fees,#Remarks)
End
Don't go there.
It's a bad idea since you will end up with a long, inefficient stored procedure that will be vulnerable to SQL injection attacks and have performance issues.
Writing an insert stored procedure for each table is the way to go.
You wrote you have six different tables with different columns, so writing a stored procedure to handle inserts for all of them will require you to send all the parameters for all columns as well as a parameter for the table name, and a nested if...else with 6 possible paths, one for each table.
This will end up as a long, messy, poorly written code at best, bad in each parameter: security, performance, code readability and maintainability.
The only way that makes some sense to achieve such a goal is to write individual insert stored procedures for each table, and then write a stored procedure that will take all of the possible parameters and the table name and inside of it decide what insert stored procedure to execute based on the value of the table name parameter. However, you will be better off leaving conditions like these to the SQL client (your c# code in this case) then to SQL Server.
Its very easy to do.........
Just call the sql query using Data Adapter.
select TABLE_NAME from INFORMATION_SCHEMA.TABLES
As you said you need dynamic SQL like this:
Create procedure [dbo].[Insert_Data]
(
#TableName nvarchar(512),
#Values nvarchar(max)
)
BEGIN
DECLARE #SQL nvarchar(max)
SELECT #SQL = 'INSERT INTO ' + #TableName + ' VALUES (' + #Values + ')'
EXEC(#SQL)
END
Note that #Values will be like this '1, ''name'', 10.2' and with the same order of columns.
or
Create procedure [dbo].[Insert_Data]
(
#TableName nvarchar(512),
#Fields nvarchar(max),
#Values nvarchar(max)
)
BEGIN
DECLARE #SQL nvarchar(max)
SELECT #SQL = 'INSERT INTO ' + #TableName + ' (' + #Fields + ') VALUES (' + #Values + ')'
EXEC(#SQL)
END
To more ability to handle column order and remove identity columns.
As Robert Harvey mentioned it is a bad idea, anyway if you want to you can do something like....
CREATE PROCEDURE Insert_Data
#TableName SYSNAME
,#Column1 SYSNAME = NULL
,#Column2 SYSNAME = NULL
,#Column3 SYSNAME = NULL
,#Value1 NVARCHAR(100) = NULL
,#Value2 NVARCHAR(100) = NULL
,#Value3 NVARCHAR(100) = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Sql NVARCHAR(MAX);
SET #Sql = N' INSERT INTO ' + QUOTENAME(#TableName)
+ N' ( '
+ STUFF(
CASE WHEN #Column1 IS NOT NULL
THEN N',' + QUOTENAME(#Column1) ELSE N'' END
+ CASE WHEN #Column2 IS NOT NULL
THEN N',' + QUOTENAME(#Column2) ELSE N'' END
+ CASE WHEN #Column3 IS NOT NULL
THEN N',' + QUOTENAME(#Column3) ELSE N'' END
,1,1,'')
+ N' ) '
+ N' VALUES ( '
+ STUFF(
CASE WHEN #Value1 IS NOT NULL
THEN N', #Value1' ELSE N'' END
+ CASE WHEN #Value2 IS NOT NULL
THEN N', #Value2' ELSE N'' END
+ CASE WHEN #Value3 IS NOT NULL
THEN N', #Value3' ELSE N'' END
,1,1,'')
+ N' ) '
Exec sp_executesql #Sql
,N'#Value1 NVARCHAR(100),#Value2 NVARCHAR(100),#Value3 NVARCHAR(100)'
,#Value1
,#Value2
,#Value3
END

Change columnname with variable in WHILE loop SQL

Say i have columns PlanSalesMt1, PlanSalesMt2 and so on for the whole year until Mt12 in a table.
Before i created a view where i unioned all the months togheter but that query is pretty slow. Now i want to try the query with a Loop.
My Problem is i can't use the variable in my column names because they get invalid. Is that a way to solve this?
What i mean is i want to loop my question 12 times and change the name of the columns also after what month it is. But i cant make a #i variable and say select PlanSalesMt#1 or PlanSalesMt+#1 or PlanSalesMt+CAST(#1 as varchar) becuase it says invalid column Name.
Here is an example of dynamic SQL
DECLARE #ColumnName1 VarChar(20)
DECLARE #ColumnName2 VarChar(20)
DECLARE #sql Varchar(1000)
DECLARE #MyWhere VarChar(20)
SET #ColumnName1 = 'PlanSalesMt1'
SET #ColumnName2 = 'PlanSalesMt2'
SET #MyWhere = 'Books'
SET #sql = 'SELECT ' + #ColumnName1 + ', ' + #ColumnName2 + ' FROM TABLE WHERE ' + #ColumnName1 + ' = ''' + #MyWhere + ''''
EXEC(#sql)
If you change EXEC(#sql) to SELECT #sql copy into SSMS and run it you will see the query this produces.

Resources