SQL Multi-condition WHERE clause with one optional parameter? - sql-server

Reworking an existing Stored Procedure to make a previously required parameter optional.
The query is massive, and deals with much more than my current issue, so I won't post it in it's entirety but I believe I can get my fix by editing one of the WHERE clauses.
WHERE
O.wsID = #wsid AND
((M.UpdateDate BETWEEN #olddate AND #newdate) OR (MI.UpdateDate BETWEEN #olddate AND #newdate))
The first parameter #wsid is the value I need to make optional, it's initially declared as 0 and given a new value from a select box on the front-end of the website. I have attempted to use a CASE statement to alternate between to WHERE clauses depending on whether the value is 0 or an actual ID.
WHERE
#wsid = CASE
WHEN #wsid <> 0 THEN ((O.wsID = #wsid) AND ((M.UpdateDate BETWEEN #olddate AND #newdate) OR (MI.UpdateDate BETWEEN #olddate AND #newdate)))
ELSE ((M.UpdateDate BETWEEN #olddate AND #newdate) OR (MI.UpdateDate BETWEEN #olddate AND #newdate)))
END
But I get a bunch of syntax errors in the WHERE clause itself and also an error stating Expecting CONVERSATION or TRY for the SELECT statement below.
Is there an easier option for making the O.wsid = #wsid parameter optional?

WHERE
(O.wsID = #wsid OR #wsid = 0) AND
((M.UpdateDate BETWEEN #olddate AND #newdate) OR (MI.UpdateDate BETWEEN #olddate AND #newdate))

Related

SQL Report Builder: Adding <All> option to drop down

I found this question on SO elsewhere, but the answer included a part that doesn't pertain to me, so I must ask this question with my specifics.
I need to simply add an option in my dropdown menu. Here's my SQL query to be used for the salesperson only (debug mode):
declare #user varchar(30)
set #user = 'DOMAIN\ppelzel'
select SalesPerson_Name
from Salesperson
where salesperson_id = case
when #user in ('DOMAIN\Brandyj',
'DOMAIN\jwilson','DOMAIN\KRoberts',
'DOMAIN\ppelzel','DOMAIN\bmurray')then salesperson_id
else SUBSTRING(#user,14,20)
end
order by 1
Per my previous mention of another question like this asked, it said to not use a WHERE clause. I, however, must use a WHERE clause because I need it to determine if the person logged in matches what's in the dataset, then that is the only name they'll see, outside of a handful of 'Admin' users who need to see everyone.
For these same Admin users, I need to add an option to select all salespeople. I tried simply using the "allow multiple values" but it doesn't like that and gives me an error: Incorrect syntax near ','. even when I take out the WHERE clause in my query of sp.salesperson_name = #salesperson. Anyway, what's my best course of action for adding an All option for this report?
EDIT: I just realized I might need to add the main dataset query for context:
SELECT sp.SalesPerson_Name
,c.Calendar_Month_Name
,sum(isnull(sales_qty, 0)) AS 'total gallons'
,sum(isnull(Ext_Retail_Base, 0) + isnull(Ext_Retail_Freight, 0)) - sum(isnull(Ext_Cost_Base, 0) + isnull(Ext_Cost_Freight, 0)) 'Sales GM'
,(sum(isnull(Ext_Retail_Base, 0) + isnull(Ext_Retail_Freight, 0)) - sum(isnull(Ext_Cost_Base, 0) + isnull(Ext_Cost_Freight, 0))) / sum(isnull(sales_qty, 0)) 'cpg'
FROM Fuel_Wholesale_Sales_Fact fwsf
JOIN calendar c ON fwsf.Calendar_key = c.calendar_key
JOIN Salesperson sp ON sp.SalesPerson_Key = fwsf.Salesperson_Key
JOIN Customer cu ON fwsf.Customer_Key = cu.Customer_Key
WHERE sp.SalesPerson_Name = #SalesPerson
AND c.Day_Date BETWEEN #Start
AND #End
and isnull(fwsf.sales_qty,0) != 0
GROUP BY sp.SalesPerson_Name, c.Calendar_Month_Name
UPDATE 1: I attempted to use the STRING_SPLIT function, but even using the simple example from Microsoft's website (https://learn.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql?view=sql-server-2016) resulted in me getting an error: Invalid object name 'STRING_SPLIT'. I am running SQL 2016. Thoughts?
Figured it out. Compatibility level issue. My DB is set on 110. I may need to ask some questions if there's a reason it's set on that as opposed to the default 130.
UPDATE 2: I finally sorted out what I needed. I just used the "Allow multiple values" option in the Parameter Properties. It wasn't working before because I foolishly did not use an IN operator nor surround the parameter with parentheses.
So I had the following: select salesperson where id = #salesperson
When what I needed was: select salesperson where id in (#salesperson) because Report Builder will pass a string of parameter values as 'Bob','Mary','John' which require that they be put inside the parentheses. This is for others who come looking for answers.

Conditionally include a line in a T-SQL WHERE clause

Honestly, I've gone over other questions posted here that mention conditional where clauses and I'm not seeing any answers that seem to work for my situation. If one does, please point me to it!
In a stored procedure called by an SSRS report, the user can select one of two values in a dropdown - say "Yes" or "No" and that goes into the variable #color.
In the WHERE clause of the sproc I need to filter differently depending on the user's selection.
So, if #color = 'Yes', then I need to have a line in the WHERE clause that reads something like tb1.somecolumn = 'BLUE'. But if #color = 'No' then I don't need that line in the where clause at all (tb1.somecolumn can be any value).
How do I conditionally include a line in the WHERE clause?
Include the check for #color in the WHERE as follows.
WHERE (#color = 'No')
OR (#color = 'Yes' AND tb1.somecolumn = 'BLUE')
Explanation:
If the value of #color is 'No', then all rows are returned.
If the value of #color is 'Yes', then only the 'BLUE' rows are returned.
Try following condition
WHERE (#color = 'Yes' AND tb1.somecolumn = 'BLUE')
OR (#color = 'No' AND tb1.somecolumn = tb1.somecolumn)

Determine if T-SQL select statement returns any rows

I am using Microsoft SQL Server 2012. I want to set a boolean value in a stored procedure. I want to set the value to true if a certain select query returns more than zero rows.
Declare #ShowQuotingTool as bit
(select count(*) from tblAgentsLicensedState where AgentCode = '016893' and StateCode in ('AZ','GA','IA', 'TN', 'SC', 'KS', 'MI' ,'NC', 'UT')) > 0;
How do I set #ShowQuotingTool to true or false based on the select query? I get the error Incorrect syntax near ">".
You can just assign #ShowQuotingTool to the count query. This is based on the fact that any count > 0 will set the bit variable #ShowQuotingTool to true and count = 0 will set it to false
Declare #ShowQuotingTool as bit
SELECT #ShowQuotingTool = (select count(*) from tblAgentsLicensedState where AgentCode = '016893' and StateCode in ('AZ','GA','IA', 'TN', 'SC', 'KS', 'MI' ,'NC', 'UT'))
You should preferably use EXISTS which would have better performance than COUNT query above.
IF EXISTS(select * from tblAgentsLicensedState where AgentCode = '016893' and StateCode in ('AZ','GA','IA', 'TN', 'SC', 'KS', 'MI' ,'NC', 'UT'))
SET #ShowQuotingTool = 1
ELSE
SET #ShowQuotingTool = 0
Good Day,
Please post DDL+DML if this is not what you are looking for. In any case please remember next time to post DDL+DML (queries to create the relevant tables and to insert some sample data, in order to give us the tools to reproduce the issue).
Back to your question:
If you have an SP that return the result of select query (or any DML query), that mean that you need this query to execute as it is. The idea of using COUNT function on the results mean that you execute another query, which is not logic action to do, since we already have the information in the headers of the result.
If you notice, by default, every time that you execute a query in the SSMS for example you get the information regarding number of rows: "(x row(s) affected)". There is no need to use another query.
If you are using external application that you develop, and your SP do not use "SET NOCOUNT ON", then this information coming back from the server :-)
You can see examples here:
https://msdn.microsoft.com/en-us/library/ms171921.aspx?f=255&MSPPError=-2147217396

Filtering by ALL or by selected attribute

Excuse my language or SQL/Reporting wording
I am generating a report using Reporting Services where I have 2 drop down lists in order to show only by period and by category. I want it so if I select and I am shown all entries and if selected from any of the 2 drop downs then filter by those selections. I have a stored procedure which states the following on it's WHERE clause:
WHERE (dbo.PERIOD_LIST.PERIOD_DESC = #period) OR (dbo.CATEGORY.CATEGORY_DESC = #category)
However I cannot get this to work on Reporting Services/Visual Studio. I am shown ALL the entries instead of the filtered ones. I initialize #period and #category as NULL. So how can I make it so the report shows all rows when both attributes are null and still be able to filter by each or both of them?
How can I achieve this?
Edit: I used the suggestion Filip Popović gave me. If you're having this problem modify your prepared statement and make sure you refresh fields on your data sets since there's additional clauses on your prepared statement!
Note that in SQL, NULL = NULL is never evaluated to true. You can take it as NULL is not nothing it is something but unspecified. And You can't compare two unspecified values. You have to test COL1 IS NULL to get true if column has null value.
Try this:
WHERE ((dbo.PERIOD_LIST.PERIOD_DESC = #period) OR (#period IS NULL))
AND ((dbo.CATEGORY.CATEGORY_DESC = #category) OR (#category IS NULL))
Check the parameter for NULL as part of the condition:
WHERE ((#period IS NULL) OR (dbo.PERIOD_LIST.PERIOD_DESC = #period))
AND ((#category IS NULL) OR (dbo.CATEGORY.CATEGORY_DESC = #category))

SQL Server functional equivalent to PostgreSQL "in"

In postgres you can do a comparison against multiple items like so:
SELECT 'test' IN ('not','in','here');
Which is the same as doing:
SELECT ('test' = 'not' OR 'test' = 'in' OR 'test' = 'here');
Is there a functional equivalent for SQL Server ?
It is supported, but you will need to put the expression somewhere that accepts a boolean expression. For example, in a case statement:
select case when 'test' in ('not','in','here') then 1 else 0 end
-----------
0
(1 row(s) affected)
Or a where clause:
select * from T where C in (1,3,5,7,9)
this should give similar results in all recent versions of MSSQL. You could also write a scalar function to shorten things up a bit.
select case
when 'test' IN ('not', 'in', 'here') then 1
else 0
end;
This will give 1 if 'test' is in the comparison set 1 or more times, or 0 if it isn't.
SELECT CAST(COUNT(*) AS BIT) as IsItHere WHERE 'test' IN('not','in','here')
Note that the cast isn't strictly necessary, but may be useful if this is called from another language... It should then resolve to a boolean.
EDIT: According to MSSQL Query planner, this is executed ~4 times faster then the CASE method. YMMV.

Resources