Format the numbers in case statement - sql

I have a query with some case statements within it and one of them determines how much an account is to be paid and right now everything is fine but I was hoping to do formatting for the results, how it is displayed in SQL. I am using SQL Server Management Studio (SQL Server 2016).
I am trying to use '$' + Format(col_name, '#,###') to display results as currency but no decimals. The picture shows you what I currently have after I run my query.
When I tried to incorporate the above format, I get Msg 402 Error The data types nvarchar and varchar are incompatible in the subtract operator.
Not sure how to modify my codes.
CASE
WHEN (prior.amountpaid - prior.amountOwed) < 0 THEN p.amountpaid
ELSE
prior.amountpaid - prior.amountOwed + p.amountpaid
END AS 'Amount Paid',

Wrap the FORMAT function around the entire CASE expression, instead of doing it on the individual columns.

Format the Result not each column
CASE
WHEN (prior.amountpaid - prior.amountOwed) < 0 THEN '$' + Format(p.amountpaid, '#,###')
ELSE
'$' + Format((prior.amountpaid - prior.amountOwed + p.amountpaid), '#,###')
END AS 'Amount Paid'
But if you can leave the formatting to the Front End not the database call, you never know what math you may want to perform in the Business logic and working with strings is a pain.

Related

Error converting data type nvarchar to numeric - SQL Server

