December 30, 2017 at 6:57 am
hello i have this stored proc for dynamically insert update delete select and select with id
but hier have a 2 column name and 2 values for this crud operaion
may be more columns and more values for crud opertaion
can i use arraylist
for example i will add 20 column for inserting proc will give me 20 values will insert 20
all in dynamically
can that structure?
thanks for discussion
GO
ALTER Procedure [dbo].[crud_operation]
@TableName VarChar(100),
@id int=null,
@action int,@COL1 sysname=null,@COL2 sysname=null,@cval1 nvarchar(max)=null,@cval2 nvarchar(max)=null
AS
Declare @SQL VarChar(1000)
----simple select--
SELECT @SQL = case
when (@action = 0 and @id is null) then 'SELECT * FROM ' + @TableName
when (@action=0 and @id is not null) then 'SELECT * FROM ' + @TableName +' '+ N'where id=' + rtrim(cast (@id as int))
----insert----
when (@action=1 and @COL1 is not null and @COL2 is null) then 'insert into ' + @TableName + ' ' +'('+@COL1+')' + ' ' + 'select '+ ''''+@cval1+''''
when (@action=1 and @COL1 is not null and @COL2 is not null) then
'insert into ' + @TableName + '('+@COL1+','+@COL2 + ')' + ' ' + 'select '+ ''''+@cval1+'''' +','+''''+@cval2+''''
----delete----
when(@action=2 and @id is not null) then
'delete from ' + @TableName + ' ' + N'where id='+ rtrim(cast(@id as int))
----update ---
when (@action=3 and @id is not null and (@COL1 is not null and @COL2 is null))
then 'update ' + @TableName + ' set ' + @COL1 + '=' + @cval1 +' where id=' + rtrim(cast(@id as int))
else '' end
print @sql
Exec ( @SQL)
December 30, 2017 at 7:47 am
Personally, I see a lot more problems with this than simply the ability to pass an unlimited amount t if columns. SQL injection is a concern with this type of set up.
What is your reason for choosing to have a one size fits all SP? you would be much better splitting this out to start with.
Thom~
Excuse my typos and sometimes awful grammar. My fingers work faster than my brain does.
Larnu.uk
December 30, 2017 at 8:16 am
Thom A - Saturday, December 30, 2017 7:47 AMPersonally, I see a lot more problems with this than simply the ability to pass an unlimited amount t if columns. SQL injection is a concern with this type of set up.What is your reason for choosing to have a one size fits all SP? you would be much better splitting this out to start with.
yes this structure is not normally
i want to pass table name columnname dyanically for insert and update
December 30, 2017 at 8:23 am
Grrr... Firefox crashed. Let's start again.
Ok, so, firstly, Let's start simple. We'll use your Stored Procedure and pass the following values (note I have removed the EXEC(@SQL) from my version:
That results in the following Dynamic SQL being produced:SELECT * FROM Test; DROP TABLE [test];
Excellent, you have just selected all the values from your table, [Test] and then dropped it. That is hardly likely to be intended.
Let's, however, go a little further shall we? Now, I don't know the privileges of your account that is accessing that SP, but let's assume they're pretty high (note I've used a variable for readability, you could just as easily pass that string straight to the SP itself):
And the resulting dynamic SQL?insert into YourTable (YourColumn) select 'a';
CREATE DATABASE [Injection];
USE master;
CREATE LOGIN [Hackzor] WITH PASSWORD = 'Hackz', CHECK_EXPIRATION = OFF, CHECK_POLICY = OFF;
EXEC sp_addsrvrolemember 'Hackzor', 'sysadmin';--'
So, what does that do? Well, I just inserted a simple value into your Table. Then, I created a new database called [Injection]. After that I switched to the [master] database, created a Login called Hackzor with a very simple password and gave it sysadmin privileges!
Now, that might not all go through, if the login doesn't have sysadmin rights itself, but anyone with malicious intent will be happy to try a few combinations until that get the result that want.
Can we fix this? Yes, definitely, but before I, or anyone else starts posting how to, it would be good for you to acknowledge the problems, and say you're ready to fix them; there's quite a bit of work here; and I'd rather not it be a fruitless endeavour.
Thom~
Excuse my typos and sometimes awful grammar. My fingers work faster than my brain does.
Larnu.uk
December 30, 2017 at 8:28 am
natigsqlserver - Saturday, December 30, 2017 8:16 AMThom A - Saturday, December 30, 2017 7:47 AMPersonally, I see a lot more problems with this than simply the ability to pass an unlimited amount t if columns. SQL injection is a concern with this type of set up.What is your reason for choosing to have a one size fits all SP? you would be much better splitting this out to start with.
yes this structure is not normally
i want to pass table name columnname dyanically for insert and update
And, as I said in my original post, why a one size fits all? Apart from fixing the injection issues, I'd at least ensure that you have separate SP's to INSERT, UPDATE, SELECT, Etc... Yes, the table can be dynamic, but highly recommend against it being able to do anything.
Thom~
Excuse my typos and sometimes awful grammar. My fingers work faster than my brain does.
Larnu.uk
December 30, 2017 at 8:51 am
I'll start off with an introduction anyway. This version below will avoid injection. I've commented the lines, which should help you understand what it's doing. if however, you don't, please do ask. You'll note this only does a SELECT, nothing else. As I said above, I suggest splitting out the operations:
Thom~
Excuse my typos and sometimes awful grammar. My fingers work faster than my brain does.
Larnu.uk
December 30, 2017 at 8:57 am
Thom A - Saturday, December 30, 2017 8:51 AMI'll start off with an introduction anyway. This version below will avoid injection. I've commented the lines, which should help you understand what it's doing. if however, you don't, please do ask. You'll note this only does a SELECT, nothing else. As I said above, I suggest splitting out the operations:CREATE PROC dbo.crud_select_operation @TableName varchar(100), @id INT = NULLASDECLARE @SQL nvarchar(4000); --This will hold our Dynamic SQLDECLARE @parm nvarchar(100); --This hold the definition of our parameter for our D-SQL, if we need it.--Start off with the basic of the SELECT statementSELECT @SQL = N'SELECT *FROM ' + QUOTENAME([name]) --Quote the table name, incase it has special charactersFROM sys.tables --We use sys.tables, to ensure the table exists. If it doesn't exist, then NULL is returned (and no SQL is run)WHERE [name] = @TableName;--Let's do the part where there is an IDIF @ID IS NOT NULL BEGINSET @SQL = @SQL + N'WHERE id = @dID;'; --This adds a WHERE clauseSET @parm = N'@dID int'; --And that's the definition of our parameter in our Dynamic SQLPRINT @SQL;EXEC sp_executesql @SQL, @parm, @dID = @ID; --And the bit that runs it all. We're much safer using sp_executesqlEND ELSE BEGIN--This is is there is no IDSET @SQL = @SQL + N';'; --Future proofingPRINT @SQL;EXEC sp_executesql @SQL;ENDGO
thank you very much
but i need insert and update
operation
December 30, 2017 at 9:02 am
natigsqlserver - Saturday, December 30, 2017 8:57 AMThom A - Saturday, December 30, 2017 8:51 AMI'll start off with an introduction anyway. This version below will avoid injection. I've commented the lines, which should help you understand what it's doing. if however, you don't, please do ask. You'll note this only does a SELECT, nothing else. As I said above, I suggest splitting out the operations:CREATE PROC dbo.crud_select_operation @TableName varchar(100), @id INT = NULLASDECLARE @SQL nvarchar(4000); --This will hold our Dynamic SQLDECLARE @parm nvarchar(100); --This hold the definition of our parameter for our D-SQL, if we need it.--Start off with the basic of the SELECT statementSELECT @SQL = N'SELECT *FROM ' + QUOTENAME([name]) --Quote the table name, incase it has special charactersFROM sys.tables --We use sys.tables, to ensure the table exists. If it doesn't exist, then NULL is returned (and no SQL is run)WHERE [name] = @TableName;--Let's do the part where there is an IDIF @ID IS NOT NULL BEGINSET @SQL = @SQL + N'WHERE id = @dID;'; --This adds a WHERE clauseSET @parm = N'@dID int'; --And that's the definition of our parameter in our Dynamic SQLPRINT @SQL;EXEC sp_executesql @SQL, @parm, @dID = @ID; --And the bit that runs it all. We're much safer using sp_executesqlEND ELSE BEGIN--This is is there is no IDSET @SQL = @SQL + N';'; --Future proofingPRINT @SQL;EXEC sp_executesql @SQL;ENDGOthank you very much
but i need insert and update
operation
Yes, I know you do; as i said before, are you happy to have these separately? Do you understand what the above is doing, and why it's safer?
The most important thing you need to learn from this post is the danger of SQL injection. I may well solve the problem you intially came here for later, however, what you need to learn is how bad the current SP you have is. You need to be able to come away from this topic knowing to never create a stored procedure like that, and to know how you should do it instead in the future as well.
Thom~
Excuse my typos and sometimes awful grammar. My fingers work faster than my brain does.
Larnu.uk
December 30, 2017 at 9:06 am
Thom A - Saturday, December 30, 2017 9:02 AMnatigsqlserver - Saturday, December 30, 2017 8:57 AMThom A - Saturday, December 30, 2017 8:51 AMI'll start off with an introduction anyway. This version below will avoid injection. I've commented the lines, which should help you understand what it's doing. if however, you don't, please do ask. You'll note this only does a SELECT, nothing else. As I said above, I suggest splitting out the operations:CREATE PROC dbo.crud_select_operation @TableName varchar(100), @id INT = NULLASDECLARE @SQL nvarchar(4000); --This will hold our Dynamic SQLDECLARE @parm nvarchar(100); --This hold the definition of our parameter for our D-SQL, if we need it.--Start off with the basic of the SELECT statementSELECT @SQL = N'SELECT *FROM ' + QUOTENAME([name]) --Quote the table name, incase it has special charactersFROM sys.tables --We use sys.tables, to ensure the table exists. If it doesn't exist, then NULL is returned (and no SQL is run)WHERE [name] = @TableName;--Let's do the part where there is an IDIF @ID IS NOT NULL BEGINSET @SQL = @SQL + N'WHERE id = @dID;'; --This adds a WHERE clauseSET @parm = N'@dID int'; --And that's the definition of our parameter in our Dynamic SQLPRINT @SQL;EXEC sp_executesql @SQL, @parm, @dID = @ID; --And the bit that runs it all. We're much safer using sp_executesqlEND ELSE BEGIN--This is is there is no IDSET @SQL = @SQL + N';'; --Future proofingPRINT @SQL;EXEC sp_executesql @SQL;ENDGOthank you very much
but i need insert and update
operationYes, I know you do; as i said before, are you happy to have these separately? Do you understand what the above is doing, and why it's safer?
yes i was understand
but ned pass column name and values for insert and update process dynamically?
December 30, 2017 at 9:10 am
natigsqlserver - Saturday, December 30, 2017 9:06 AMyes i was understand
but ned pass column name and values for insert and update process dynamically?
Ok, provided you understand, that's fine. I'll be providing several SP's, which is going to take awhile to write up. I'll post again later.
Thom~
Excuse my typos and sometimes awful grammar. My fingers work faster than my brain does.
Larnu.uk
December 30, 2017 at 9:13 am
ok
thank you very much
i'm waiting
December 30, 2017 at 9:16 am
Thom A - Saturday, December 30, 2017 9:10 AMnatigsqlserver - Saturday, December 30, 2017 9:06 AMyes i was understand
but ned pass column name and values for insert and update process dynamically?Ok, provided you understand, that's fine. I'll be providing several SP's, which is going to take awhile to write up. I'll post again later.
ok thank you very much
i'm waiitng
December 30, 2017 at 10:21 am
Ok, that was a lot of work... Now, I'm made the comment in the script I've made as well, however, I'm going to repeat i'm not 100% happy with this. I pretty confident i've avoided injection, but the UPDATE and INSERT statement weren't fun with the addition of dynamic columns (or number of). I'm therefore, more than happy for someone to make changes to those. At the moment, however, it's a Saturday, and that was more work than I wanted to entertain on a day off.
Anyway, there's probably a decent amount to take in below. This script create a sample database [Crud], however, if you have a test environment I still suggest you run it there first, and make sure you understand it. Feel free to ask questions about it. Apologies for the formatting; that's SSC's fault. As such, I've also attached a copy to this post, which maintains the original formatting.
This script was tested on:
Microsoft SQL Server 2017 (RTM-CU2) (KB4052574) - 14.0.3008.27 (X64)
Nov 16 2017 10:00:49
Copyright (C) 2017 Microsoft Corporation
Developer Edition (64-bit) on Linux (Ubuntu 17.10)
As you posted in the SQL Server 2017, I've assumed that's what you are using.
Thom~
Excuse my typos and sometimes awful grammar. My fingers work faster than my brain does.
Larnu.uk
December 30, 2017 at 11:33 am
Thom A - Saturday, December 30, 2017 10:21 AMOk, that was a lot of work... Now, I'm made the comment in the script I've made as well, however, I'm going to repeat i'm not 100% happy with this. I pretty confident i've avoided injection, but the UPDATE and INSERT statement weren't fun with the addition of dynamic columns (or number of). I'm therefore, more than happy for someone to make changes to those. At the moment, however, it's a Saturday, and that was more work than I wanted to entertain on a day off.Anyway, there's probably a decent amount to take in below. This script create a sample database [Crud], however, if you have a test environment I still suggest you run it there first, and make sure you understand it. Feel free to ask questions about it. Apologies for the formatting; that's SSC's fault. As such, I've also attached a copy to this post, which maintains the original formatting.
This script was tested on:
Microsoft SQL Server 2017 (RTM-CU2) (KB4052574) - 14.0.3008.27 (X64)
Nov 16 2017 10:00:49
Copyright (C) 2017 Microsoft Corporation
Developer Edition (64-bit) on Linux (Ubuntu 17.10)As you posted in the SQL Server 2017, I've assumed that's what you are using.
USE [master];--Create a sample DBCREATE DATABASE Crud;GOUSE Crud;GO--Sample TableCREATE TABLE Test (ID int, String varchar(10));--Initial Sample DataINSERT INTO TestVALUES (1,'A'),(2,'B'),(2,'BA');GO--Select ProcCREATE PROC dbo.crud_select_operation @TableName varchar(100), @ID int = NULLASDECLARE @SQL nvarchar(4000); --This will hold our Dynamic SQLDECLARE @parm nvarchar(100); --This hold the definition of our parameter for our D-SQL, if we need it.--Start off with the basic of the SELECT statementSELECT @SQL = N'SELECT *FROM ' + QUOTENAME([name]) --Quote the table name, incase it has special charactersFROM sys.tables --We use sys.tables, to ensure the table exist. If it doesn't exist, then NULL the returned (and no SQL is run)WHERE [name] = @TableName;--Let's do the part where there is an IDIF @ID IS NOT NULL BEGINSET @SQL = @SQL + N'WHERE ID = @dID;'; --This add a WHERE clauseSET @parm = N'@dID int'; --And that's the definition of our parameter in our Dynamic SQLPRINT @SQL;EXEC sp_executesql @SQL, @parm, @dID = @ID; --And the bit that runs it all. We're much safer using sp_executesqlEND ELSE BEGIN--This is is there is no IDSET @SQL = @SQL + ';'; --Future proofingPRINT @SQL;EXEC sp_executesql @SQL;ENDGO--TestingEXEC crud_select_operation @TableName = 'Test'; --3 rows!EXEC crud_select_operation @TableName = 'Test', @Id = 2; --2 row, For ID 2;GO--Delete is going to be easier, so let's do that nextCREATE PROC crud_delete_operation @TableName varchar(100), @ID int --ID is required, so no default valueAS--Unsurprisingly, this is very similar to the SELECTDECLARE @SQL nvarchar(4000), @parm nvarchar(100);--Start off with the basic of the SELECT statementSELECT @SQL = N'DELETEFROM ' + QUOTENAME([name]) + N'WHERE ID = @dID;' --We can go straight to a WHERE this timeFROM sys.tables --We use sys.tables, to ensure the table exist. If it doesn't exist, then NULL the returned (and no SQL is run)WHERE [name] = @TableName;SET @parm = N'@dID int'; --And that's the definition of our parameter in our Dynamic SQLPRINT @SQL;EXEC sp_executesql @SQL, @parm, @dID = @ID; --And the bit that runs it all. We're much safer using sp_executesqlGO--Testing timeEXEC crud_delete_operation @TableName = 'Test', @ID = 1;--And might as well check that ID one has gone:EXEC crud_select_operation @TableName = 'Test'; --2 rows! Success!GO--Now UPDATE and SELECT have multiple columns involved.--That adds an extra layer of complexity. So let's use a Custom Table Data Type:CREATE TYPE crud_columns_and_values AS TABLE (ColumnName varchar(100), ColumnValue varchar(100)); --the size of Column Value may need to be largerGO--Now, we can use that new datatype to do our other SP's:--Let's do the INSERTCREATE PROC crud_insert_operation @TableName varchar(100), @ColVals crud_columns_and_values READONLYASDECLARE @SQL nvarchar(4000);--Start off with the basics againSELECT @SQL = N'INSERT INTO' + QUOTENAME([name]) --Quote the table name, incase it has special charactersFROM sys.tables --We use sys.tables, to ensure the table exist. If it doesn't exist, then NULL the returned (and no SQL is run)WHERE [name] = @TableName;--Now, however, we have to get all those columns into thereSELECT @SQL = @SQL + N'(' +--This creates a delimited list of the columns--Again, it uses sys.columns as we want to ensure the column really exists.STUFF((SELECT N',' + QUOTENAME(c.[name])FROM sys.columns cJOIN sys.tables t ON c.object_id = t.object_idWHERE t.[name] = @TableNameAND c.Name IN (SELECT CV.ColumnName FROM @ColVals CV)ORDER BY c.[name] --ORDERING IS IMPORTANT!FOR XML PATH(N'')),1,1,N'') +--This is called the FOR XML STUFF technique. Have a Google if you don't understand what it's doing--or reply to my post.N')' + NCHAR(10); --NCHAR(10) is a line break--This is the "hard" bit, we need to get those values in--I'm not 100% happy on this, but I *think* we've avoided injection here. I am more than happy for someone to prove me wrong here thoughSET @SQL = @SQL + N'SELECT ' +STUFF((SELECT N',' + N'''' + REPLACE(ColumnValue,N'''',N'''''') + N''''FROM @ColValsORDER BY ColumnNameFOR XML PATH(N'')),1,1,N'') + N';';PRINT @SQL;EXEC sp_executesql @SQL;GO--Now to testDECLARE @ValuesToInsert crud_columns_and_values;INSERT INTO @ValuesToInsertVALUES ('ID','3'),('String','C');EXEC crud_insert_operation @TableName = 'Test', @ColVals = @ValuesToInsert;GODECLARE @ValuesToInsert crud_columns_and_values;INSERT INTO @ValuesToInsertVALUES ('ID','4'),('String','D''d');EXEC crud_insert_operation @TableName = 'Test', @ColVals = @ValuesToInsert;GO--Better check that as well!EXEC crud_select_operation @TableName = 'Test'; --4 rows!GO--Ok, finally, the UPDATECREATE PROC crud_update_operation @TableName varchar(100), @ID int, @ColVals crud_columns_and_values READONLYASDECLARE @SQL nvarchar(4000);--Start off with the basics againSELECT @SQL = N'UPDATE ' + QUOTENAME([name]) + NCHAR(10)--Quote the table name, incase it has special charactersFROM sys.tables --We use sys.tables, to ensure the table exist. If it doesn't exist, then NULL the returned (and no SQL is run)WHERE [name] = @TableName;--Again, I'm not 100% happy on this, but I *think* we've avoided injection here. I am more than happy for someone to prove me wrong here thoughSET @SQL = @SQL + N'SET ' + STUFF((SELECT N',' + QUOTENAME(c.name) + N' = ''' + REPLACE(CV.ColumnValue,N'''',N'''''') + N''''FROM sys.columns cJOIN sys.tables t ON c.object_id = t.object_idJOIN @ColVals CV ON c.[name] = CV.ColumnNameWHERE t.[name] = @TableNameORDER BY c.[name] --ORDERING IS IMPORTANT!FOR XML PATH(N'')),1,1,N'') + N';'PRINT @SQL;EXEC sp_executesql @SQL;GODECLARE @ValuesToUpdate crud_columns_and_values;INSERT INTO @ValuesToUpdateVALUES ('String','E''e');EXEC crud_update_operation @TableName = 'Test', @ID = 4, @ColVals = @ValuesToUpdate;EXEC crud_select_operation @TableName = 'Test', @ID = 4; --Value has E'e!!!GO--Clean upUSE [master];DROP DATABASE Crud;GO
thanks Alot TOM
great working
but have a problem because this script will working in c# asp.net web app
i think delete and select will succes work
but insert and update need first look table have a this data in sql table?if have dont need need insert or
have't then insert
and need pass parameter thats structure
exec dbo.ourproc _insert @tablenmae='xxx',coumns='col1,col2,....coln' ,values='val1,val2....valn'
can we create thi structure in our sroed proc ?
than you very much for discussion and helping
December 30, 2017 at 11:53 am
You can define table parameters in C#. I'd suggest keeping with the Custom Table Data Type and incorporating it into your application, rather than a delimited string.
Have a research yourself on how to achieve this first.
Thom~
Excuse my typos and sometimes awful grammar. My fingers work faster than my brain does.
Larnu.uk
Viewing 15 posts - 1 through 15 (of 32 total)
You must be logged in to reply to this topic. Login to reply