How to round 4 decimal places in SQL - casting

I am using MS SQL server. I have varchar columns that I need to convert to NUMERIC(19,4). I am trying to cast and round the field, however in some instances it seems to truncate down to 4 decimal places, rather than properly round. Excample: 17.654593 needs to be 17.6546 rather than just dropping off the '93' from the end. I am using the below to update the entire field. Is there a way to add a 'round' to this script so it updates properly?
update table_name
SET price = case when isnull(price,'') <> ''
then CAST(CAST(price as FLOAT) as NUMERIC(19,4))
else 0
end

Problems
I would advise not casting to FLOAT. It is an inherently inexact datatype, and is probably the cause of the rounding problem. You should be able to cast directly to NUMERIC(19,4).
As this is a VARCHAR column, there's the possibility that a row might be holding a value which will cause your statement to fail. Try putting some text in that field and then running your fix - unless you're handling the error somewhere else, it will fail.
If you push this value back into the same VARCHAR column, it's just going to be implicitly converted back into a VARCHAR anyway. It will have been rounded to four decimal places, but it will still be VARCHAR. I'll presume that's really want you want to do, but have a think about whether it's the right solution.
Also, is there a good reason why you're replacing NULL with 0? Just a word of caution there, because the number zero and a NULL have very different meanings, and if you're not being careful this may trip up you or someone else who needs to consume the data at a later date.
Solutions
SQL Server 2012 or later, resolves rounding issue, resolves unsafe cast to NUMERIC, and leaves NULL values as NULL:
update table_name
set price = ISNULL(TRY_CAST(price as NUMERIC(19,4)), price);
SQL Server 2012 or later, resolves rounding issue, resolves unsafe cast to NUMERIC, sets NULL values to 0:
update table_name
set price = ISNULL(ISNULL(TRY_CAST(price as NUMERIC(19,4)), price), 0);
SQL Server 2008 or later, resolves rounding issue, resolves unsafe cast to NUMERIC, sets NULL values to 0:
update table_name
set price = case
when price is NULL
then '0'
when ISNUMERIC(price + 'e0') = 1
then CAST(CAST(price as NUMERIC(19,4)) as VARCHAR)
else price
end
If you want to stop NULLs from being converted into 0, simply remove the first when clause.

Related

How do I correct an IF function when used with CAST function in Bigquery

SELECT
stn,
date,
-- Use the IF function to replace 999.9 values, which the dataset description explains is the default value when wind speed is missing, with NULLs instead.
IF(
wdsp="999.9",
NULL,
CAST(wdsp AS Float64)) AS wind_speed,
I kept getting error and my query cannot run

Access Table - Expression Builder unexpected results

I have a huge CSV data file that generates 500,000+ rows and 70+ columns, running Excel queries over this much data causes my desktop to crash.
As an alternative i've managed to import the CSV into Access.
The majority of the data fields i need to review/consider within further calculations i've imported as "double" field type.
I guess the first question is should i use single rather than double? The values i am considering will only ever report to 2 decimal places.
Within the imported table i've created some new columns, as i need to validate that the sum of underlying values equals the totals reported.
A sum of 5 underlying columns (called SUMofService)
[Ancillary Costs] + [Incidental Costs] + [One-Off Costs] + [Ongoing Costs] + [Transaction Costs]
I've not reviewed all 500,000 rows, but this formula seems to be summing the values correctly.
Using this value i've then created a new column to compare this total to the total in the report
IIF([SUMofService] = [Total Service],"Match","No Match")
This also seems to work as expected, but there are instances where this field returns a false.
Looking at the underlying numbers in [SUMofService] and [TotalService] they match, so i am confused as to why i am seeing the false results.
Could anyone review what i've detailed, and perhaps provide a steer as to whether i've considered something incorrectly.
There are probably better ways to achieve what i'm trying to do, but i haven't really used Access since school and you forget quite a bit in 30 years!!
Any responses are much appreciated - i've googled this as much as i can, but not 100% what to ask, and some responses are so far beyond my level of thinking.
should I use single rather than double?
The values I am considering will only ever report to 2 decimal places.
Neither. Use Currency.
That will also provide correct results for:
IIF([SUMofService] = [Total Service],"Match","No Match")
Using Double or, indeed, Single will cause floating point errors - as in this classic example:
? 10.1 - 10.0
9.99999999999996E-02
' thus:
? 10.1 - 10.0 = 0.1
False

