Can TSQL convert from boolean to BIT - sql-server

I was creating a function that returns BIT, I tried to "Return #count < 1", that did not work, how to convert boolean to BIT in TSQL.
Thanks

You will need to have a conditional statement:
if #count < 1
return 1
else
return 0
Or you could use a CASE statement:
case
when #count < 1 then return 1
else return 0
end

Can count ever be negative? And count should be integer
So what you want is "1 if #COUNT = zero, zero otherwise"
RETURN 1 - SIGN(#COUNT)

Or a simple transmogrification of Shark's answer:
return case
when #Count < 1 then 1
else 0
end
Note that a CASE may have as many WHEN clauses as you need.
Trivia: Curiously, a BIT can be set to 'TRUE' or 'FALSE'. Yeah, quoted strings. Go figure.

Related

want to convert negative number to positive

I have a below query which I have used this in a procedure and want to convert one number into positive as right now it is negative.
UPDATE SHIPMENT
SET TOTAL_SHIP_UNIT_COUNT = (
CASE
WHEN V_SHIP_UNIT_COUNT > v_diff_cost
THEN V_SHIP_UNIT_COUNT - v_diff_cost
ELSE v_diff_cost - V_SHIP_UNIT_COUNT
END)
WHERE SHIPMENT_GID = v_shipment_id;
COMMIT;
in this query v_diff_cost value is negative so while performing ( V_SHIP_UNIT_COUNT - v_diff_cost) action it is adding both the values so if I will convert v_diff_cost value to positive then while subtracting it will give me the right result.
Suppose V_SHIP_UNIT_COUNT value is 33 and v_diff_cost value is -10 then in this case it should perform the action as 33-10 = 23 but it is doing as 33-(-10)= 43 and this should not happen.
kindly help me out.
Thanks
Use ABS() function,
MSDN : A mathematical function that returns the absolute (positive) value of the specified numeric expression.
UPDATE SHIPMENT
SET TOTAL_SHIP_UNIT_COUNT = (
CASE
WHEN V_SHIP_UNIT_COUNT > v_diff_cost
THEN V_SHIP_UNIT_COUNT - ABS(v_diff_cost)
ELSE ABS(v_diff_cost) - V_SHIP_UNIT_COUNT
END)
WHERE SHIPMENT_GID = v_shipment_id;
COMMIT;
Try this code:
UPDATE SHIPMENT
SET TOTAL_SHIP_UNIT_COUNT = (
CASE
WHEN V_SHIP_UNIT_COUNT > v_diff_cost
THEN V_SHIP_UNIT_COUNT - abs(v_diff_cost)
ELSE v_diff_cost - abs(V_SHIP_UNIT_COUNT)
END)
WHERE SHIPMENT_GID = v_shipment_id;
COMMIT;
Try this:
UPDATE SHIPMENT
SET TOTAL_SHIP_UNIT_COUNT = ABS(V_SHIP_UNIT_COUNT - ABS(v_diff_cost))
WHERE SHIPMENT_GID = v_shipment_id;

Alternative query for calculating percentage

In SQL Server for calculating percentage I have a function like below:
CREATE FUNCTION [dbo].[fuGetPercentage] ( #part FLOAT, #total FLOAT )
RETURNS FLOAT
AS
BEGIN
DECLARE #Result FLOAT = 0, #Cent FLOAT = 100;
IF (isnull(#total, 0) != 0)
SET #Result = isnull(#part, 0) * #Cent / #total;
RETURN #Result
END
I wonder that is there any better alternative for that, with same checks and a better calculating percentage like below:
SELECT (CASE ISNULL(total, 0)
WHEN 0 THEN 0
ELSE ISNULL(part, 0) * 100 / total
END) as percentage
I want to use it directly after SELECT like above.
There is one issue with using functions such as ISNULL. The query will not use indexes in that case. If the beauty of the code isn't in the first place then you can do something like that:
SELECT
CASE WHEN total * part <> 0 /* will check that both total and part are not null and != 0*/
THEN part * 100 / total
ELSE 0
END AS percentage;
I use #DmitrijKultasev answer but now, I found that it has two problems:
Error on conversion because of the overflow of result of multiply.
Performance problem; because of that math multiply and its conversion.
So I change it to this:
SELECT
CASE
WHEN total <> 0 AND part <> 0 THEN -- This will return 0 for Null values
part * 100 / total
ELSE
0
END AS percentage;

AND/OR based on variable value in stored procedures

I would like to use AND/OR between the conditions in a stored procedure, and the decision is dependent on the parameter value whether it was 0 (AND) or 1 (OR)
Can anyone help me with this please, i guess this is an easy thing to do but i can't seem to figure it out. Thanks
The easiest way (on first glance) would be to concatenate the query string using dynamic SQL, but dynamic SQL has its issues.
See The Curse and Blessings of Dynamic SQL for an in-depth explanation.
So I would try to avoid dynamic SQL, which is no big deal if your queries are not too complex.
The easiest way is just to fire two different queries depending on the parameter value:
CREATE PROCEDURE spTest
#AndOr bit
AS
BEGIN
if #AndOr = 0 begin
select * from YourTable where foo = 1 and bar = 2
end
else begin
select * from YourTable where foo = 1 or bar = 2
end
END
This is of course an example with a very simple query.
If you have lots of queries, or if your queries are very complex, this might not be the best solution because it forces you to duplicate all queries...but as always, it depends :-)
You can implement your logic on a CASE statement. Something like this:
CREATE PROCEDURE dbo.MySP #OrAnd BIT
AS
BEGIN
SELECT *
FROM MyTable
WHERE CASE WHEN Condition1 AND Condition2 AND #OrAnd = 0 THEN 1
WHEN (Condition1 OR Condition2) AND #OrAnd = 1 THEN 1 ELSE 0 END = 1
END
If you convert the simple conditions' boolean results into numeric ones (0 or 1), you will be able to use your parameter in the following way:
(
(CASE WHEN condition1 THEN 1 ELSE 0 END ^ #AndOr)
&
(CASE WHEN condition2 THEN 1 ELSE 0 END ^ #AndOr)
) ^ #AndOr = 1
Here #AndOr is your parameter, ^ is the Transact-SQL bitwise exclusive OR operator, & stands for the bitwise AND in Transact-SQL, and the CASE expressions are used to convert the boolean results into 0 or 1.
If #AndOr = 0 (which means we want AND between the conditions), the above expression effectively boils down to this:
case1 & case2 = 1
because X XOR 0 yields X and so neither individual values of case1 and case2 nor the entire result of the & operator are not affected by the ^ operators. So, when #AndOr is 0, the result of the original expression would be equivalent to the result of condition1 AND condition2.
Now, if #AndOr = 1 (i.e. OR), then every ^ operator in the expression returns the inverted value of its left operand, in other words, negates the left operand, since 1 XOR 1 = 0 and 0 XOR 1 = 1. Therefore, the original expression would essentially be equivalent to the following:
¬ (¬ case1 & ¬ case2) = 1
where ¬ means negation. Or, converting it back to the booleans, it would be this:
NOT (NOT condition1 AND NOT condition2)
According to one of De Morgan's laws,
(NOT A) AND (NOT B) = NOT (A OR B)
Applying it to the above condition, we get:
NOT (NOT condition1 AND NOT condition2) = NOT (NOT (condition1 OR condition2)) =
= condition1 OR condition2
So, when #AndOr is 1, the expression given in the beginning of my answer is equivalent to condition1 OR condition2. Thus, it works like expected based on the value of #AndOr.
Having the input parameter you can use a IF clause to make different selects.
If input parameter = 0 make the AND conditions, otherwise make the OR conditions.
I can't see any particular elegant way to do it. So here's the straightforward approach
create function myfun (#parm1 int, #parm2 int, #andor int) returns int
begin
if (#andor = 0 AND #parm1 = 99 AND #parm2 = 99) return 1
else if (#andor = 1 AND (#parm1 = 99 OR #parm2 = 99)) return 1
return 0
end
go
select dbo.myfun(99,98,0) -- AND condition should return 0
select dbo.myfun(99,98,1) -- OR condition should return 1
select dbo.myfun(98,98,0) -- AND condition should return 0
select dbo.myfun(98,98,1) -- OR condition shoujld return 0

Check Constraints and Case Statement

I need help with this check constraint, I get the following error message: "Msg 102, Level 15, State 1, Line 14
Incorrect syntax near '='."
Or maybe the question I should ask is if this is possible using a check constraint
What I am trying to achieve is: If InformationRestricted is True, InformationNotRestricted cannot be true and InformationRestrictedFromLevel1, InformationRestrictedFromLevel2, InformationRestrictedFromLevel3, InformationRestrictedFromLevel4, InformationRestrictedFromLevel5 cannot be true
I am not trying to assign values to the columns, just trying to ensure the values of the columns = 0 (i.e. false) if InformationRestricted is True
Here is the script:
CREATE TABLE EmployeeData
(FirstName varchar(50),
Last Name varchar(50),
Age int,
Address varchar(100),
InformationRestricted bit,
InformationNotRestricted bit,
InformationRestrictedFromLevel1 bit,
InformationRestrictedFromLevel2 bit
InformationRestrictedFromLevel3 bit
InformationRestrictedFromLevel4 bit
InformationRestrictedFromLevel5 bit);
ALTER TABLE EmployeeData ADD CONSTRAINT ck_EmployeeData
CHECK (CASE WHEN InformationRestricted = 1 THEN InformationNotRestricted = 0 --InformationRestricted is true, InformationNotRestricted is false
AND( InformationRestrictedFromLevel1 = 0 --is false
OR InformationRestrictedFromLevel2 = 0 --is false
OR InformationRestrictedFromLevel3 = 0 --is false
OR InformationRestrictedFromLevel4 = 0 --is false
OR InformationRestrictedFromLevel5 = 0)); --is false
A CASE expression is something that returns a value of a particular data type (the type to be determined by the various datatypes of each THEN clause).
SQL Server doesn't have a boolean data type, so you can't return the result of a comparison operation.
Try adding additional comparisons into WHEN clauses, and having the THENs return either 1 or 0, if you want to allow or disallow the outcome (respectively). Then compare the overall result to 1.
I can't parse out the sense of your condition entirely, but something like:
CHECK(CASE WHEN InformationRestricted = 1 THEN
CASE WHEN InformationNotRestricted = 0 AND
(InformationRestrictedFromLevel1 = 0 --is false
OR InformationRestrictedFromLevel2 = 0 --is false
OR InformationRestrictedFromLevel3 = 0 --is false
OR InformationRestrictedFromLevel4 = 0 --is false
OR InformationRestrictedFromLevel5 = 0)
THEN 1
ELSE 0
END
--Other conditions?
END = 1)
My confusion is I'd have though you'd want to check that one and only one of the InformationRestrictedFromXXX columns would be one. In fact, from the general description, (without knowing more about your problem domain), I'd have probably just created a column InformationRestrictionLevel, of type int, with 0 meaning unrestricted, and higher values indicating the level it's restricted from.
Looks like you're not closing the case with end. The basic format of a check constraint using case is:
check(case when <condition> then 1 else 0 end = 1)
If you nest multiple cases, be sure to match the number of cases with the number of ends:
check
(
1 =
case
when <condition> then
case
when <condition> then 1
else 0
end
else 0
end
)
Formatting all elements of the same case with the same indentation can be a big help.

Microsoft SQL: CASE WHEN vs ISNULL/NULLIF

Besides readability is there any significant benifit to using a CASE WHEN statement vs ISNULL/NULLIF when guarding against a divide by 0 error in SQL?
CASE WHEN (BeginningQuantity + BAdjustedQuantity)=0 THEN 0
ELSE EndingQuantity/(BeginningQuantity + BAdjustedQuantity) END
vs
ISNULL((EndingQuantity)/NULLIF(BeginningQuantity + BAdjustedQuantity,0),0)
Remember that NULL is different from 0. So the two code snippets in the question can return different results for the same input.
For example, if BeginningQuantity is NULL, the first expression evaluates to NULL:
CASE WHEN (NULL + ?)=0 THEN 0 ELSE ?/(NULL + ?) END
Now (NULL + ?) equals NULL, and NULL=0 is false, so the ELSE clause is evaluated, giving ?/(NULL+?), which results in NULL. However, the second expression becomes:
ISNULL((?)/NULLIF(NULL + ?,0),0)
Here NULL+? becomes NULL, and because NULL is not equal to 0, the NULLIF returns the first expression, which is NULL. The outer ISNULL catches this and returns 0.
So, make up your mind: are you guarding against divison by zero, or divison by NULL? ;-)
In your example I think the performance is negligible. But in other cases, depending on the complexity of your divisor, the answer is 'it depends'.
Here is an interesting blog on the topic:
For readability, I like the Case/When.
In my opinion, using Isnull/Nullif is faster than using Case When. I rather the isnull/nullif.
I would use the ISNULL, but try to format it so it shows the meaning better:
SELECT
x.zzz
,x.yyyy
,ISNULL(
EndingQuantity / NULLIF(BeginningQuantity+BAdjustedQuantity,0)
,0)
,x.aaa
FROM xxxx...
CASE WHEN (coalesce(BeginningQuantity,0) + coalesce(BAdjustedQuantity,0))=0 THEN 0 ELSE coalesce(EndingQuantity,0)/(coalesce(BeginningQuantity,0) + coalesce(BAdjustedQuantity,0)) END
your best option imho
Sorry, here is the little more simplify upbuilded sql query.
SELECT
(ISNULL([k1],0) + ISNULL([k2],0)) /
CASE WHEN (
(
CASE WHEN [k1] IS NOT NULL THEN 1 ELSE 0 END +
CASE WHEN [k2] IS NOT NULL THEN 1 ELSE 0 END
) > 0 )
THEN
(
CASE WHEN [k1] IS NOT NULL THEN 1 ELSE 0 END +
CASE WHEN [k2] IS NOT NULL THEN 1 ELSE 0 END
)
ELSE 1 END
FROM dbo.[Table]

Resources