I am deprecating a project from linq coding back to sql stored procedures. (My company refuses to upgrade our sql 2000 database.) I am stuck on this current code trying to convert it to sql. Can anyone help with this?
Dim ICD9Codes = (
From a In Linq2Db.ICD9Codes
Where IIf(String.IsNullOrEmpty(Variable1), 1 = 1, a.Code.StartsWith(Variable1))
Select a).ToList
I am stuck on the 'IIF' statements converting it where the 'where' clause only uses the if statement if the value is not null.
To convert this into a SP you'll need to make Variable1 a parameter. The IIf part could be addressed in the WHERE clause, like this:
CREATE PROCEDURE [procedure_name] #variable1 varchar(50)
AS
BEGIN
SELECT *
FROM ID9Codes
WHERE LEN(LTRIM(RTRIM(ISNULL(#variable1, '')))) = 0
OR Code lIKE #Variable1 + '%'
END
Related
I have a pretty simple Stored Procedure that I am in trouble to do because i'm new to SQL and PL/SQL. I Have a table with a name column that is a varchar(55).
I discovered that if the user executes my procedure with an empty string as a paramter the LIKE statment brings all rows from TABLE1
SELECT *
FROM TABLE1
WHERE COLUMN LIKE VARIABLE || '%'
AND...
So I tried to change the query so if the VARIABLE is passed with a empty string it can still perform other conditions in the where statment.
SELECT *
FROM TABLE1
WHERE (VARIABLE <> '' AND COLUMN LIKE VARIABLE || '%')
AND...
But now wherever I pass as variable ('', NULL, 'anystring') I get no rows returned.
How can I build a query that validates if the variable is different of empty string and if it is it performs the LIKE statment with the variable correctly?
If I understand you correctly, it is not difficult thing to do. You can use conditional WHERE clause using CASE WHEN. So your query will support different scenarios, something like this:
SELECT *
FROM TABLE1
WHERE (CASE WHEN variable IS NULL AND column IS NULL THEN 1
WHEN variable LIKE '%' AND column LIKE variable||'%' THEN 1
ELSE 0
END) = 1
AND...
Basically, it checks if the variable = '' then it will compare the column against ''. Otherwise, it will compare it against variable||'%'.
Notice, Oracle treats empty string of the type VARCHAR as NULL (this does not apply to CHAR). So, in the first scenario we compare against NULL.
Hello Just a thought for this we can use Dynamic sql too. If you may try this approach. Hope it helps.
CREATE OR REPLACE PROCEDURE SPS_TEST_OUT(
p_input_in IN VARCHAR2
)
AS
lv_sql LONG;
lv_where VARCHAR2(100);
BEGIN
lv_where:= CASE WHEN p_input_in IS NULL OR p_input_in = '' THEN
''
ELSE
' AND COLUMN1 LIKE '''||p_input_in||'''%'
END;
lv_sql:='SELECT * FROM TABLE
WHERE 1 = 1
' ||lv_where;
dbms_output.put_line(lv_sql);
END;
I have this XML Query in SQL Server 2005:
SElECT XmlField FROM tablename WHERE xmlField.exist('(/Root/Name[id="10")[1]') = 1
However, I want to replace the value "10" with a parameter that I pass to the Stored Procedure. How do I achieve this? I have tried using "#variablename" but it doesn't work.
Thanks in advance.
Probably, you want to have something like
SELECT XmlField FROM tablename WHERE xmlField.exist('(/Root/Name[id="{ sql:variable("#variablename") }")[1]') = 1
See http://msdn.microsoft.com/en-us/library/ms188254(v=SQL.100).aspx for how to access variables and columns in XQuery in SQL Server.
After a few minutes of hair pulling...i found an answer...
Result_XML.exist('(/Root/Name[id="{sql:variable("#myId")}"])[1]') = 1
should be written as
Result_XML.exist('(/Root/Name[id=(sql:variable("#myId"))])[1]') = 1
I replaced the "{ and }" with ( and ) to enclose the sql:variable keyword.
There is one more thing I found out about by many many trials: if your variable is a char value, if you declare it in your sql statement, it should be varchar, not char.
This sql didn't return any results:
DECLARE #myparam char(50)
SET #myparam = 'someval'
...
WHERE
t.c.exist('/root/child[text() = sql:variable("#myparam ")]') = 1
But this did:
DECLARE #myparam varchar(50)
SET #myparam = 'someval'
...
WHERE
t.c.exist('/root/child[text() = sql:variable("#myparam ")]') = 1
Maybe this is obvious, but I spent some time before I figured the reason why no records would be returned.
I am passing a comma-delimited list of values into a stored procedure. I need to execute a query to see if the ID of an entity is in the comma-delimited list. Unfortunately, I think I do not understand something.
When I execute the following stored procedure:
exec dbo.myStoredProcedure #myFilter=N'1, 2, 3, 4'
I receive the following error:
"Conversion failed when converting the varchar value '1, 2, 3, 4' to data type int."
My stored procedure is fairly basic. It looks like this:
CREATE PROCEDURE [dbo].[myStoredProcedure]
#myFilter nvarchar(512) = NULL
AS
SET NOCOUNT ON
BEGIN
-- Remove the quote marks so the filter will work with the "IN" statement
SELECT #myFilter = REPLACE(#myFilter, '''', '')
-- Execute the query
SELECT
t.ID,
t.Name
FROM
MyTable t
WHERE
t.ID IN (#myFilter)
ORDER BY
t.Name
END
How do I use a parameter in a SQL statement as described above? Thank you!
You could make function that takes your parameter, slipts it and returns table with all the numbers in it.
If your are working with lists or arrays in SQL Server, I recommend that you read Erland Sommarskogs wonderful stuff:
Arrays and Lists in SQL Server 2005
You need to split the string and dump it into a temp table. Then you join against the temp table.
There are many examples of this, here is one at random.
http://blogs.microsoft.co.il/blogs/itai/archive/2009/02/01/t-sql-split-function.aspx
Absent a split function, something like this:
CREATE PROCEDURE [dbo].[myStoredProcedure]
#myFilter varchar(512) = NULL -- don't use NVARCHAR for a list of INTs
AS
SET NOCOUNT ON
BEGIN
SELECT
t.ID,
t.Name
FROM
MyTable t
WHERE
CHARINDEX(','+CONVERT(VARCHAR,t.ID)+',',#myFilter) > 0
ORDER BY
t.Name
END
Performance will be poor. A table scan every time. Better to use a split function. See: http://www.sommarskog.se/arrays-in-sql.html
I would create a function that takes your comma delimited string and splits it and returns a single column table variable with each value in its own row. Select that column from the returned table in your IN statement.
I found a cute way of doing this - but it smells a bit.
declare #delimitedlist varchar(8000)
set #delimitedlist = '|1|2|33|11|3134|'
select * from mytable where #delimitedlist like '%|' + cast(id as varchar) + '|%'
So... this will return all records with an id equal to 1, 2, 33, 11, or 3134.
EDIT:
I would also add that this is not vulnerable to SQL injection (whereas dynamic SQL relies on your whitelisting/blacklisting techniques to ensure it isn't vulnerable). It might have a performance hit on large sets of data, but it works and it's secure.
I have a couple of blog posts on this as well, with a lot of interesting followup comments and dialog:
More on splitting lists
Processing list of integers
My procedure was working fine in a 2005 database, but my PC died and when I set it up again I installed 2008 rather than 2005 - now this procedure doesn't return any results. I ask the question about the difference between the 2 versions simply because I have used this logic before and I haven't changed the procedure since I created it and it was working, the only change has been the fact I am now using SQL 2008
I wrote the procedure in Visual Studio and have noticed that when I paste the select statement into the SQL pane for the table that it is restructured and expanded so that each variation that could be expressed by combining the ANDs and ORs.
What I need is to be able to call this procedure optionally passing either parameter; so if I pass only the componentType it should evaluate the final statement part of the statement and use the value passed - if no value was passed then it would match the IS NULL side of the condition.
ALTER PROCEDURE dbo.uspSel_ComponentByType(
#filterText VARCHAR(50) = NULL
, #componentType CHAR(2) = NULL)
AS
SELECT [pkComponentID], [ComponentType], [ComponentName], [fkSupplierID], [Cost], [WastageCost]
FROM [tblComponents] AS c INNER JOIN
[tblSuppliers] AS s ON [c].[fkSupplierID] = [s].[pkSupplierID]
WHERE ([ComponentName] LIKE #filterText + '%' OR [SupplierName] LIKE #filterText + '%')
AND [c].[IsDeleted] = 0
AND (#componentType IS NULL OR [ComponentType] = #componentType)
I'm no SQL pro, but if I understand your intentions right, you should be able to use the sproc with no/either/both parameters and get expected results if you default #filterText to '' instead of NULL.
ALTER PROCEDURE dbo.uspSel_ComponentByType(
#filterText VARCHAR(50) = '' ,
#componentType CHAR(2) = NULL
)
AS
SELECT ... --the rest of the sproc is unchanged
As David M clarified, this is probably because SQL Server 2005 and 2008 handles string concatenation with NULL values differently. It seems that in SQL Server 2005
'A string' + NULL = 'A string';
while in SQL Server 2008
'A string' + NULL = NULL;
By changing the default to '', we made the default comparison '' + '%', which will always be treated as % and match everything, instead of NULL + '%', which will end upp NULL and match nothing.
Looks like different default handling of concatenating a null value - it is now concatenating NULL with '%' to give NULL, causing the LIKE comparison to fail. If you replace the NULL default with an empty string for #filterText you have a stored procedure that is not affected by such a difference in behaviour.
I guess it's due to SET options, especially likely is CONCAT_NULL_YIELDS_NULL, with ANSI_NULLS as a bubbler
We are trying to update our classic asp search engine to protect it from SQL injection. We have a VB 6 function which builds a query dynamically by concatenating a query together based on the various search parameters. We have converted this to a stored procedure using dynamic sql for all parameters except for the keywords.
The problem with keywords is that there are a variable number words supplied by the user and we want to search several columns for each keyword. Since we cannot create a separate parameter for each keyword, how can we build a safe query?
Example:
#CustomerId AS INT
#Keywords AS NVARCHAR(MAX)
#sql = 'SELECT event_name FROM calendar WHERE customer_id = #CustomerId '
--(loop through each keyword passed in and concatenate)
#sql = #sql + 'AND (event_name LIKE ''%' + #Keywords + '%'' OR event_details LIKE ''%' + #Keywords + '%'')'
EXEC sp_executesql #sql N'#CustomerId INT, #CustomerId = #CustomerId
What is the best way to handle this and maintaining protection from SQL injection?
You may not like to hear this, but it might be better for you to go back to dynamically constructing your SQL query in code before issuing against the database. If you use parameter placeholders in the SQL string you get the protection against SQL injection attacks.
Example:
string sql = "SELECT Name, Title FROM Staff WHERE UserName=#UserId";
using (SqlCommand cmd = new SqlCommand(sql))
{
cmd.Parameters.Add("#UserId", SqlType.VarChar).Value = "smithj";
You can build the SQL string depending on the set of columns you need to query and then add the parameter values once the string is complete. This is a bit of a pain to do, but I think it is much easier than having really complicated TSQL which unpicks lots of possible permutations of possible inputs.
You have 3 options here.
Use a function that converts lists tables and join into it. So you will have something like this.
SELECT *
FROM calendar c
JOIN dbo.fnListToTable(#Keywords) k
ON c.keyword = k.keyword
Have a fixed set of params, and only allow the maximum of N keywords to be searched on
CREATE PROC spTest
#Keyword1 varchar(100),
#Keyword2 varchar(100),
....
Write an escaping string function in TSQL and escape your keywords.
Unless you need it, you could simply strip out any character that's not in [a-zA-Z ] - most of those things won't be in searches and you should not be able to be injected that way, nor do you have to worry about keywords or anything like that. If you allow quotes, however, you will need to be more careful.
Similar to sambo99's #1, you can insert the keywords into a temporary table or table variable and join to it (even using wildcards) without danger of injection:
This isn't really dynamic:
SELECT DISTINCT event_name
FROM calendar
INNER JOIN #keywords
ON event_name LIKE '%' + #keywords.keyword + '%'
OR event_description LIKE '%' + #keywords.keyword + '%'
You can actually generate an SP with a large number of parameters instead of coding it by hand (set the defaults to '' or NULL depending on your preference in coding your searches). If you found you needed more parameters, it would be simple to increase the number of parameters it generated.
You can move the search to a full-text index outside the database like Lucene and then use the Lucene results to pull the matching database rows.
You can try this:
SELECT * FROM [tablename] WHERE LIKE % +keyword%