SQL Parameter Compare to Whitelist Column Values - sql

I have a table that has a whitelist of all valid domains. The column in question is called "URL"
URL column is VARCHAR(60) and #url is a .Net string primitive.
I want a SQL statement that returns "1" if the SQL parameter provided starts with the whitelisted URLs I have stored on my table. This is what I have:
SELECT 1
FROM [TABLE]
WHERE #url LIKE (URL || '%')
But it doesn't work and gives the following error:
A LIKE predicate or POSSTR scalar function is not valid because the first operand is not a string expression or the second operand is not a string.
An example of what I'd like to happen is when given the parameter value of HTTP://WWW.GOOGLE.COM/ANYTHING/AFTER/THIS and there is a row on my table that looks like HTTP://WWW.GOOGLE.COM it will return "1", but if there is not a row that starts with the domain then return null.
Example table values:
HTTP://WWW.GOOGLE.COM
HTTPS://WWW.ANOTHERWEBSITE.GOV
HTTP://WWW.DOMAIN.CORP
HTTP://MY.WEBSITE.COM
HTTPS://STUFF/SUBDOMAIN/
HTTP://BUSINESS.JUNK.CORP/

How about:
SELECT 1
FROM table
WHERE LEFT(URL, LENGTH(#url)) = #url;
or
SELECT 1
FROM table
WHERE LOCATE(URL, #url,1) = 1;
EDIT:
Depending of your datatypes I suggest to use cast:
CAST(URL AS VARCHAR(100)) -- instead of URL
CAST(#url AS VARCHAR(100)) -- instead of #url
EDIT FROM POSTER:
The combination of the above solutions solved my problem, I'll post the SQL that I used below:
SELECT 1
FROM table
WHERE LOCATE(URL, CAST(#url AS VARCHAR(60)), 1) = 1

Related

why I need a dynamic query for "column value from a query"

For example this returns a value from a query, which I will then use as a column name.
#A=Select top 1 productid from productlist order by timestamp desc
then I would like this "productid" A to be used in the other table
Select #A from customerlist
then the result is #A value instead of field value in customerlist.
When I use dynamic query, I can get right result.
Why?
(I know I can use join but because this productlist table is dynamic, so let's assume it is a sub query)
You need "dynamic SQL" because SQL will NOT allow you to use a parameter as a column name or a table name. You can only use parameters for data values such as in a where clause where column1 = #val
set #A = 'çolumn1'
Select #A from customerlist -- this fails because it is not allowed
Dynamic SQL is a "hack" to get around those restrictions as the SQL statement is placed into a string along with any value held by parameters.
set #A = 'çolumn1'
set #SQL = 'Select ' + #A + ' from customerlist;'
execute #SQL -- this works, the SQL statement is valid with no parameters as column names
The string formed as #SQL is a complete sql statement without needing any parameters as column names.
Note: the syntax I used here is incomplete and is based on MS SQL Server, different databases will use a different, but similar, syntax.

How to do a conditional where clause with where in PL/SQL within Procedure

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;

How do you pass values for a parameter by position when you need to check multiple values?

I created a stored procedure (spBalanceRange) with 2 optional parameters. They've been set to a default value and the sp works fine when I pass only 1 value per parameter by position. However, I have a situation where I'm trying to pass, by position, two strings immediately followed by a wildcard. I want the user to be able to search for Vendor names that start with either 'C%' or 'F%'. Here's the gist of the CREATE PROC statement:
CREATE PROC spBalanceRange
#VendorVar varchar(40) = '%',
#BalanceMin money = 1.0
...
Here's what I've tried so far, but doesn't work:
EXEC spBalanceRange '(C%|F%)', 200.00;
EXEC spBalanceRange 'C%|F%', 200.00;
Is there a way to check for 2 or more string values with a wildcard when passed by position? Thanks.
EDIT: According to your comments you are looking for the first letter of a vendor's name only.
In this special case I could suggest an easy, not well performing but really simple approach. CHARINDEX returns a number greater than zero, if a character appears within a string. So you just have to pass in all your lookup-first-characters as a simple "chain":
DECLARE #DummyVendors TABLE(VendorName VARCHAR(100));
INSERT INTO #DummyVendors VALUES
('Camel Industries')
,('Fritz and Fox')
,('some other');
DECLARE #ListOfFirstLetters VARCHAR(100)='CF';
SELECT VendorName
FROM #DummyVendors AS dv
WHERE CHARINDEX(LEFT(dv.VendorName,1),#ListOfFirstLetters)>0
This was the former answer
Checking against more than one value needs either a dedicated list of compares
WHERE val=#prm1 OR val=#prm2 OR ... (you know the count before)
...or you use the IN-clause
WHERE LEFT(VenoderName,1) IN ('C','F', ...)
...but you cannot pass the IN-list with a parameter like ... IN(#allValues)
You might think about a created TYPE to pass in all your values like a table and use an INNER JOIN as filter: https://stackoverflow.com/a/337864/5089204 (and a lot of other examples there...)
Or you might think of dynamic SQL: https://stackoverflow.com/a/5192765/5089204
And last but not least you might think of one of the many split string approaches. This is one of my own answers, section "dynamic IN-statement": https://stackoverflow.com/a/33658220/5089204
I'm answering my own question, and maybe other solutions exist but here is what had to happen with my stored procedure in order to pass variables by position:
CREATE PROC spBalanceRange
#VendorVar varchar(40) = '%',
#BalanceMin money = 1.0
AS
IF (#VendorVar = '%' AND #BalanceMin IS NULL OR #BalanceMin = '')
BEGIN
PRINT 'BalanceMin cannot be null.';
END
IF (#VendorVar = % AND #BalanceMin IS NOT NULL)
BEGIN
(sql statement using parameters)
END
EXEC spBalanceRange '[C,F]%', 200.00;
That's what I know.

SQL query with column name obtained from another table SQL Server 2012

trying to run the query
select * from customers, TablesList where TablesList.TableName+'ID' =
10 and tableslist.tableid= 123
where the column name obtained from another table. I get the following error
Msg 245, Level 16, State 1, Line 1 Conversion failed when converting
the nvarchar value 'CustomersID' to data type int.
I know I can do something like Select * from customers where customersID = 10
But trying to create CustomersID column name dynamically from another table. The intent it to have TablesList.TableName+'ID' give me CustomersID string that I can use to equate to 10.
My guess is that the value for Tablelist.TableName is Customer so when you do + 'ID' it results in 'CustomerID'. 'CustomerID' is the VALUE that is returned and not the FIELD NAME that gets compared to 10.
Hence when sqlserver try to convert 'CustomerID' to 10 you get an error message telling you that it's not an integer Value.
As far as I know you cannot get a "field name" from a field value directly trough SQL, for that you'd need to create a stored proc or some kind of programming language to build the query dynamically
TablesList.TableName+'ID' generates the string 'CustomersID'. You get the error because your comparison is actually made like this:
'CustomersID' = 10 -- The comparison NVARCHAR = INT produces the error
What i think you're trying to achieve requires dynamic SQL.
The problem with what you have is that your where clause is checking if the value 'CustomerID' is equal to 10. It isn't (and can't) use that string as a column name in that context. You need to use dynamic sql.
Dynamic SQL is where you build up a string which contains the SQL you ulitmately want to run. So as an example, you could do something like this:
declare #sql varchar(max)
set #sql = 'select * from customers where ' + (select top 1 TableName from TableList where tableId = 123) + 'ID = 10'
EXEC(#sql)
This sets the #sql variable to select * from customers where customerID = 10 then runs that statement.
Use Concat:
select * from customers, TablesList where Concat('TablesList.TableName','ID') =
10 and tableslist.tableid= 123

How to filter using WHERE with a parameter possibly beeing null

I'm using C# to write to a SQL Compact Edition 3.5 database. I got a table containing e-mail addresses and names for each address.
MailRecipientAddressID int primary key identity(1,1) not null,
Address nvarchar(4000),
Name nvarchar(4000)
In this table I want every address-name combination to be unique. In some cases it's possible that either Address or Name is NULL in a row. Before inserting new rows into this table, I'm using a SELECT query to check if there is an existing row matching the one I want to insert. When using this query
SELECT MailRecipientAddressID FROM MailRecipientAddress WHERE Address = #Address AND Name = #Name
I will not find existing rows with NULL values in one column (see here).
Now I got this query, which works and kind of solves my problem
SELECT MailRecipientAddressID FROM MailRecipientAddress WHERE ISNULL(Address, '') = ISNULL(#Address, '') AND ISNULL(Name, '') = ISNULL(#Name, '')
but even though it is no problem in my case that NULL and empty string values are handled equally, I do not like this solution. I think it's kind of hackish. Is there a better approach
to apply a filter on a SELECT statement with parameters which can contain NULL
which works on SQL CE
Edit
I do not understand why, but my query works with SQL Management Studio but it does not in my application (see here). To correct my own approach I would need to use COALESCE.
I don't like the option to replace my NULL values with empty strings because I think it would be kind of inconsequent to set a value at a place where I got no value or is my understanding of this design question wrong?
The best solution is a constraint on the table that prevents duplicates from going into the table. You can put one in with a unique index:
create unique index idx_MailRecipientAddress_address_name on MailRecipientAddress(Address, Name);
This will generate an error on the insert, which you would then need to catch.
However, this is only a partial solution, because NULL values do not count as duplicates. You might solve your overall problem by not allowing NULL values in the field at all. Instead, represent no data using empty strings. Note: I wouldn't normally recommend this. In SQL, NULL means "unknown" and by the definition of the language, two "unknown" values are not equal. However, you seem to want them to be equal.
As for SQL, yours is okay, but it equates NULL and the empty string. An explicit check is more accurate:
WHERE (Address = #Address or Address is null and #Address is null) and
(Name = #Name or Name is null and #Name is null)
#George
if Parameter value is Null and column value is not null then "(Address = #Address or Address is NULL) returns false "
if Parameter value is Null and column value is null then "(Address = #Address or Address is NULL) returns true"
if Parameter value is Not Null and column value is null then "(Address = #Address or Address is NULL) returns true"
if Parameter value is Not Null and column value is Not null and if matches then "(Address = #Address or Address is NULL) returns true otherwise false"
SELECT MailRecipientAddressID FROM MailRecipientAddress WHERE (Address = #Address or Address is NULL) AND (Name = #Name or Name is NULL)