DECLARE #a varchar(max);
set #a ='''a'' OR Name like ''%a'';';
--Why the below query not working
Select TOP 10 * FROM Member where Name = #a
-- The query below was executed to make sure that the query above
being constructed properly
print 'SQL: Select TOP 10 * FROM Member where Name ='+ #a
--SQL: Select TOP 10 * FROM Member where Name ='a' OR Name like '%a';
Correct me if im wrong, SQL injection wont work in Stored Procedure is due to some precompiled factor but the above scenario was tested in query statement instead of Stored Procedure. Why still not working?
I'm not sure why you think that would work. #a is a varchar variable, so Select TOP 10 * FROM Member where Name = #a finds rows where Name is equal to the value of that variable.
If you want SQL-Server to take the value of #a and insert it into the query as code, then you need to use sp_executesql (analogous to eval in languages like Bash and Python and JavaScript):
EXECUTE sp_executesql 'Select TOP 10 * FROM Member where Name = ' + #a
SQL Injection occurs when data is confused for and interpreted as code.
This does not happen in your scenario since parameter or variable values are not directly interpreted as code - they're only at risk of being interpreted as code if you construct new code by combining strings and these parameter/variable values and then pass the entire constructed string to the system and ask it to interpret the entire string as code - via exec, sp_executesql or other such means.
Look there is no name ending with 'a'. Try like
Select TOP 10 * FROM Member where Name ='a' OR Name like '%a%'
Updated
Microsoft handle SQL injection for SQL parameters.
Related
Is it possible to test for a column before selecting it within a select statement?
This may be rough for me to explain, I have actually had to teach myself dynamic SQL over the past 4 months. I am using a dynamically generated parameter (#TableName) to store individual tables within a loop (apologize for the vagueness, but the details aren't relevant).
I then want to be able to be able to conditionally select a column from the table (I will not know if each table has certain columns). I have figured out how to check for a column outside of a select statement...
SET #SQLQuery2 = 'Select #OPFolderIDColumnCheck = Column_Name From INFORMATION_SCHEMA.COLUMNS Where Table_Name = #TABLENAME And Column_Name = ''OP__FolderID'''
SET #ParameterDefinition2 = N'#TABLENAME VARCHAR(100), #OPFolderIDColumnCheck VARCHAR(100) OUTPUT'
EXECUTE SP_EXECUTESQL #SQLQuery2, #ParameterDefinition2, #TABLENAME, #OPFolderIDColumnCheck OUTPUT
IF #OPFolderIDColumnCheck IS NULL
BEGIN
SET #OP__FOLDERID = NULL
END
ELSE
IF #OPFolderIDColumnCheck IS NOT NULL
BEGIN
...etc
but id like to be able to do it inside of a select statement. Is there a way to check and see if OP__FOLDERID exists in the table?
Id like to be able to do something like this:
SELECT IF 'OP__FOLDERID' EXISTS IN [TABLE] THEN 'OP__FOLDERID' FROM [TABLE]
Thank you for any help or direction you can offer.
I'm afraid there isn't any direct way to do this within a SELECT statement at all. You can determine if a column exists in a table, however, and construct your dynamic SQL accordingly. To do this, use something like this:
IF COL_LENGTH('schemaName.tableName', 'columnName') IS NOT NULL
BEGIN
-- Column Exists
END
You could then set a variable as a flag, and the code to construct the dynamic SQL would construct the expression with/without the column, as desired. Another approach would be to use a string value, and set it to the column name if it is present (perhaps with a prefix or suffix comma, as appropriate to the expression). This would allow you to save writing conditionals in the expression building, and would be particularly helpful where you have more than one or two of these maybe-columns in a dynamic expression.
I want to be able to run a snippet of my SQL query by selecting it and pressing F5. Issue is, if that selection contains a variable name I get an error: Must declare the scalar variable "#variableName".. Is there anyway to resolve this? I want variableName to be the value it would otherwise be had I run the whole statement at that moment in time that I've selected...
Sample of full code:
DECLARE #cat INT;
SET #cat = 2;
SELECT * FROM TableName
WHERE ColumnName = #cat;
Sample of my selection that I want to run without including declaration/set lines:
SELECT * FROM TableName
WHERE ColumnName = #cat;
Probably not possible but I figured it'd be worth a shot.
P.S. I'm a SQL noobie so if I'm missing something obvious let me know!
I understand where you are coming from. This is a snippet in a long procedure or something and naturally you want to keep the declarations at the top, which I agree with. In this case, when you are testing, the only real way to circumvent this is to re-declare it and set it at the top of your snippet. Then, when you are running the entire batch of code just comment out this line. Otherwise you'd have to wrap the snippet in a try / catch block to try and catch compile errors which is tricky.
Also, this is usually how I've seen people put a select * from someWorkTable to test results along the way. Then it's commented out when the batch is ran.
Left click on table name, right click design and you are able to view the datatype of the column name.
if it is nvarchar..
DECLARE #cat INT;
SET #cat = 2;
Convert(varchar, #cat)
SELECT * FROM TableName
WHERE ColumnName = #cat;
OR
directly declare
DECLARE #Cat VARCHAR(3)
SET #cat = '2'
SELECT * FROM TableName
WHERE ColumnName = #cat;
Hope this helps
You can simulate your variable as declared in a select query with an alias result. Then you can just use alias.column as part of your join...
SELECT
TN.*
FROM
( select '2' as TmpColumn ) tmpAlias
JOIN TableName TN
on tmpAlias.TmpColumn = TN.ColumnName
this way, no "scalar" variable is required, but not as practical as a simple parameterized query using a direct WHERE clause. Additionally, you could use the alias.column throughout in case you had other tables relations, etc or even additional "variables" you wanted to apply in your query.
I have a Table in my Database Which have name of all the Database of my Server
Table Look like
create Table #db_name_list(Did INT IDENTITY(1,1), DNAME NVARCHAR(100))
INSERT INTO #db_name_list
SELECT 'db_One ' UNION ALL
SELECT 'db_Two' UNION ALL
SELECT 'db_Three' UNION ALL
SELECT 'db_four' UNION ALL
SELECT 'db_five'
select * from #db_name_list
I have so many SP in my Database..Which uses multiple table and Join Them..
At Present I am using the SQL code like
Select Column from db_One..Table1
Left outer join db_two..Table2
on ....some Condition ....
REQUIREMENT
But I do not want to HARDCODE the DATABASE Name ..
I want store DataBase name in Variable and use that .
Reason :: I want to restore same Database with Different name and want to Run those SP..At Present we Cant Do ,Because I have used db_One..Table1
or db_two..Table2
I want some thing like ...
/SAMPLE SP/
CREATE PROCEDURE LOAD_DATA
AS
BEGIN
DECLARE #dbname nvarchar(500)
set #dbname=( SELECT DNAME FROM #db_name_list WHERE Did=1)
set #dbname2=( SELECT DNAME FROM #db_name_list WHERE Did=2)
PRINT #DBNAME
SELECT * FROM #dbname..table1
/* or */
SELECT * FROM #dbname2.dbo.table1
END
i.e using Variable Instead of Database name ..
But it thow error
"Incorrect syntax near '.'."
P.S This was posted by some else on msdn but the answer there was not clear & I had the same kind of doubt. So please help
You can't use a variable like this in a static sql query. You have to use the variable in dynamic sql instead, in order to build the query you want to execute, like:
DECLARE #sql nvarchar(500) = 'SELECT * FROM ' + #dbname + '.dbo.mytable'
EXEC(#sql);
There seem to be a couple of options for you depending on your circumstances.
1. Simple - Generalise your procedures
Simply take out the database references in your stored procedure, as there is no need to have an explicit reference to the database if it is running against the database it is stored in. Your select queries will look like:
SELECT * from schema.table WHERE x = y
Rather than
SELECT * from database.schema.table WHERE x = y
Then just create the stored procedure in the new database and away you go. Simply connect to the new database and run the SP. This method would also allow you to promote the procedure to being a system stored procedure, which would mean they were automatically available in every database without having to run CREATE beforehand. For more details, see this article.
2. Moderate - Dynamic SQL
Change your stored procedure to take a database name as a parameter, such as this example:
CREATE PROCEDURE example (#DatabaseName VARCHAR(200))
AS
BEGIN
DECLARE #SQL VARCHAR(MAX) = 'SELECT * FROM ['+#DatabaseName+'].schema.table WHERE x = y'
EXEC (#SQL)
END
I am creating a result set where I want the column name to be equal to a variable name that is et during run time. Is that possible ? How do I do that?
In the example below the user choses the date (myDate) before running the query (e.g 2015-06-11). The I want the column name to be that date (2015-06-11). How do I do that? FYI: I'm using Teradata.
SELECT
table_A.Cnt as ?myDate
/* I can't write ?myDate like that. I also tried to convert it to a string */
FROM
(
SELECT COUNT(*) AS Cnt FROM A
WHERE theDate=?myDate
) AS table_A
What you are trying to do is parameterize an object (or the name of an object) rather than parameterize a value, which seems straight forward when you think up the idea, but it's a bit more difficult to pull off.
First off, only an SP allows you to write and execute SQL dynamically, which is what you are doing here. Second, it's a little verbose. Third, it opens you up to SQL injection issues since you are slipping a parameter from a user into SQL then executing it, so proceed cautiously and do what you can to prevent a-holes from mucking up your system.
CREATE PROCEDURE paramMyField
(
IN myDate Date,
--This has to be less than 30 otherwise Teradata will be angry.
--I would set it low just to keep injection possibilities to minimum
IN fieldName VARCHAR(10)
)
--Tell it how many result sets this thing is going to return:
DYNAMIC RESULT SETS 1
--Set the security (using the security of the bloke that sets this thing off, if you don't trust them, neither do I)
SQL SECURITY INVOKER
BEGIN
--We'll need a variable to hold the dynamically generated sql statement
DECLARE dynSQL VARCHAR(5000);
--And we'll need a cursor and a statement
DECLARE dynCursor CURSOR WITH RETURN ONLY FOR dynStatement;
SET dynSQL = '
SELECT
table_A.Cnt as ' || fieldName || '
FROM
(
SELECT COUNT(*) AS Cnt FROM A
WHERE theDate = DATE ''' || myDate || '''
) AS table_A;';
--Now to prep the statement
PREPARE dynStatement FROM dynSQL;
--And open the cursor (we will open and not close it so it's sent back as a resultset
OPEN dynCursor;
END;
There's a lot happening there, but basically it's a stored procedure that takes in two parameters (the date and the name of the field) and spits back a record set that is the results of the SQL statement with a dynamically named field. It does this by using a dynamic SQL statement.
This is executed by running something like:
CALL paramMyField(DATE '2015-06-15', 'Whatever');
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Need help in dynamic query with IN Clause
I am using SQL server 2008 and this is the problem that I am facing. I have a table named Cars with a column Company. Now I have a stored procedure that looks something like this
CREATE PROCEDURE FindCars (#CompanyNames varchar(500))
AS
SELECT * FROM Cars WHERE Company IN (#CompanyNames)
I tried something like this and failed
DECLARE #CompanyNames varchar(500)
SET #CompanyNames = '''Ford'',''BMW'''
exec FindCars #CompanyNames
I dont get any rows returned. When I do the following
DECLARE #CompanyNames varchar(500)
SET #CompanyNames = '''Ford'',''BMW'''
Select #CompanyNames
I get the following result
'Ford','BMW'
and if I replace this value in the select statement inside the stored procedure, it works
SELECT * FROM Cars where Company in ('Ford','BMW')
Thus I think that the stored procedure seems to be treating 'Ford','BMW' as one string rather than an array. Could someone please help me with this. How do I dynamically construct the string/array required in the IN clause of the select statement inside the stored procedure.
You are right, you created one string, and that is being processed as a list of strings that contains one string. The commas are just characters in that one string. The only equivilent to an array in SQL Server is a table.
For example; WHERE x IN (SELECT y FROM z).
For this reason many people create a SPLIT_STRING() function that returns a table of items from a given comma delimitted string...
WHERE x IN (SELECT item FROM dbo.split_string(#input_string))
There are many ways to implement that split string. Some return strings, some cast to integers, some accept a second "delimiter" parameter, etc, etc. You can search the internet for SQL SERVER SPLIT STRING and get many results - Including here in StackOverflow.
An alternative is to use dynamic SQL; SQL that writes SQL.
SET #sql = 'SELECT * FROM x WHERE y IN (' + #input_string_list + ')'
SP_EXECEUTESQL #sql
(I recommend SP_EXECUTESQL over just EXEC because the former allows you to use parameterised queries, but the latter does not.)