I am trying to take an average of a column in my database. The column is AMOUNT and it is stored as NVARCHAR(300),null.
When I try to convert it to a numeric value I get the following error:
Msg 8114, Level 16, State 5, Line 1
Error converting datatype NVARCHAR to NUMBER
Here is what I have right now.
SELECT AVG(CAST(Reimbursement AS DECIMAL(18,2)) AS Amount
FROM Database
WHERE ISNUMERIC(Reimbursement) = 1
AND Reimbursement IS NOT NULL
You would think that your code would work. However, SQL Server does not guarantee that the WHERE clause filters the database before the conversion for the SELECT takes place. In my opinion this is a bug. In Microsoft's opinion, this is an optimization feature.
Hence, your WHERE is not guaranteed to work. Even using a CTE doesn't fix the problem.
The best solution is TRY_CONVERT() available in SQL Server 2012+:
SELECT AVG(TRY_CONVERT(DECIMAL(18,2), Reimbursement)) AS Amount
FROM Database
WHERE ISNUMERIC(Reimbursement) = 1 AND Reimbursement IS NOT NULL;
In earlier versions, you can use CASE. The CASE does guarantee the sequential ordering of the clauses, so:
SELECT AVG(CASE WHEN ISNUMERIC(Reimbursement) = 1 AND Reimbursement IS NOT NULL
THEN CONVERT(DECIMAL(18,2), Reimbursement))
END)
FROM Database;
Because AVG() ignores NULL values, the WHERE is not necessary, but you can include it if you like.
Finally, you could simplify your code by using a computed column:
alter database add Reimbursement_Value as
(CASE WHEN ISNUMERIC(Reimbursement) = 1 AND Reimbursement IS NOT NULL
THEN CONVERT(DECIMAL(18,2), Reimbursement))
END);
Then you could write the code as:
select avg(Reimbursement_Value)
from database
where Reimbursement_Value is not null;
Quote from MSDN...
ISNUMERIC returns 1 for some characters that are not numbers, such as plus (+), minus (-), and valid currency symbols such as the dollar sign ($). For a complete list of currency symbols, see money and smallmoney
select isnumeric('+')---1
select isnumeric('$')---1
so try to add to avoid non numeric numbers messing with your ouput..
WHERE Reimbursement NOT LIKE '%[^0-9]%'
If you are on SQLServer 2012,you could try using TRY_Convert which outputs null for conversion failures..
SELECT AVG(try_convert( DECIMAL(18,2),Reimbursement))
from
table
I am guessing that since it is Nvarchar you are going to find some values in there with a '$','.', or a (,). I would run a query likt this:
SELECT Amount
FROM database
WHERE Amount LIKE '%$%' OR
Amount LIKE '%.%' OR
Amount LIKE '%,%'
See what you get and my guess you will get some rows returned and then update those rows and try it again.
Currently your query would pull all numbers that are not all numeric which is a reason why it is failing too. Instead try running this:
SELECT AVG(CAST(Reimbursement AS DECIMAL(18,2)) AS Amount
FROM Database
--Changed ISNUMERIC() = to 0 for true so it will only pull numeric numbers.
WHERE ISNUMERIC(Reimbursement) = 0 and Reimbursement IS NOT NULL

Average Row [SQL]

Actually I'm a bit confused about what should i wrote in the subject.
The point is like this, I want to average the Speed01,Speed02,Speed03 and Speed04 :
SELECT
Table01.Test_No,
Table01.Speed01,
Table01.Speed02,
Table01.Speed03,
Table01.Speed04,
I want to create new column that consists of this average -->>
AVG(Table01.Speed01, Table01.Speed02, Table01.Speed03,Table01.Speed04) as "Average"
I have tried this, but it did not work.
From
Table01
So, the contain of the Speed column could be exist but sometimes the Speed02 don't have number but the others are have numbers. sometimes speed04 data is also missing and the others is exist, sometimes only one data (example: only Speed01) have the data. lets say it depends on the sensor ability to catch the speed of the test material.
It will be a big help if you can find the solution. I'm newbie here.
THANK YOU ^^
AVG is a SQL aggregate function, therefore not applicable. So simply do the math. Average is sum divided by count:
(SPEED01 + SPEED02 + SPEED03 +SPEED04)/4
To deal with missing values, use NULLIF or COALESCE:
(COALESCE(SPEED01, 0) + COALESCE(SPEED02, 0) + COALESCE(SPEED03, 0) + COALESCE(SPEED04, 0))
That leaves the denominator. You need to add 1 for every non null. For example:
(COALESCE(SPEED01/SPEED01,0) + COALESCE(SPEED02/SPEED02,0) + ...)
You can also use CASE, depending on the supported SQL dialect, to avoid the possible divide by 0:
CASE WHEN SPEED01 IS NULL THEN 0 ELSE 1
OR you can normalize the data, extract all SPEEDs into a 1:M relation and use the AVG aggregate, avoiding all these issues. Not to mention the possibility to add a 5th measurement, then a 6th and so on and so forth!
Just add the columns and divide them by 4. To deal with the "missing" values use coalesce to treat NULL values as zero:
SELECT Test_No,
(coalesce(Speed01,0) + coalesce(Speed02,0) + coalesce(Speed03,0) + coalesce(Speed04,0)) / 4 as "Average"
FROM Table01;
You didn't mention your DBMS (Postgres, Oracle, ...), but the above is ANSI (standard) SQL and should run on nearly every DBMS.
As I understood your question, I supposed that Table01.Speed01, Table01.Speed03, Table01.Speed04 are nullable and of type int whereas Table01.Speed02 is nullable and of type nvarchar:
SELECT
Table01.Test_No,
(
ISNULL(Table01.Speed01, 0) +
CASE ISNUMERIC(Table01.Speed02) WHEN 0 THEN 0 ELSE CAST(Table01.Speed02 AS int) END +
ISNULL(Table01.Speed03, 0) +
ISNULL(Table01.Speed04, 0)
)/4 AS AVG
FROM Table01

Return Character from Numeric Field using Cast & Coalesce

Using SQL Server 2008 R2
Relatively basic SQL user, apologies if this is a simple question but need a little help to tidy up the output of a fairly complex script I have been given.
I have a number of columns being returned for which where there is a NULL, I want to replace all NULL's with a standard set of characters, currently "---". Using ISNULL works for most columns. However, for some columns we are looking at 2 tables to find a value so have after doing some research on here, I have modified a line I am having trouble with as follows:
Previous
isnull (ff.ff_sales,aa.ff_sales) as 'Total Revenue'
Latest
cast(coalesce(ff.ff_sales,aa.ff_sales,'') as FLOAT) as 'Total Revenue'
The initial line returned 'NULL' if both ff.ff_sales & aa.ff_sales were empty, now with the latest line using cast & coalesce I get '0'. However, I am trying to achieve a situation where I get '---' as per all other fields where a NULL exists. I don't want it to return '0' for a Sales field as this is misleading. I have tried using VARCHAR instead of FLOAT but am unsure if this is the right thing to do at this stage?
1st column is using ISNULL, 2nd column current output with cast & coalesce, 3rd column is what I want to get to:
Total Revenue Total Revenue Total Revenue
67755 67755 67755
6.123 6.123 6.123
494.75 494.75 494.75
0 0 0
1139909 1139909 1139909
12346.45 12346.45 12346.45
129.866 129.866 129.866
NULL 0 ---
NULL 0 ---
554 554 554
Thanks for your help!
You can use case to decide what should be output in this scenario, like so:
select
case
when isnull (ff.ff_sales,aa.ff_sales) is null then '---'
else cast(isnull (ff.ff_sales,aa.ff_sales) as varchar)
end as 'Total Revenue'
This will force the output to be returned as varchar though, because you cannot cast '---' as a numeric type.
Alternatively, you could just let the value be NULL in DB, and in your presentation layer, replace a DBNull or equivalent value with '---'. This will let you keep total revenue as a numeric field at the DB level.

DB2 SQL - How can I display nothing instead of a hyphen when the result of my case statement is NULL?

All,
I'm writing a query that includes a CASE statement which compares two datetime fields. If Date B is > Date A, then I'd like the query to display Date B. However, if Date B is not > Date A, then the user who will be getting the report created by the query wants the column to be blank (in other words, not contain the word 'NULL', not contain a hyphen, not contain a low values date). I've been researching this today but have not come up with a viable solution so thought I'd ask here. This is what I have currently:
CASE
WHEN B.DTE_LNP_LAST > A.DTE_PROC_ACT
THEN B.DTE_LNP_LAST
ELSE ?
END AS "DATE OF DISCONNECT"
If I put NULL where the ? is, then I get a hyphen (-) in my query result. If I omit the Else statement, I also get a hyphen in the query result. ' ' doesn't work at all. Does anyone have any thoughts?
Typically the way nulls are displayed is controlled by the client software used to display query results. If you insist on doing that in SQL, you will need to convert the date to a character string:
CASE
WHEN B.DTE_LNP_LAST > A.DTE_PROC_ACT
THEN VARCHAR_FORMAT(B.DTE_LNP_LAST)
ELSE ''
END AS "DATE OF DISCONNECT"
Replace VARCHAR_FORMAT() with the formatting function available in your DB2 version on your platform, if necessary.
You can use the coalesce function
Coalesce (column, 'text')
If the first value is null, it will be replaced by the second one.

Converting to money format

I have following query trying to apply money format.
select case when c.num is null
then 0.00
else '$' + Convert(varchar,CONVERT(money(c.total+c.customerS),1),2)
end verified
from table_Sales c
where c.id=#id
When I run this it gives error it couldn't convert varchar to numeric. When i change
varchar to integer or numeric it doesn't do anything.
Please let me know how to fix it.
Whilst I appreciate this is not a direct answer, I would strongly advocate NOT formatting numeric data to strings in the data layer.
It feels to me a lot more like the type of logic which would or could be application specific. What if you want to re-use the same query to work with GBP or Euros?
Additionally, what if your application needs to handle more than one currency?
I would suggest returning the data without the addition of the currency symbol in decimal form and applying the formatting within the application or on the client side if web based maybe.
Just my 2c(or 2p)
Both types in Case Clause must be same, so 0.00 must be '0.00'
Query:
select case when c.num is null
then '0.00'
else '$' + Convert(varchar,CONVERT(money(c.total+c.customerS),1),2)
end verified
from table_Sales c
where c.id=#id