When 2 values are the same, check which has a higher value in another column and return a text value

I'm using EXCEL 2010.
I have a table of data for when tasks run through a certain period of time. Tasks can run in early break, late break or no breaks.
Column B returns a text value signalling which category these fall into.
I need to then check, if 2 values return the same in Column B, e.g. B10 = FS and B11 = FS, then I need to check which has the higher value in Column D and return another text value.
Any help would be appreciated
You can achieve this with an array formula (or certainly what it sounds like you need to do) Give this a try: (bear in mind that the ranges are set to my test range, so you will need to adjust)
=IF(COUNTIF($B$2:$B$19,B2)>1,MAX(IF($B$2:$B$19=B2,$D$2:$D$19)))
Remember to calculate with Ctrl+Shift+Enter

Preserving output precision with Django DecimalField and PostgreSql Numeric field

I'm saving data to a PostgreSQL backend through Django. Many of the fields in my models are DecimalFields set to arbitrarily high max_digits and decimal_places, corresponding to numeric columns in the database backend. The data in each column have a precision (or number of decimal places) that is not known a priori, and each datum in a given column need not have the same precision.
For example, arguments to a model may look like:
{'dist': Decimal("94.3"), 'dist_e': Decimal("1.2")}
{'dist': Decimal("117"), 'dist_e': Decimal("4")}
where the keys are database column names.
Upon output, I need to preserve and redisplay those data with the precision with which they were read in. In other words, after the database is queried, the displayed data need to look exactly like the data in that were read in, with no additional or missing trailing 0's in the decimals. When queried, however, either in a django shell or in the admin interface, all of the DecimalField data come back with many trailing 0's.
I have seen similar questions answered for money values, where the precision (2 decimal places) is both known and the same for all data in a given column. However, how might one best preserve the exact precision represented by Decimal values in Django and numeric values in PostgreSQL when the precision is not the same and not known beforehand?
EDIT:
Possibly an additional useful piece of information: When viewing the table to which the data are saved in a Django dbshell, the many trailing 0's are also present. The python Decimal value is apparently converted to the maximum precision value specified in the models.py file upon being saved to the PostgreSQL backend.
If you need perfect parity forwards and backwards, you'll need to use a CharField. Any number-based database field is going to interact with your data muxing it in some way or another. Now, I know you mentioned not being able to know the digit length of the data points, and a CharField requires some length. You can either set it arbitrarily high (1000, 2000, etc) or I suppose you could use a TextField, instead.
However, with either approach, you're going to be wasting a lot database resources in most scenarios. I would suggest modifying your approach such that extra zeros at the end don't matter (for display purpose you could always chop them off), or such that the precision is not longer arbitrary.
Since I asked this question awhile ago and the answer remains the same, I'll share what I found should it be helpful to anyone in a similar position. Django doesn't have the ability to take advantage of the PostgreSQL Numerical column type with arbitrary precision. In order to preserve the display precision of data I upload to my database, and in order to be able to perform mathematical calculations on values obtained from database queries without first recasting strings into python Decimal types, I opted to add an extra precision column for every numerical column in the database.
The precision value is an integer indicating how many digits after the decimal point are required. The datum 4.350 is assigned a value of 3 in its corresponding precision column. Normally displayed integers (e.g. 2531) have a precision entry of 0. However, large integers reported in scientific notation are assigned a negative integer to preserve their display precision. The value 4.320E+33, for example, gets the precision entry -3. The database recognizes that all objects with negative precision values should be re-displayed in scientific notation.
This solution adds some complexity to the structure and code surrounding the database, but it has proven effective. It also allows me to accurately preserve precision through calculations like converting to/from log and linear values.

"out of memory" exception in CRecordset when selecting a LONGTEXT column from MySQL

