WHERE [Expression] = TRUE/FALSE in SQL Server - sql

I have a situation where I'm trying to filter people that have credits or not. Here's an example Dapper query for reference:
var sql = #"
SELECT *
FROM Person
WHERE (Person.Credits > 0) = #hasCredits";
Connection.Query(sql, new { hasCredits });
I was pretty sure Postgres allows you to do this, hence my surprise when on SQL Server this failed with Incorrect syntax near '='.
With the sample data below, I would expect the query to return the Person with the ID of 1 when hasCredits is FALSE and the Person with the ID of 2 when hasCredits is TRUE.
INSERT INTO Person (PersonId, Credits) VALUES (1, 0), (2, 0);
In SQL Server Is there a way to evaluate whether an expression evaluates to true or false?
I've considered the following (horrible looking) options, but was hoping there was a more elegant solution:
"WHERE (Person.Credits " + (hasCredits ? ">" : "=") + " 0)"
"WHERE (#hasCredits = 1 AND Person.Credits > 0) OR (#hasCredits = 0 AND Person.Credits = 0)"

Considering that when Has credits radio button is selected #hasCredits variable will have 1 else when Doesn't have credits is selected #hasCredits variable will have 0 else #hasCredits variable will be null
SELECT *
FROM Person
WHERE (Person.Credits > 0 and #hasCredits=1) or --Has credits
(Person.Credits <1 and #hasCredits=0) or --Doesn't have credits
(#hasCredits IS NULL) --Don't care

You question was quite plain and the answer is super easy!
case when Person.Credit > 0 then 1 else 0 end = #hasCredits

Related

Oracle PLSQL using a dynamic variable in a where clause

For testing in Toad, I have the following code
select ...
from ...
where term_code = :termcode AND
(
case
when :theSubject is not null then SUBJ_CODE = :theSubject
else 1 = 1
end
)
AND ptrm_code <> 8
In short: If theSubject is not entered (is null) I want to display all the courses, otherwise I want to display only those where subject_code is the same as the one entered in the variable window in Toad.
But I get an error:
[Error] Execution (77: 68): ORA-00905: missing keyword
in here:
when :theCourse is not null then sect.SSBSECT_SUBJ_CODE = theCourse
You can use boolean logic:
where
term_code = :termcode
and (:theSubject is null or subj_code = :theSubject)

SELECT WHERE {column} = CASE WHEN {expression} THEN NULL

I have this code which is part of a stored procedure
INSERT INTO #TempTable
/* A few subqueries, about 100 lines */
WHERE (cartera.ClaSucursal = #pIdSucursal OR #pIdSucursal = -1)
AND (cartera.ClaAsesorActual =
CASE
WHEN #pIdAsesor > 0 THEN #pIdAsesor
WHEN #pIdAsesor = 0 THEN NULL
END
OR #pIdAsesor = -1)
/* Rest of my code, about 200 lines */
SELECT * FROM #TempTable
Basically I have a parameter called #pIdAsesor and depending on its value there can be three possible outcomes.
#pIdAsesor = -1 which brings me all entries regardless of the Id value
#pIdAsesor = sumId which brings me all entries with given Id
#pIdAsesor = 0 which brings me all entries with NULL as the Id
Outcomes 1 and 2 work flawlessly, but scenario 3 doesn't bring back results.
null isn't a value - it's the lack thereof. null is never equal to anything (not even another null), but you can check for it explicitly with the is operator.
You could ditch the case expression and construct this logic with a series of ors:
AND ((#pIdAsesor = -1) OR
(#PIdAsesor = 0 AND cartera.ClaAsesorActual IS NULL) OR
(#pIdAsesor = cartera.ClaAsesorActual))
You can't use = for null in case when result comes null but = null doesn't work. You have to use is null.

MSSQL 2008: Problems with the 'Case' - statement

I'm having some troubles finding a solution to my SQL-Problem. I've tried google but so far my search didn't give me any statisfactory results.
I have an SSRS report with two parameters:
#SupplierId NVARCHAR (May contain NULL)
#EmployeeId NVARCHAR (May contain NULL)
My original query retrieved all the employees who came in service during the last year:
SELECT Name, Surname from dbo.Employee Where Employee.DateInService > DATEADD(year,-1,GETDATE())
Right now i want to add those parameters to the query using the following logic.
Remark this is pseudo SQL:
SELECT
...
FROM ...
WHERE Employee.DateInService > DATEADD(year,-1,GETDATE()) AND
IF (LEN(RTRIM(#SupplierId)) = 0 Or #SupplierID IS NULL ) THEN
dbo.Employee.EmployeeId = #EmployeeId
Else
dbo.Employee.SupplierId = #SupplierId
My search sofar led me to the Case statement. I made a query which contains an syntax error (obviously). My base query:
SELECT
...
FROM ...
WHERE Employee.DateInService > DATEADD(year,-1,GETDATE()) AND
CASE WHEN (LEN(RTRIM(#SupplierId)) = 0) THEN
dbo.Employee.EmployeeId = #EmployeeId
Else
dbo.Employee.SupplierId = #SupplierId
Error: Syntax error near '='.
Question 1: Why does he give an error near the '='?
Question 2: How do i correctly implement the following:
CASE WHEN (LEN(RTRIM(#SupplierId)) = 0 "Or #SupplierId is null" ) THEN
Instead of
CASE WHEN (LEN(RTRIM(#SupplierId)) = 0) Then dbo.Employee.EmployeeId = #EmployeeId
WHEN (#SupplierId IS NULL) Then dbo.Employee.EmployeeId = #EmployeeId
ELSE dbo.Employee.EmployeeId = #EmployeeId END
Note: if i've missed a post during my google searches, please don't hesitate to point it out.
Thanks for your help
You can't change the actual query predicate like that with CASE - there are 2 distinct queries depending on the value of #SupplierId. You can conditionally apply the filter as follows (I've assumed the #SupplierId = null flow is the same as the whitespace branch:
SELECT
...
FROM ...
WHERE Employee.DateInService > DATEADD(year,-1,GETDATE())
AND
(
(dbo.Employee.EmployeeId = #EmployeeId
AND (LEN(RTRIM(#SupplierId)) = 0 OR #SupplierId IS NULL))
OR
(dbo.Employee.SupplierId = #SupplierId AND LEN(RTRIM(#SupplierId)) > 0)
)
Although this can be prone to query plan sniffing related performance issues, in which case you might need to consider an alternative approach, e.g. using parameterized dynamic sql to build up and execute the sql, as there are 2 distinct process flows through the query.
Edit
As per Ypercube's comment above, in order to provide the boolean result needed for the predicate, if you can find a hack workaround is to find a way to project a COMMON scalar from each of the CASE .. WHEN row and then do a comparison of the scalar. In the example below, projecting a yes / no flag.
SELECT * FROM dbo.Employee
WHERE
CASE
WHEN (LEN(RTRIM(#SupplierId)) = 0 OR #SupplierId IS NULL)
THEN CASE WHEN dbo.Employee.EmployeeId = #EmployeeId THEN 1 ELSE 0 END
ELSE CASE WHEN dbo.Employee.SupplierId = #SupplierId THEN 1 ELSE 0 END
END = 1;
But the big problem with this approach is performance - the above will require a full scan to determine the results.

T-SQL and decision making constructs

Please help me with the syntax of this query. It doesn't compile. It says there's a syntax error near the keyword END.
Obviously, I've got these BEGINs and ENDS mixed up.
I am using Microsoft SQL Server 2008 R2. I am not sure of the syntax of these BEGINS and ENDs.
Please don't mind the condition 1 = 0. That's something that will be replaced with a proper predicate later.
IF EXISTS (SELECT * FROM StringCategory WHERE ResourceKeyId = 18134 AND CategoryId = 0)
BEGIN
UPDATE StringCategory
SET CategoryId = 0
WHERE ResourceKeyId = 18134
END
ELSE
BEGIN
IF 1 = 0
BEGIN
DELETE FROM StringCategory WHERE ResourceKeyId = 18134
END
ELSE
BEGIN
INSERT INTO StringCategory
VALUES(18134, 0)
END
END
END
Your last END is an extra. You can think of the BEGINs and ENDs like { and } in C# for the IF constructs (They serve to mark the beginning and end of the block to be executed in the IF/ELSE statement).
Here is a much simpler way to do what you appear to be attempting.
insert into StringCategory
(ResourceKey, CategoryId)
select 18134, 0
where not exists (
SELECT *
FROM StringCategory
WHERE ResourceKeyId = 18134
AND CategoryId = 0)

Nhibernate Criteria Conditional Where

Im working on a NHibernate criteria wich i graduatly builds upp depending on input parameters.
I got some problem with the postal section of these paramters.
Since we got a 5 number digit zipcodes the input parameter is a int, but since we in database also accept foreign zipcodes the database saves it as string.
What im trying to replicate in NHibernate Criteria/Criterion is the following where clause.
WHERE
11182 <=
(case when this_.SendInformation = 0 AND dbo.IsInteger(this_.Zipcode) = 1 then
CAST(REPLACE(this_.Zipcode, ' ', '') AS int)
when this_.SendInformation = 1 AND dbo.IsInteger(this_.WorkZipcode) = 1 then
CAST(REPLACE(this_.WorkZipcode, ' ', '') AS int)
when this_.SendInformation = 2 AND dbo.IsInteger(this_.InvoiceZipcode) = 1 then
CAST(REPLACE(this_.InvoiceZipcode, ' ', '') AS int)
else
NULL
end)
What we do is to check where the member contact (this_) has preferenced to get information sent to, then we check the input zipcode as integer against three different columns depending on if the column is convertable to int (IsInteger(expr) function) if column is not convertable we mark the side as NULL
in this case we just check if the zipcode is >= input parameter (reversed in sql code since paramter is first), the goal is to do a between (2 clauses wrapped with 'AND' statement), >= or <=.
UPDATE
Got a hint of success.
Projections.SqlProjection("(CASE when SendInformation = 0 AND dbo.IsInteger(Zipcode) = 1 then CAST(REPLACE(Zipcode, ' ', '') AS int) when SendInformation = 1 AND dbo.IsInteger(WorkZipcode) = 1 then CAST(REPLACE(WorkZipcode, ' ', '') AS int) when SendInformation = 2 AND dbo.IsInteger(InvoiceZipcode) = 1 then CAST(REPLACE(InvoiceZipcode, ' ', '') AS int) else NULL END)"
, new[] { "SendInformation", "Zipcode", "WorkZipcode", "InvoiceZipcode" },
new[] { NHibernateUtil.Int32, NHibernateUtil.String, NHibernateUtil.String, NHibernateUtil.String });
Throw my whole clause in a Projections.SqlProjection, however when i run my code some of my projection is cut (" AS int) else NULL END)" is cut from the end) and makes the sql corrupt.
Is there some kind of limit on this ?
Got it working yesterday.
Projections.SqlProjection worked, however if you don't name the projection as a column it some how cuts some of the TSQL code.
(Case
when x = 1 then 'bla'
when x = 2 then 'bla_bla'
else NULL
END) as foo
when using the last part (as foo) and naming the entire case syntax it works and dont cut anything.
However i dont know why but i could not manage to use the aliases from the other part of the criteria.