Role of precedence in expression evaluation in C - c

If y is of integer type, then the expressions:
3*(y-8)/9
and
(y-8)/9*3
Will yield different result always or is it possible for them to yield same result?
What does it depend on?
Explanation with an example will be helpful.

May yield different or same result, it is depend on 'y' value. The operations will be carried from left to right.
Ex: for y=11:
3*(y-8)/9: 1 (y-8)/9*3: 0
for y = 10
3*(y-8)/9: 0 (y-8)/9*3: 0

Related

#Error even after using IIF to avoid division by Zero in Expression

Ran into this issue in SSRS and am hoping for some assistance.
Simply want to return a 0 or 0.00 in a Total textbox when there is a zero in textbox 167 or 168. I have ISNULL covered in the dataset for both fields. Textbox is formatted Currency in Report. I'm getting results if 167 and 168 are both not 0, but #Error if they are. Any thoughts?
=IIF((ReportItems!Textbox167.Value > 0) AND (ReportItems!Textbox168.Value > 0)
,CDEC(ReportItems!Textbox173.Value / ReportItems!Textbox167.Value) -
CDEC(ReportItems!Textbox176.Value / ReportItems!Textbox168.Value), 0)
Thanks!
IIF evaluates both possibilities even IF it doesn't need to - resulting in your error.
The theory is that you want the expression to evaluate normally if the denominator is not zero, but use 0 / 1 if the denominator is zero.
Your expression would look like:
=IIF(ReportItems!Textbox167.Value = 0, 0, CDEC(ReportItems!Textbox173.Value))
/
IIF(ReportItems!Textbox167.Value = 0, 1, CDEC(ReportItems!Textbox167.Value))
-
IIF(ReportItems!Textbox168.Value = 0, 0, CDEC(ReportItems!Textbox176.Value))
/
IIF(ReportItems!Textbox168.Value = 0, 1, CDEC(ReportItems!Textbox168.Value))
The problem here is that IIF is not like the ternary operator in C# as an example, where the conditional expressions are only evaluated depending on the state of the boolean expression.
In other words, this:
=IIF(a, b, c)
Will first evaluate a, b, and c, before IIF is evaluated. The damage has already done by the time IIF gets to look at the values.
Instead you should bake the dividend into an IIF expression to ensure you will never get the 0 in the divide expression at all, instead of trying to avoid using the expression.

Why is arithmetic + preferred over textual one?

If I run
select '1' + '1'
the result is 11, since I have added a text to another one.
If I run
select 1 + '1'
the result is 2. I assume the arithmetic operator is chosen over the concatenator because of the type of the first operand. If my reasoning was valid, then the result of
select '1' + 1
would be 11. But instead, it is 2. So, it seems that the operator + is tried to be used as an arithmetic operator and if neither of the operands is arithmetic, then goes on to the next operator. If that is true, that would explain why did I get the error of
Conversion failed when converting the varchar value 'customer_' to data type
int.
instead of customer_<somenumber> when I ran a select and had 'customer_' + <somenumber>.
Long story short: I think I observed that arithmetic + is preferred over its meaning of concatenation at SQL Server. Am I right? If so, is there an official reason of this behavior?
What you're running into is a matter of data type precedence. SQL Server looks to character data types after numerics. So regardless of the ordering of your operands (1 + '1' vs '1' + 1), it's attempting to convert your types to numerics, and succeeding.
The same happens with your second attempt - it's trying to convert the string customer_ to an integer because you're using an arithmetic operator along with an integer.
Yes, the precedence is arithmetic first when compared to concatenation.
https://msdn.microsoft.com/en-us/library/ms190276.aspx
Your error, as you know, is because the it won't implicitly attempt to convert INT to VARCHAR

Why is '-' equal to 0 (zero) in SQL?

When you run the following query in SQL Management studio the result will be 1.
SELECT
CASE WHEN '-' = 0 THEN
1
ELSE
0
END
That scares me a bit, because I have to check for 0 value a numerous number of times and it seems it is vulnerable for being equal to value '-'.
You're looking at it the wrong way around.
'-' is a string, so it will get implicitly casted to an integer value when comparing it with an integer:
select cast('-' as int) -- outputs 0
To make sure that you are actually comparing a value to the string '0', make your comparison like this instead:
select case when '-' = '0' then 1 else 0 end
In general, you're asking for trouble when you're comparing values of different data types, since implicit conversions happen behind the scene - so avoid it at all costs.

Divide in query and error Arithmetic overflow error converting expression to data type int

