Dynamic WHERE clause in T-SQL - sql

I have a requirement to display reports if a field value or a combination of field value matches.
I have designed a table to store ReportId values against a field or a combination of fields. I have stored the values in a pattern so that I can construct the WHERE clause for SQL to fetch desired data. Following is the table data:
Field1 Field2 Field3 ReportId
2 NULL NULL Rep1
5 4 NULL Rep2
6 NULL 8 Rep4
Now, I want to create a stored procedure to fetch relevant ReportIds. In the stored procedure I have following parameters as input:
Parameter1, Parameter2, Parameter3
In the stored procedure, I want to construct a SQL with a dynamic WHERE clause to fetch ReportIds. The WHERE clause will put a AND operator between all NON NULL fields and compare with the passed parameters.
As per the given table data, the non-null field in first row is “Field1”. So the WHERE clause will be
Field1 = Parameter1
As per the given table data, the non-null fields in the second row is “Field1” and “Field2”. So WHERE clause will be:
Field1 = Parameter1 AND Field2 =Parameter2
As per the given table data, the non-null fields in the third row is “Field1” and “Field3”. So the WHERE clause will be:
Field1 = Parameter1 AND Field3 =Parameter3
How I can write a generic SQL with a dynamic WHERE clause for this requirement?

Le sigh.
The solution I am thinking of is a simple:
WHERE (Field1 IS NULL OR Field1=#Parameter1)
AND (Field2 IS NULL OR Field2=#Parameter2)
AND ...
You can stack any number of field/parameter pairings into this solution.

You can construct the query by appending the where clause to NVARCHAR(MAX) variable and then execute that query with sql built in function sp_executesql
For Example
DECLARE #query NVARCHAR(MAX);
SET #query = 'SELECT #Count = COUNT(*) FROM Reports WHERE 1=1 '
IF #Field1 IS NOT NULL
SET #query = #query + 'AND Field1 = #Field1 '
......
......
......
EXECUTE sp_executesql #query,
N'#Field1 VARCHAR(MAX),
....
....
#Param1,
.....
.....
I hope this helps you get the right direction.

If you think about what you are looking for and restate your question it becomes easier. What do you really want to do? You want to include rows where each field matches the parameter passed, or whether the value in the table is null. So you want to match rows where each field is either null, or it matches the parameter:
WHERE (Field1 is null OR Field1 = #Parameter1)
AND (Field2 is null OR Field2 = #Parameter2)
AND (Field3 is null OR Field3 = #Parameter2)

Related

Optional clauses in WHERE SQL COBOL

I have a form and each field is optional.
I would like to make an SQL query that includes optional conditions in the WHERE.
I'm using as a programming language COBOL, so i can't concatinate where clauses on the query
Bellow is my Query
SELECT *
FROM TABLE
WHERE Field1 = :VAL1
AND Field2 = :VAL2
How can i fill VAL1 and VAL2 when fields of the form is empty to get all row of the table TABLE
You can add an extra condition in the filtering. For example:
SELECT *
FROM TABLE
WHERE (Field1 = :VAL1 or :VAL1 = '')
AND (Field2 = :VAL2 or :VAL2 = '')
Note: If performance becomes an issue, it can be improved by the use of Dynamic SQL. That is, by dynamically adding only the parameters that are significant. This, of course, requires extra effort on coding and testing.
You could use different queries depending on the values filled from the form.
For example:
IF VAL1 EQUAL SPACES AND VAL2 EQUAL SPACES
EXEC SQL
SELECT *
FROM TABLE
END-EXEC
ELSE IF FIELD1 EQUAL SPACES
EXEC SQL
SELECT *
FROM TABLE
WHERE FIELD2 = :VAL2
END-EXEC
ELSE
EXEC SQL
SELECT *
FROM TABLE
WHERE FIELD1 = :VAL1
END-EXEC
END-IF
You can use SQLCODE =100 here is an example :
EXEC SQL
SELECT *
FROM TABLE
WHERE Field1 = :VAL1
AND Field2 = :VAL2
END-EXEC.
EVALUATE SQLCODE
WHEN ZEROS
CONTINUE
WHEN 100
*fill VAL1 and VAL2
WHEN OTHER
DISPLAY 'ERREUR'
END-EVALUATE.

Using column variables in my WHERE clause

I have two tables (tableA and tableB) both with a name column. tableA's name column might be called NAME, tableB's column might be called FULLNAME, but they both are supposed to have the same value.
I am to write a query that pulls member id's (from either table) where these two column values are not the same. However, I'd like to pass the column names I'm checking via parameter, as this will be going in an SSRS report and in the future i'd like to be able to use it to compare any other column between these two tables.
Something like this:
DECLARE #COLUMN_A VARCHAR(50), #COLUMN_B VARCHAR(50)
/* COLUMN PARAMS WILL BE PASSED IN VIA SSRS */
SELECT
DISTINCT(MEMBER_ID)
FROM
TABLE_A
JOIN TABLE_B
ON (TABLE_A.MEMBER_ID = TABLE_B.MEMBER_ID)
WHERE
#COLUMN_A <> #COLUMN_B
Is something like this possible?
edit:
Or might something like this work?
DECLARE
#column VARCHAR(50)
SELECT #column = 'FIRST_NAME';
SELECT DISTINCT
MEMBR_ID,
case
when #column='FIRST_NAME' then MEMBR_FIRST_NAME
when #column='LAST_NAME' then MEMBR_LAST_NAME
end TABLE_1,
case
when #column='FIRST_NAME' then FIRSTNAME
when #column='LAST_NAME' then LASTNAME
end TABLE_2,
#column
FROM
TABLE_1
JOIN TABLE_2
ON (TABLE_1.MEMBR_ID = TABLE_2.MEMBR_ID)
WHERE
TABLE_1.#column <> TABLE_2.#column
Is something like this possible?
Technically, the syntax is fine. The where will be comparing two constant strings. The results will be either all rows or no rows, depending on whether the two strings are the same.
Do these evaluate to the columns? No, they do not. You cannot pass parameters into a SQL statement for identifiers -- column names, table names, schema names, database names, function names, or operators (for example).
You can do this using dynamic SQL, but you have to plug the names in:
DECLARE #sql NVARCHAR(MAX);
SET #sql = '
SELECT DISTINCT A.MEMBER_ID
FROM TABLE_A A JOIN
TABLE_B B
ON A.MEMBER_ID = B.MEMBER_ID
WHERE A.#COLUMN_A <> B.#COLUMN_B
';
SET #sql = REPLACE(#sql '#COLUMN_A', COLUMN_A);
SET #sql = REPLACE(#sql '#COLUMN_B', COLUMN_B);
exec sp_executesql #sql;

Multi Columns filtration in stored procedure in SQL Server

I am having more controls (assume 10 controls with textbox, dropdown, radio buttons) in my Windows forms application for filtering data which all are not a mandatory, hence user may filter data with 1 control or more.
Now I have to create a stored procedure for filtering the data based on their inputs.
Ex: if user enters some text in 1 textbox control, and left remaining 9 controls with empty data, I have to filter data based on only that textbox which user entered.
If user enters some text in 1 textbox control and 1 dropdown, and left remaining 8 controls with empty data, I have to filter data based on only that textbox and dropdown which user entered.
What am I supposed to do?
In source code:
If user entered/selected text on any control, I am passing values as parameters else i am passing as "null" to remaining all other parameters .
In stored procedure:
I gave all 10 controls parameters to get value from Source Code,based on parameters I am filtering data.
if #Param1=null && #Param2=null && #Param3='SomeText'
begin
sELECT * FROM tABLE1 wHERE TableCOLUMN3=#Param3
END
if #Param1=null && #Param2='SomeText' && #Param3='SomeText'
begin
sELECT * FROM tABLE1 wHERE TableCOLUMN2=#Param2 AND TableCOLUMN3=#Param3
END
Note: I need to filter data with each table column to each parameter , Simply assume #Param1--TableCOLUMN1, #param2--TableCOLUMN2, filter varies depend on parameters text.
If I do like this my stored procedure will be more enormous and very big because I have 10 parameters to check (just for your reference I gave 3 parameters above sample).
What I want is :
Since I gave 10 parameters, based on parameters which having values (some text other than NULL) only I have to filter data by using where condition.
Is there any other way to do this, or does anyone have any other ways for this to do?
As long as you make your params default to null and either don't pass in a value for the params you dont need or pass in dbnull value then you can filter like this
CREATE PROC dbo.SAMPLE
(
#Param1 VARCHAR(255) = NULL,
#Param2 VARCHAR(255) = NULL,
#Param3 VARCHAR(255) = NULL,
#Param4 VARCHAR(255) = NULL,
#Param5 VARCHAR(255) = NULL,
#Param6 VARCHAR(255) = NULL
)
AS
BEGIN
SELECT *
FROM Table1
WHERE (#Param1 IS NULL OR TableCOLUMN1 = #Param1)
AND (#Param2 IS NULL OR TableCOLUMN2 = #Param2)
AND (#Param3 IS NULL OR TableCOLUMN3 = #Param3)
AND (#Param4 IS NULL OR TableCOLUMN4 = #Param4)
AND (#Param5 IS NULL OR TableCOLUMN5 = #Param5)
OPTION (RECOMPILE) -- as JamesZ suggested to prevent caching
END
EXEC dbo.SAMPLE #Param2 = 'SomeText' -- only filter where TableCOLUMN2 = #Param2
I would suggest something like that:
SELECT *
FROM TABLE1
WHERE TableCOLUMN1=ISNULL(#Param1,TableCOLUMN1)
AND TableCOLUMN2=ISNULL(#Param2,TableCOLUMN2)
AND TableCOLUMN3=ISNULL(#Param3,TableCOLUMN3)
AND TableCOLUMN4=ISNULL(#Param4,TableCOLUMN4)
... and so on...
This will filter column1 on a value if you specify param1 otherwise it will use the columnvalue itself which will always be true.
But this will only work if your #Param values were NULL in each case if you won't use them.
If the table is big / you need to use indexes for fetching the rows, the problem with this kind of logic is, that indexes can't really be used. There's basically two ways how you can do that:
Add option (recompile) to the end of the select statement by #Ionic or #user1221684. This will cause the statement to be recompiled every time it is executed, which might be a lot of CPU overhead if it's called often.
Create dynamic SQL and call it using sp_executesql
Example:
set #sql = 'SELECT * FROM TABLE1 WHERE '
if (#Param1 is not NULL) set #sql = #sql + 'TableCOLUMN1=#Param1 AND '
if (#Param2 is not NULL) set #sql = #sql + 'TableCOLUMN2=#Param2 AND '
if (#Param3 is not NULL) set #sql = #sql + 'TableCOLUMN3=#Param3 AND '
-- Note: You're not concatenating the value of the parameter, just it's name
set #sql = #sql + ' 1=1' -- This handles the last 'and'
EXEC sp_executesql #sql,
N'#Param1 varchar(10), #Param2 varchar(10), #Param3 varchar(10)',
#Param1, #Param2, #Param3
As an extra option, you could do some kind of mix between your original idea and totally dynamic one, so that it would have at least the most common search criteria handled so that in can be fetched efficiently.
Normally every parameter will have a default value, for example int will have the default value as zero. So using this you can have the condition. See the exam sql below.
create procedure [dbo].[sp_report_test](
#pParam1 int,
#pParam2 int ,
#pParam3 int,
#pParam4 varchar(50)
)
AS
SELECT
*
FROM [vw_report]
where
(#pParam1 <= 0 or Column1 = #pParam1) and
(#pParam2 <= 0 or Column2 = #pParam2) and
(#pParam3 <= 0 or Column3 = #pParam3) and
(#pParam4 is null or len(#pParam4) <= 0 or Column4 = #pParam4);
GO

Assigning Value along with Data Retrieval

Is there a way to combine assigning a value to a variable and Selecting a column in sql. I need to compute and select a column in a table based on the variable. The variable's value changes based on another column in the table.
var #BeginValue
Columns in table : ReducedBy
My initial begin value is stored in #BeginValue. The table has reducedBy which is a factor by which my begin value should be reduced. So when i select, beginvalue for the first recored would be #BeginValue and the #EndValue should be #BeginValue = #BeginValue - reducedBy. It continues like this, as many times as the number of records in my table.
Result set must be like this:
#Begin = 10
Begin End ReducedBy
10 8 2
8 6 2
6 5 1
Is there a way with which i can achieve this without using a cursor or with multiple update statements.
You can't assign in a query that returns a result set. The closest you can get is to store the result in a table variable. Then you can both do computations against that table, and return it as a result set:
-- Store results in table variable
declare #tbl table (id int, col1 int, ...)
insert #tbl
(id, col1, ...)
select id
, col1
, ...
from ... your query here ...
-- Assign variable
select #YourVariable = ... your computation here ...
from #tbl
-- Return result set
select *
from #tbl
If your question is
Can I do..
SELECT #a = field, field2 from table
and get a resultset and set the value of #a?
Then the answer is no, not in a single statement.

SQL problem with multi field searches

I am having some problems here, I have actually had the same issue for a while now but I hack around and get it working in the end however I would like to know if I have missed a simple way of doing it.
Say if I have:
Field input 1
Field input 2
Field input 3 (empty)
Field input 4
I want to query SELECT * FROM tbl_table WHERE field1 LIKE ? AND field2 LIKE ? AND field3 LIKE ? AND field4 LIKE ?
Basically I come into trouble when an input is empty because its searching in a field and looking for null or another string when I want it to just discard the LIKE operator of the empty Input.
I know this might read really bad however its hard to get a point across some times.
SELECT * FROM tbl_table WHERE (field1 IS NULL OR field1 LIKE ?) AND (field2 IS NULL OR field2 LIKE ?) AND ....
Essentially, you need to check the value of the variable in the where clause. Check if it is null or has value like this.
Declare #input1 varchar(50);
Declare #input2 varchar(50);
Declare #input3 varchar(50);
Declare #input4 varchar(50);
SET #input1 = 'a'
SET #input2 = 'b'
SET #input3 = NULL
SET #input4 = 'c'
SELECT
*
FROM tbl_table
WHERE
(#input1 is null OR field1 LIKE #input1)
AND (#input2 is null OR field1 LIKE #input2)
AND (#input3 is null OR field1 LIKE #input3)
AND (#input4 is null OR field1 LIKE #input4)