How to multiply two values if not null in RDLC report expression
I was using this
=SUM(Fields!Quantity.Value*Fields!ExclusivePrice.Value)
changed to this, but still getting error if value is null
=Sum((IIf(Fields!Quantity.Value Is Nothing, 0,Fields!Quantity.Value))*(IIf(Fields!ExclusivePrice.Value Is Nothing,
0,Fields!ExclusivePrice.Value)))
Thanks in advance for the help.
You have to convert every possible values to the same type (CDec for Decimal, CDbl for Double, etc.) before aggregation.
For example you can modify your expression like this:
=Sum(IIf(Fields!Quantity.Value Is Nothing, CDec(0), CDbl(Fields!Quantity.Value)) * IIf(Fields!ExclusivePrice.Value Is Nothing, CDbl(0), CDec(Fields!ExclusivePrice.Value)))
This is the 'compressed' version:
=Sum(IIf(Not IsNothing(Fields!Quantity.Value * Fields!ExclusivePrice.Value), CDbl(Fields!Quantity.Value * Fields!ExclusivePrice.Value), CDbl(0)))
Related
I have the below data which I want to multiply together, column A times column B to get column C.
A has datatype string and B has datatype long.
A B
16% 894
15% 200
I have tried this expression in query cast(A as int)*B but it is giving me an error.
You can try below way -
select cast(left(A, patindex('%[^0-9]%', A+'.') - 1) as int)*B
from tablename
You need to remove the '%' symbol before attempting your cast. And assuming you are actually wanting to calculate the percentage, then you also need to divide by 100.00.
cast(replace(A,'%','') as int)/100.00*B
Note: You need to use 100.00 rather than 100 to force decimal arithmetic instead of integer. Or you could cast as decimal(9,2) instead of int - either way ensures you get an accurate result.
You may well want to reduce the number of decimal points returned, in which case cast it back to your desired datatype e.g.
cast(cast(replace(A,'%','') as int)/100.00*# as decimal(9,2))
Note: decimal(9,2) is just an example - you would use whatever precision and scale you need.
The syntax of the cast in SQL Server is CAST(expression AS TYPE);
As you cannot convert '%' to an integer so you have to replace that with an empty character
as below:
SELECT cast(replace(A,'%','') AS int);
Finally you can write as below:
SELECT (cast(replace(A,'%','') AS int)/100.00)*B as C;
I am new to SQL so this question is likely simple and easy to answer.
I am creating a temp table in which I want a blank column to be filled later with decimal values.
Can I use as a placeholder in my SELECT statement to indicate that I want decimal values to fill the column?
For columns that I will fill with integer values, I am using the following code:
SELECT 0 AS ColumnName
I do not believe this will work for the column that I want filled with decimal values, as I believe the 0 indicates integer values instead. Is there something that I can use instead of the 0?
Any help would be appreciated!
SQL will perform implicit conversion of some types when it knows there is no risk of data loss. In your case, int can safely convert to decimal, because there's no way to corrupt your data. 0 is 0.0 as far as SQL is concerned.
The opposite would not be true, as casting from decimal to int would lose the decimal part. Therefore SQL would not implicitly cast the opposite.
Your query is good as is.
Using a 0 in a float field will not cause truncation on the record since it contains less precision than a float, so it is safe to do this and implies a 0.0
You could also DEFAULT the field to 0.0 in the table declaration so it will be 0.0 until updated. But not required.
Ex: CREATE TABLE table
( col1 FLOAT(size,d) DEFAULT 0.0 )
I have method like this:
def self.weighted_average(column)
sql = "SUM(#{column} * market_cap) / SUM(market_cap) as weighted_average"
Company.select(sql).to_a.first.weighted_average
end
When the column is a decimal, it returns a value without problem.
But when the column is integer, the method ends up with a PG::NumericValueOutOfRange error.
Should I change column type integer to decimal, or is there a way to get the result of sum without changing column type?
You can always make float from your integer.
def self.weighted_average(column)
column = column.to_f
sql = "SUM(#{column} * market_cap) / SUM(market_cap) as weighted_average"
Company.select(sql).to_a.first.weighted_average
end
You can cast your value to alway be a decimal value, thus no need to change the column type:
sql = "SUM(#{column} * CAST(market_cap as decimal(53,8))) / SUM(CAST(market_cap as decimal(53,8))) as weighted_average"
P.S. I would go with changing the column type - it is consistent then.
I would suggest you to change the datatype to decimal. Because, when SUM gets PG::NumericValueOutOfRange, it means that your datatype is not sufficient. It will lead to gracefully handle this scenario, instead of a workaround.
Postgres documentation says this about SUM() return type:
bigint for smallint or int arguments, numeric for bigint arguments,
otherwise the same as the argument data type
This means that you will somehow need to change datatype that you pass to SUM. It can be one of the following:
Alter table to change column datatype.
Cast column to other datatype in your method.
Create a view that casts all integer columns to numeric and use that in your method.
You are trying to place a decimal value into a integer parameter. Unless you use the ABS() value that will not be possible, unless you are 100% sure that the % value will always be 0.
Use type Float or function ABS() if you HAVE to have an INT
Yo could try casting column to decimal
sql = "SUM(CAST(#{column}) AS DECIMAL * market_cap) / SUM(market_cap) as weighted_average"
I use sqlserver 2012.
I have a query like this
SELECT SUM(TH.CLEAVE_EARN_DAY), SUM(TH.CLEAVE_DAY),
SUM(TH.CLEAVE_EARN_DAY) - SUM(TH.CLEAVE_DAY)
FROM TH_LEAVE_CARD TH
The result is 0, 14.5, -15
so -15 is wrong. Must be -14.5
any suggestion ?
This is what you can try
SELECT SUM(TH.CLEAVE_EARN_DAY), SUM(TH.CLEAVE_DAY),
SUM(TH.CLEAVE_EARN_DAY)*1.0 - SUM(TH.CLEAVE_DAY)
FROM TH_LEAVE_CARD TH
Multiplying with 1.0 will just give you back decimal value and taking away will give you what you asked for
Try converting all arguments to the same datatype and then do calculation:
SELECT
SUM(CAST(TH.CLEAVE_EARN_DAY AS DECIMAL(18,2))),
SUM(CAST(TH.CLEAVE_DAY AS DECIMAL(18,2))),
SUM(CAST(TH.CLEAVE_EARN_DAY AS DECIMAL(18,2))
- CAST(TH.CLEAVE_DAY AS DECIMAL(18,2))) AS substraction
FROM TH_LEAVE_CARD TH
Also you can combine:
SUM(TH.CLEAVE_EARN_DAY) - SUM(TH.CLEAVE_DAY)
to (if both column are NOT NULL):
SUM(TH.CLEAVE_EARN_DAY - TH.CLEAVE_DAY)
or (thanks Arvo for pointing this):
SUM(ISNULL(TH.CLEAVE_EARN_DAY,0) - ISNULL(TH.CLEAVE_DAY,0))
To perform mathematical operations on columns:
Used columns should be converted into same numeric/decimal data type.
To handle null values you may use ISNULL function.
Ex:
SELECT SUM(TH.CLEAVE_EARN_DAY), SUM(TH.CLEAVE_DAY),
SUM(cast (TH.CLEAVE_EARN_DAY) as decimal(5,1)) - SUM(cast ( (TH.CLEAVE_DAY) as decimal(5,1))
FROM TH_LEAVE_CARD
There is few reason why the result is not as per what you are expecting. In Sql Server any math operation that contains a null would result to null. for example sum(1,2,3,null,4) is equal to null. 1 + null also equal to null.
therefore it would be safer to use isnull function to assign a default value in case the value is null.
for mathematical operation. sql server would do the calculation based on the specified data type. for example int / int = int. therefore the result would be missled. because most of the time int / int = float.
it would be better to change the value to double prior to do any arithmetic operation.
below is the example after include the isnull function as well as cast to float.
SELECT SUM(CAST(ISNULL(TH.CLEAVE_EARN_DAY,0) as double)), SUM(cast(ISNULL(TH.CLEAVE_DAY,0) as double)),
SUM(cast(ISNULL(TH.CLEAVE_EARN_DAY,0) as double)) - SUM(cast(ISNULL(TH.CLEAVE_DAY,0) as double))
FROM TH_LEAVE_CARD TH
I am using in insert statement to convert BDE table (source) to a Firebird table (destination) using IB Datapump. So the INSERT statement is fed by source table values via parameters. One of the source field parameters is alphanum (SOURCECHAR10 char(10), holds mostly integers and needs to be converted to integer in the (integer type) destination column NEWINTFLD. If SOURCECHAR10 is not numeric, I want to assign 0 to NEWINTFLD.
I use IIF and SIMILAR to to test whether the string is numeric, and assign 0 if not numeric as follows:
INSERT INTO "DEST_TABLE" (......, "NEWINTFLD",.....)
VALUES(..., IIF( :"SOURCECHAR10" SIMILAR TO '[[:DIGIT:]]*', :"SOURCECHAR10", 0),..)
For every non numeric string however, I still get conversion errors (DSQL error code = -303).
I tested with only constants in the IIF result fields like SOURCECHAR10" SIMILAR TO '[[:DIGIT:]]*', 1, 0) and that works fine so somehow the :SOURCECHAR10 in the true result field of the IIF generates the error.
Any ideas how to get around this?
When your query is executed, the parser will notice that second use of :"SOURCECHAR10" is used in a place where an integer is expected. Therefor it will always convert the contents of :SOURCECHAR10 into an integer for that position, even though it is not used if the string is non-integer.
In reality Firebird does not use :"SOURCECHAR10" as parameters, but your connection library will convert it to two separate parameter placeholders ? and the type of the second placeholder will be INTEGER. So the conversion happens before the actual query is executed.
The solution is probably (I didn't test it, might contain syntax errors) to use something like (NOTE: see second example for correct solution):
CASE
WHEN :"SOURCECHAR10" SIMILAR TO '[[:DIGIT:]]*'
THEN CAST(:"SOURCECHAR10" AS INTEGER)
ELSE 0
END
This doesn't work as this is interpreted as a cast of the parameter itself, see CAST() item 'Casting input fields'
If this does not work, you could also attempt to add an explicit cast to VARCHAR around :"SOURCECHAR10" to make sure the parameter is correctly identified as being VARCHAR:
CASE
WHEN :"SOURCECHAR10" SIMILAR TO '[[:DIGIT:]]*'
THEN CAST(CAST(:"SOURCECHAR10" AS VARCHAR(10) AS INTEGER)
ELSE 0
END
Here the inner cast is applied to the parameter itself, the outer cast is applied when the CASE expression is evaluated to true