I want to write this query (all of the fields are int):
select SUM(Service.discount+((Service.price*Factor.discount)/(Factor.amount-Factor.discount)))
But sometimes I get this error:
Arithmetic overflow error converting expression to data type int.
Other times I get this error:
Divide by zero error encountered.
How can I rewrite this query to avoid these errors?
//I Use this but agan overflow
select case when(Factor.amount-Factor.discount)<>0 then
Service.discount+((Service.price*Factor.discount)/(Factor.amount-Factor.discount))
else
Service.discount
end
from Factor inner join Service on Factor.code=Service.factorCode
Arithmetic overflow: don't use sum at all, take SUM off and take the brackets off either end.
Divide by zero: see Jonny's answer (I think he means //something as in whatever you want to do when factor.amount-factor.discount is zero....)
so maybe:
select case when discount2 <> 0 then discount+((price*discount)/(discount2)) else
discount+(price*discount) end FROM SERVICE
SELECT CASE
WHEN (Factor.amount-Factor.discount) <> 0
THEN
CONVERT(FLOAT,Service.discount+((Service.price*Factor.discount)/(Factor.amount-
Factor.discount)))
ELSE
Service.discount
END
FROM Factor INNER JOIN Service ON Factor.code=Service.factorCode
It might be better to decide how many decimal places you want to see:
CONVERT(decimal(10,2),Service.discount+((Service.price*Factor.discount)/(Factor.amount-Factor.discount)))
select
CASE (Factor.amount-Factor.discount)
WHEN 0
-- choose the result when Factor.amount-Factor.discount = 0 and replace this line
ELSE
SUM(Service.discount+((Service.price*Factor.discount)/
(Factor.amount-Factor.discount)))
END
...

Postgres NOT in array

I'm using Postgres' native array type, and trying to find the records where the ID is not in the array recipient IDs.
I can find where they are IN:
SELECT COUNT(*) FROM messages WHERE (3 = ANY (recipient_ids))
But this doesn't work:
SELECT COUNT(*) FROM messages WHERE (3 != ANY (recipient_ids))
SELECT COUNT(*) FROM messages WHERE (3 = NOT ANY (recipient_ids))
What's the right way to test for this condition?
SELECT COUNT(*) FROM "messages" WHERE NOT (3 = ANY (recipient_ids))
You can always negate WHERE (condition) with WHERE NOT (condition)
You could turn it around a bit and say "3 is not equal to all the IDs":
where 3 != all (recipient_ids)
From the fine manual:
9.21.4. ALL (array)
expression operator ALL (array expression)
The right-hand side is a parenthesized expression, which must yield an array value. The left-hand expression is evaluated and compared to each element of the array using the given operator, which must yield a Boolean result. The result of ALL is "true" if all comparisons yield true (including the case where the array has zero elements). The result is "false" if any false result is found.
Beware of NULLs
Both ALL:
(some_value != ALL(some_array))
And ANY:
NOT (some_value = ANY(some_array))
Would work as long as some_array is not null. If the array might be null, then you must account for it with coalesce(), e.g.
(some_value != ALL(coalesce(some_array, array[]::int[])))
Or
NOT (some_value = ANY(coalesce(some_array, array[]::int[])))
From the docs:
If the array expression yields a null array, the result of ANY will be null
If the array expression yields a null array, the result of ALL will be null
Augmenting the ALL/ANY Answers
I prefer all solutions that use all or any to achieve the result, appreciating the additional notes (e.g. about NULLs). As another augementation, here is a way to think about those operators.
You can think about them as short-circuit operators:
all(array) goes through all the values in the array, comparing each to the reference value using the provided operator. As soon as a comparison yields false, the process ends with false, otherwise true. (Comparable to short-circuit logical and.)
any(array) goes through all the values in the array, comparing each to the reference value using the provided operator. As soon as a comparison yields true, the process ends with true, otherwise false. (Comparable to short-circuit logical or.)
This is why 3 <> any('{1,2,3}') does not yield the desired result: The process compares 3 with 1 for inequality, which is true, and immediately returns true. A single value in the array different from 3 is enough to make the entire condition true. The 3 in the last array position is prob. never used.
3 <> all('{1,2,3}') on the other hand makes sure all values are not equal 3. It will run through all comparisons that yield true up to an element that yields false (the last in this case), to return false as the overall result. This is what the OP wants.
an update:
as of postgres 9.3,
you can use NOT in tandem with the #> (contains operator) to achieve this as well.
IE.
SELECT COUNT(*) FROM "messages" WHERE NOT recipient_ids #> ARRAY[3];
not (3 = any(recipient_ids))?
Note that the ANY/ALL operators will not work with array indexes. If indexes are in mind:
SELECT COUNT(*) FROM "messages" WHERE 3 && recipient_ids
and the negative:
SELECT COUNT(*) FROM "messages" WHERE NOT (3 && recipient_ids)
An index can then be created like:
CREATE INDEX recipient_ids_idx on tableName USING GIN(recipient_ids)
Use the following query
select id from Example where NOT (id = ANY ('{1, 2}'))

Resources