I am using CODBCRecordset (a class found on CodeProject) to find a single record in a table with 39 columns. If no record is found then the call to CRecordset::Open is fine. If a record matches the conditions then I get an Out of Memory exception when CRecordset::Open is called. I am selecting all the columns in the query (if I change the query to select only one of the columns with the same where clause then no exception).
I assume this is because of some limitation in CRecordset, but I can't find anything telling me of any limitations. The table only has 39 columns.
Has anyone run into this problem? And if so, do you have a work around / solution?
This is a MFC project using Visual Studio 6.0 if it makes any difference.
Here's the query (formatted here so wold show up without a scrollbar):
SELECT `id`, `member_id`, `member_id_last_four`, `card_number`, `first_name`,
`mi`, `last_name`, `participant_title_id`, `category_id`, `gender`,
`date_of_birth`, `address_line_1`, `address_line_2`, `city`, `state`,
`zip`, `phone`, `work_phone`, `mobile_phone`, `fax`, `email`,
`emergency_name`, `emergency_phone`, `job_title`, `mail_code`,
`comments`, `contract_unit`, `contract_length`, `start_date`,
`end_date`, `head_of_household`, `parent_id`, `added_by`, `im_active`,
`ct_active`, `organization`, `allow_members`, `organization_category_id`,
`modified_date`
FROM `participants`
WHERE `member_id` = '27F7D0982978B470C5CF94B1B833CC93F997EE23'
Copying and pasting into my query browser gives me only one result.
More info:
Commented out each column in the select statement except for id. Ran the query and no exception.
Then I systematically went through and uncommented each column, one at a time, and re-ran query in between each uncomment.
When I uncomment the comment column then I get the error.
This is defined as the following (Using MySQL): LONGTEXT
Can we assume you mean you're calling CODBCRecordset::Open(), yes? Or more precisely, something like:
CDatabase db;
db.Open (NULL,FALSE,FALSE,"ODBC;",TRUE);
CODBCRecordSet rs (&db);
rs.Open ("select blah, blah, blah from ...");
EDIT after response:
There are some known bugs with various ODBC drivers that appear to be caused by retrieving invalid field lengths. See these links:
http://forums.microsoft.com/msdn/showpost.aspx?postid=2700779&siteid=1
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=296391
This particular one seems to have been because CRecordset will allocate a buffer big enough to hold the field. As the column returns a length of zero, it's interpreted as the max 32-bit size (~2G) instead of the max 8-bit size (255 bytes). Needless to say, it can't allocate enough memory for the field.
Microsoft has acknowledged this as a problem, have a look at these for solutions:
http://support.microsoft.com/kb/q272951/
http://support.microsoft.com/kb/940895/
EDIT after question addenda:
So, given that your MySQL field is a LONGTEXT, it appears CRecordSet is trying to allocate the max possible size for it (2G). Do you really need 2 gig for a comments field? Typing at 80 wpm, 6cpw would take a typist a little over 7 years to fill that field, working 24 h/day with no rest :-).
It may be a useful exercise to have a look at all the columns in your database to see if they have appropriate data types. I'm not saying that you can't have a 2G column, just that you should be certain that it's necessary, especially in light of the fact that the current ODBC classes won't work with a field that big.
Read Pax's response. It gives a you a great understanding about why the problem happens.
Work Around:
This error will only happen if the field defined as (TEXT, LONGTEXT, etc) is NULL (and maybe empty). If there is data in the field then it will only allocate for the size the data in the field and not the max size (thereby causing the error).
So, if there is a case where you absolutely have to have these large fields. Here is a potential solution:
Give the field a default value in the database. (ie. '<blank>')
Then when displaying the value; you pass NULL/empty if you find default value.
Then when updating the value; you pass the default value if you find NULL/empty.
I second Pax's suggestion that this error is due to trying to allocate a buffer big enough to hold the biggest LONGTEXT possible. The client doesn't know how large the data is until it has fetched it.
LONGTEXT is indeed way larger than you would ever need in most applications. Consider using MEDIUMTEXT (max size 16MB) or just TEXT (max size 64KB) instead.
There are similar problems in PHP database interfaces. A PHP normally has a memory size limit and any fetch of a LONGBLOB or LONGTEXT is likely to exceed that limit.