Dividing numeric data types result as different scaled numeric type [duplicate] - sql

I keep getting this error message everytime I run this query:
Msg 8115, Level 16, State 8, Line 33
Arithmetic overflow error converting numeric to data type numeric.
The statement has been terminated.
But if I change the create table to (7,0), I don't get the error message.But I need my data to be displayed as a decimal. I have tried 8,3 does not work.
Is there any one who can help me work this?Any help will be greatly appreciated.
DECLARE #StartDate AS DATETIME
DECLARE #StartDate_y AS DATETIME
DECLARE #EndDate AS DATETIME
DECLARE #temp_y AS DATETIME
SET #temp_y = Dateadd(yy, Datediff(yy, 0, Getdate()), 0)
SET #StartDate_y = Dateadd(dd, 1 - Datepart(dw, Dateadd("ww", -2, #temp_y)),
Dateadd("ww", -2, #temp_y))
SET #StartDate = Dateadd(dd, 1 - Datepart(dw, Dateadd("ww", -2, Getdate())),
Dateadd("ww", -2, Getdate()))
SET #EndDate = Dateadd(dd, 6, #StartDate)
--temp table to hold all cities in list
CREATE TABLE ##temp
(
city VARCHAR(50)
)
INSERT INTO ##temp
VALUES ('ABERDEEN'),
('CHESAPEAKE'),
('Preffered-Seafood/CHICAGO'),
('Preffered-Redist/CHICAGO'),
('CLACKAMAS'),
('COLUMBUS'),
('CONKLIN'),
('DENVER'),
('FORT WORTH'),
('HANOVER PARK'),
('JACKSONVILLE'),
('LAKELAND'),
('MONTGOMERY'),
('PFW-NORTHEAST'),
('PFW-SOUTHEAST'),
('RIVERSIDE'),
('TRENTON,CANADA'),
('VERNON')
--temp to hold data for the cities
CREATE TABLE #temp
(
city VARCHAR(50),
ytdshipments INT,
ytdtotalweight DECIMAL(7, 2) NOT NULL,
ytdtotalcharges DECIMAL (7, 2) NOT NULL
--YTDRevperPound decimal (7,2) not null
)
INSERT INTO #temp
SELECT ##temp.city,
0,
0,
0
FROM ##temp
INSERT #temp
-- YTD shipments/Charges/Weight by city
SELECT city = CASE
WHEN nameaddrmstr_1.city IN( 'ABERDEEN', 'CHESAPEAKE', 'CHICAGO'
,
'CLACKAMAS',
'COLUMBUS', 'CONKLIN', 'DENVER',
'FORT WORTH',
'HANOVER PARK', 'JACKSONVILLE',
'LAKELAND'
,
'MONTGOMERY'
,
'RIVERSIDE', 'TRENTON', 'VERNON' )
THEN
CASE
WHEN
nameaddrmstr_1.city = 'CHICAGO'
AND h.shipr = 'PREFRESVS' THEN 'Preffered-Redist/CHICAGO'
WHEN
nameaddrmstr_1.city = 'TRENTON'
AND nameaddrmstr_1.city = 'CA' THEN 'TRENTON,CANADA'
ELSE
nameaddrmstr_1.city
END
ELSE 'Other'
END,
ytdshipments = COUNT(CONVERT(VARCHAR(10), h.dateshipped, 101)),
ytdtotalweight =SUM(CASE
WHEN h.totaldimwgt > h.totalwgt THEN h.totaldimwgt
ELSE h.totalwgt
END),
ytdtotalcharges = SUM (cs.totalestrevcharges)
--YTDRevperPound = convert(decimal(7,2),sum (cs.TotalEstRevCharges )/sum( CASE WHEN h.TotalDimWGT > > h.TotalWGT THEN h.TotalDimWGT ELSE h.TotalWGT END ))
FROM as400.dbo.hawb AS h WITH(nolock)
INNER JOIN as400.dbo.chargesummary AS cs
ON h.hawbnum = cs.hawbnum
LEFT OUTER JOIN as400.dbo.nameaddrmstr AS nameaddrmstr_1
ON h.shipr = nameaddrmstr_1.nameaddrcode
WHERE h.dateshipped >= '01/01/2010'
AND h.dateshipped <= '12/19/2010'
--WHERE H.DateShipped >= >= #StartDate_y AND H.dateshipped <= #EndDate
AND h.cust IN( 'DARDENREED', 'MAINEDARDE', 'MBMRIVRSDE', 'MBMCOLUMBS',
'MBMLAKELND', 'MBMFTWORTH', 'SYGMACOLUM', 'SYGMANETW6',
'MAI215', 'MBMMNTGMRY' )
GROUP BY CASE
WHEN nameaddrmstr_1.city IN( 'ABERDEEN', 'CHESAPEAKE', 'CHICAGO', 'CLACKAMAS',
'COLUMBUS', 'CONKLIN', 'DENVER', 'FORT WORTH',
'HANOVER PARK', 'JACKSONVILLE', 'LAKELAND',
'MONTGOMERY'
,
'RIVERSIDE', 'TRENTON', 'VERNON' ) THEN CASE
WHEN
nameaddrmstr_1.city = 'CHICAGO'
AND h.shipr = 'PREFRESVS' THEN 'Preffered-Redist/CHICAGO'
WHEN
nameaddrmstr_1.city = 'TRENTON'
AND nameaddrmstr_1.city = 'CA' THEN 'TRENTON,CANADA'
ELSE
nameaddrmstr_1.city
END
ELSE 'Other'
END
SELECT #temp.city AS city,
MAX(#temp.ytdshipments) AS ytdshipments,
MAX(#temp.ytdtotalweight) AS ytdtotalweight,
MAX(#temp.ytdtotalcharges) AS ytdtotalcharges
FROM #temp WITH(nolock)
LEFT OUTER JOIN ##temp
ON ##temp.city = #temp.city
GROUP BY #temp.city
DROP TABLE #temp
DROP TABLE ##temp

My guess is that you're trying to squeeze a number greater than 99999.99 into your decimal fields. Changing it to (8,3) isn't going to do anything if it's greater than 99999.999 - you need to increase the number of digits before the decimal. You can do this by increasing the precision (which is the total number of digits before and after the decimal). You can leave the scale the same unless you need to alter how many decimal places to store. Try decimal(9,2) or decimal(10,2) or whatever.
You can test this by commenting out the insert #temp and see what numbers the select statement is giving you and see if they are bigger than your column can handle.

I feel I need to clarify one very important thing, for others (like my co-worker) who came across this thread and got the wrong information.
The answer given ("Try decimal(9,2) or decimal(10,2) or whatever.") is correct, but the reason ("increase the number of digits before the decimal") is wrong.
decimal(p,s) and numeric(p,s) both specify a Precision and a Scale. The "precision" is not the number of digits to the left of the decimal, but instead is the total precision of the number.
For example:
decimal(2,1) covers 0.0 to 9.9, because the precision is 2 digits (00 to 99) and the scale is 1.
decimal(4,1) covers 000.0 to 999.9
decimal(4,2) covers 00.00 to 99.99
decimal(4,3) covers 0.000 to 9.999

(7,2) it means, variable will contain 5 digits before the decimal and 2 digits after decimal .if you are putting 7 digits before the decimal that is wrong.
for better understand :- https://www.sqlshack.com/understanding-sql-decimal-data-type/

If you want to reduce the size to decimal(7,2) from decimal(9,2) you will have to account for the existing data with values greater to fit into decimal(7,2). Either you will have to delete those numbers are truncate it down to fit into your new size. If there was no data for the field you are trying to update it will do it automatically without issues

Use TRY_CAST function in exact same way of CAST function. TRY_CAST takes a string and tries to cast it to a data type specified after the AS keyword. If the conversion fails, TRY_CAST returns a NULL instead of failing.

I approach these problems by trying to isolate the select statement.
Comment out fields until you can isolate which field is actually the problem.
Once you can say : Select from
you can then add Cast(field as numeric(4,6)) [tryMe]
This has the benefit of selecting N rows and then throwing the error.
You can then take the cast off and see what value N+1 has.
The result is usually surprising... or you would not be reading this SO!
I had a problem today where I was calculating tax and had Numeric(7,4)
The issue wound up being I had one order that owed 1000$ in tax.
Numeric(7,4) will only allow 3 digits to the left of the decimal.
DOH!

check your value which you want to store in integer column. I think this is greater then range of integer. if you want to store value greater then integer range. you should use bigint datatype

Related

How do I convert a 5 or 6 digit decimal to a date in sql

I've got a column that shows the date as a decimal such as 101118 for 10-11-18 and 90118 for 09-01-18. I am trying to create a simple report that would give me all reservations yesterday.
So for example
Select playerid, datereservationmade
from dbo.lms
normally there is very simple and I would just do
Select playerid, datereservationmade
from dbo.lms
where datereservationmade >= dateadd(day,datediff(day,1,GETDATE()),0)
AND datereservationmade < dateadd(day,datediff(day,0,GETDATE()),0)
That does not work in this case because the datereservationmade field is a decimal and if its a month 1-9 it leaves off the 0 and makes it a 5 digit decimal then if its 10-12 it is a 6 digit decimal.
Someone please help me figure out how to convert this!
If at all possible, you really should fix your schema so that dates are actually being stored as dates.
If you need to work with the decimal data type, you can use something like the following...
IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL
BEGIN DROP TABLE #TestData; END;
CREATE TABLE #TestData (
decimal_date DECIMAL(6, 0) NOT NULL
);
INSERT #TestData (decimal_date) VALUES (101118), (90118), (101718);
--==============================================
SELECT
td.decimal_date,
dd.date_date
FROM
#TestData td
CROSS APPLY ( VALUES (RIGHT('0' + CONVERT(VARCHAR(6), td.decimal_date), 6)) ) cd (char_date)
CROSS APPLY ( VALUES (CONVERT(DATE, STUFF(STUFF(cd.char_date, 5, 0, '/'), 3, 0, '/'), 1)) ) dd (date_date)
WHERE
dd.date_date = CONVERT(DATE, DATEADD(DAY, -1, GETDATE()));
Convert the decimal to varchar(6) by adding a zero in front and getting the RIGHT 6 characters.
Then convert the string to a date from its parts, which are substrings in your varchar(6). This is made easier in SQL Server 2012 with the DATEFROMPARTS function.
Using the DATEFROMPARTS, as Tab Alleman suggested, you might get something like this:
-- Example of the arithmetic
SELECT 101118 / 10000 AS Month, (101118 % 10000) / 100 AS Day, (101118 % 100) AS Year
-- Using the math in DATEFROMPARTS
SELECT DATEFROMPARTS((101118 % 100) + 2000, 101118 / 10000, (101118 % 10000) / 100 )
However, I'm skeptical that you've provided all the correct information. What happens on January first? Your decimal value won't start with zero (as you stated). Will your day always pad with zero? If not, then 1119 won't produce the same result as 10119. If, however, your day does start with zero, then the equation above should work fine.

DATEDIFF() to just return age with 2 decimal points

I have a SELECT statement requesting the age of he individual when a test was made:
SELECT
DATEDIFF(dd,BIRTH_DATE,TEST_DATE)/365.25 [Age at Result]
FROM TABLE
WHERE ID = '100'
The result comes out like 2.056125.
I saw on another post to convert to seconds and divide by 86400.0, but I was still getting 6 decimal points.
What I was looking back was to get the age as 2.05 or even round to 2.00.
Thanks
You can cast to a decimal with the precision you want:
SELECT CAST(DATEDIFF(day, BIRTH_DATE, TEST_DATE)/365.25 as DECIMAL(10, 2)) as [Age at Result]
FROM TABLE
WHERE ID = 100;
Note: I removed the single quotes around "100". Only use single quotes if it the id is a string.
I would use the following -
DECLARE #TestDate DATETIME = GETDATE()
DECLARE #BirthDate DATETIME = '1995-06-06 08:00:00.000'
SELECT CAST(DATEDIFF(dd,#BirthDate,#TestDate)/365.25 AS DECIMAL(10, 2)) [Age at Result]

trouble with string to date conversion

Greetings StackWarriors....
I am in need of some help.
I have this SQL Select statement:
SELECT GEOID, cast(LEFT(PP.PurchaseDate,4) + RIGHT(Left(PP.PurchaseDate,6),2) as integer) AS Month
FROM PropertyParametersNew PP
join PropertyTracts PT on PP.ParcelID = PT.PARCELID
WHERE
PP.PurchaseDate >0
and convert(datetime, PP.PurchaseDate, 112)>= DATEADD(MONTH,-1,getdate())
The intent in this query is trying to get GEOID, and the year/month associated in the PurchaseDate Column.
and I'm getting this error:
Msg 242, Level 16, State 3, Line 1 The conversion of a varchar data
type to a datetime data type resulted in an out-of-range value.
I realized that inside that column, I have yyyymmdd formatted dates that have 00's in the mm and dd. Examples include 20130000 and 20120300.
I am trying to rephrase the sql query to handle those entries.
My owners say that 0000 should reflect January 1, and 00 should reflect the 1st of the month.
How can I restructure this SQL statement to reflect this value, so I can get Year/Month combo without the conversion failure?
Thanks.
You can use REPLACE to fix values in PurchaseDate, then simply use fixed field in its place:
(edit made after correct remark by #t-clausen)
SELECT GEOID,
cast(LEFT(x.PurchaseDate,4) + RIGHT(Left(x.PurchaseDate,6),2) as integer) AS Month
FROM PropertyParametersNew PP
CROSS APPLY (SELECT CASE WHEN RIGHT(PP.PurchaseDate, 4) = '0000'
THEN LEFT(PP.PurchaseDate, 4) + '0101'
WHEN RIGHT(PP.PurchaseDate, 2) = '00'
THEN LEFT(PP.PurchaseDate, 6) + '01'
ELSE PurchaseDate
END) x(PurchaseDate)
JOIN PropertyTracts PT on PP.ParcelID = PT.PARCELID
WHERE
PP.PurchaseDate >0
and convert(datetime, x.PurchaseDate, 112)>= DATEADD(MONTH,-1,getdate())
If, for example, PP.PurchaseDate is equal to 20130000, then the above query sets x.PurchaseDate equal to 20130101 and uses this value inside CONVERT as well as in SELECT clause.
For all this to work PP.PurchaseDate must be of fixed length (8 characters).
Best senario would be fixing the data to date second best would be changing your dates to be valid dates as char(8).
But your question is how to write your select.
You should not convert the purchase date to datetime, you should go the other way and convert the getdate() to char(8). This will give you a better performance. Then there is the issue of the varchar being 20130000. You can compensate by subtracting 1 from the date and ask for a greater value instead of greater equal.
The answer is quite simple and improves performance because you don't have a conversion on your column:
WHERE
PP.PurchaseDate >0
and PP.PurchaseDate >
CONVERT(char(8),DATEADD(MONTH,-1,getdate())-1, 112)

Values show up as rounded in SQL Server Management Studio but not when extracted

I have set up the query underneath in Microsoft SQL Server Mgmt studio and am receiving interesting results in regards to the Rate and Variable rate columns.
When I run my query in Management Studio I receive the following result set:
The columns are in the following order: TradeID,Dealer,IssuanceDate,MaturityDate,Face,Rate,Proceeds,TxnCCY,VariableRate
Trade ID Dealer IssuanceDate MaturityDate Face Rate Proceeds TXN CCY Variable Rate
PERNOD & RICARD BAR 20121212 20121221 10000000 0.24 9999400 USD NULL
PUT_30 04821QAP6 1ML POOL BAS 20121022 20130418 100000000 0.28 100000000 USD 0.2075
When I run my query outside of Management Studio in a batch file I receive the following result set:
Trade ID Dealer IssuanceDate MaturityDate Face Rate Proceeds TXN CCY Variable Rate
PERNOD & RICARD; BAR;20121212; 20121221; 10000000;0.23999999999999999;9999400;USD;
PUT_30 04821QAP6 1ML POOL;BAS;20121022; 20130418; 100000000;0.28000000000000003;100000000;USD;
0.20749999999999999
How come SQL Server Management Studio is rounding the value but my batch file is not? I need to see the rounded value in my batch extract. I have tried changing the data types of the columns to decimal and real only to receive errors.
Does anyone have any suggestions as to how I can make this work and show the rounded values in my extract?
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
ALTER PROCEDURE [dbo].[CALYON_TRADES_LIABILITIES_TEST]
-- Add the parameters for the stored procedure here
#BusDate datetime = NULL
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
IF #BusDate is null
BEGIN
DECLARE #yesterday datetime
set #yesterday = DATEADD(D, -1, GETDATE())
set #BusDate = CONVERT(datetime,
convert(varchar(2), datepart(month, #yesterday)) + '/' + convert(varchar(2),datepart
(day, #yesterday)) + '/' + convert(varchar(4), datepart(year, #yesterday))
)
END
Drop table dbo.VariableRateLiabilities
Create table dbo.VariableRateLiabilities
(TradeID VarChar(35) null,
Dealer VarChar(15) null,
IssuanceDate varchar (8) null,
MaturityDate varchar (8) null,
Face numeric (9) null,
Rate float null,
Proceeds numeric null,
TxnCCY VarChar (3) null,
VariableRate float null,
VariableRateDate varchar (8) null)
INSERT INTO dbo.VariableRateLiabilities SELECT DISTINCT
RPT.TradeName as TradeID,
RPT.DealerShortName as Dealer,
CONVERT(varchar(8), RPT.TxnValueDate, 112) as IssuanceDate,
CONVERT(varchar(8), RPT.MaturityDate, 112) as MaturityDate,
RPT.Face,
RPT.Rate,
RPT.Proceeds,
RPT.TxnCCY,
IRI.InterestIdxRate as VariableRate,
CONVERT (varchar (8), IRI.InterestIdxDate, 112) as VariableRateDate
From RPT_TradesIssuance RPT
INNER JOIN LiabilityTrades LT
ON RPT.Price = LT.Price
LEFT OUTER JOIN InterestRateIndexes IRI
ON LT.InterestRateCode = IRI.InterestRateCode
WHERE RPT.SPVId=12
AND RPT.MaturityDate > #BusDate
AND RPT.TxnValueDate <= #BusDate
select TradeId,Dealer,IssuanceDate,MaturityDate,Face,Rate,Proceeds,TxnCCY,VariableRate
from dbo.VariableRateLiabilities
where TradeId NOT LIKE 'PUT%'
UNION
select a.TradeId,a.Dealer,a.IssuanceDate,a.MaturityDate,a.Face,a.Rate,a.Proceeds,a.TxnCCY,a.VariableRate
from dbo.VariableRateLiabilities a
where a.VariableRateDate in (select MAX(b.VariableRateDate) from dbo.VariableRateLiabilities b where a.TradeID = b.TradeID)
ORDER BY Dealer,1
END
Your table definition would look like this:
CREATE TABLE dbo.VariableRateLiabilities (
TradeID VARCHAR(35) NULL
,Dealer VARCHAR(15) NULL
,IssuanceDate VARCHAR(8) NULL
,MaturityDate VARCHAR(8) NULL
,Face NUMERIC(9) NULL
,Rate NUMERIC(18, 2) NULL
,Proceeds NUMERIC NULL
,TxnCCY VARCHAR(3) NULL
,VariableRate NUMERIC(18, 4) NULL
,VariableRateDate VARCHAR(8) NULL
);
And your data insert would look like this (assuming that the original values are floats or something similar, so you'd need to CAST or CONVERT):
INSERT INTO dbo.VariableRateLiabilities
SELECT DISTINCT
RPT.TradeName AS TradeID
,RPT.DealerShortName AS Dealer
,CONVERT(VARCHAR(8), RPT.TxnValueDate, 112) AS IssuanceDate
,CONVERT(VARCHAR(8), RPT.MaturityDate, 112) AS MaturityDate
,RPT.Face
,CAST(RPT.Rate AS NUMERIC(18, 2)) AS Rate
,RPT.Proceeds
,RPT.TxnCCY
,CAST(IRI.InterestIdxRate AS NUMERIC(18,4)) AS VariableRate
,CONVERT (VARCHAR(8), IRI.InterestIdxDate, 112) AS VariableRateDate
FROM RPT_TradesIssuance RPT
INNER JOIN LiabilityTrades LT ON RPT.Price = LT.Price
LEFT OUTER JOIN InterestRateIndexes IRI ON LT.InterestRateCode = IRI.InterestRateCode
WHERE RPT.SPVId = 12
AND RPT.MaturityDate > #BusDate
AND RPT.TxnValueDate <= #BusDate;
I am not sure what will happen when you try to CAST the Rate and VariableRate columns like this, because that depends on the data types they have in the RPT_TradesIssuance and InterestRateIndexes tables. Are they FLOAT as well?
(Please note, I chose NUMERIC(18, 2) and NUMERIC(18, 4) as data types, but you should adapt those according to the data that will be stored in those columns.)
If you can avoid floating-point data types in dealing with money, you probably should. Wherever you see a float data type, try replacing it with numeric.
Contrary to common opinion, you can't round an arbitrary floating-point value to two places. And any calculation that involves a floating-point value is probably going to require all values be converted to floating-point, and it will probably return a float. (I looked for SQL Server docs on this, but haven't found them yet.)
Using the correct data type will fix the root cause of the problem.
You might be able to work around the real problem by explicit casting and rounding at the right time, but everybody will have to get that exactly right every time. Fixing the root cause makes everyone's life easier. (cast(float_column_name as numeric(n,m), where 'n' and 'm' are application-dependent. You might choose convert() instead of cast.)
You should convert the FLOAT variables to DECIMAL before rounding them.

SQL 2008 CASE statement aggravation

Why does this fail:
DECLARE #DATE VARCHAR(50) = 'dasf'
SELECT CASE WHEN ISDATE(#DATE) = 1 THEN CONVERT(date,#DATE) ELSE #DATE END
Msg 241, Level 16, State 1, Line 2
Conversion failed when converting date
and/or time from character string.
Why is it trying to convert dasf to date when it clearly causes ISDATE(#DATE) = 1 to evaluate to false...
If I do:
SELECT ISDATE(#DATE)
The return value is 0.
CASE returns a single type. In this case, the type is Date, found from your THEN clause. It is implicitly converting the ELSE clause result to Date to match.
You must choose a single type to be returned by CASE. It cannot be used to return sometimes Date and sometimes varchar.
from MSDN:
http://msdn.microsoft.com/en-us/library/ms181765.aspx
Return Types
Returns the highest
precedence type from the set of types
in result_expressions and the optional
else_result_expression. For more
information, see Data Type Precedence
(Transact-SQL).
and then following that link: http://msdn.microsoft.com/en-us/library/ms190309.aspx
8) date
27) varchar
It's not clear what you want, so it's hard to offer alternatives (I don't know if the CASE is part of a larger query or script), but here's a couple things you can do:
-- choose a single return type per CASE expression
SELECT
CASE
WHEN IsDate(#Date) = 1
THEN convert(date, #Date)
ELSE null
END as [Date],
CASE
WHEN IsDate(#Date) = 1
THEN null
ELSE #Date
END as [VarChar]
--use control flow to select what you want.
IF IsDate(#Date) = 1
THEN
SELECT convert(date, #Date)
ELSE
SELECT #Date
try this:
DECLARE #DATE VARCHAR(50) = 'dasf'
SELECT CASE
WHEN ISDATE(#DATE)=1 THEN CONVERT(char(23),CONVERT(date,#DATE),121)
ELSE #DATE
END
It will basically format your valid date and leave the non-dates alone. Is that what you are after?
actual working sample:
DECLARE #YourTable table (DATE VARCHAR(50))
INSERT #YourTable VALUES ('dasf')
INSERT #YourTable VALUES ('1/1/2010')
SELECT
CASE
WHEN ISDATE(DATE)=1 THEN CONVERT(char(23),CONVERT(datetime,DATE),121)
ELSE DATE
END AS DATE
FROM #YourTable
OUTPUT:
DATE
--------------------------------------------------
dasf
2010-01-01 00:00:00.000
(2 row(s) affected)
In the working example, I made a substitute from date data type to datetime because I'm on SQL Server 2005 and date datatype is SQL Server 2008 only.