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

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.

Related

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

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

BigInt won't convert to proper date format

So I have a query I'm trying to write where there are two columns that will have variable results. One is date and one is time. My query will look like
Select Schedule ID , Job_Name , next_run_date , next_run_time
The values will vary depending on what database I'm running against. For example, [next_run_date] might = 20181014 and [next_run_time] might read 1000 which would be 1am. But if I run it on a different server, it could have a completely different set of values, but just the same format.
I've unsuccessfully tried to convert the columns to date/time format by using
CONVERT(varchar(10),CONVERT(date,[next_run_date],110),110) AS 'Next Run'
And just get 'Explicit conversion from data type int to date is not allowed'
What I'd like it to display is [next_run_date] might = 10-14-2018 and [next_run_time] = 01:00. Just unsure how to convert this correctly. I do not have to write privs to the database. If I read correctly, at least for the date column, I would have to convert from Bigin to Varchar to ToDate, but unclear how to fully write that.
For the time field you can stuff a : in it.
And a FORMAT for the times below 10 AM.
And the date part can be done with 2 casts and a CONVERT or a FORMAT.
The date from an INT to a VARCHAR in the 'mm-dd-yyyy' format:
CONVERT(VARCHAR(10), CAST(CAST([next_run_date] AS VARCHAR(8)) AS DATE), 110)
The time from an INT to a VARCHAR in the 'hh:mi' format:
STUFF(CAST(FORMAT([next_run_time],'000000') AS VARCHAR(4)),3,0,':')
Example snippet:
DECLARE #Table TABLE (next_run_date INT, next_run_time INT);
INSERT INTO #Table (next_run_date, next_run_time) VALUES
(20180901, 13500)
,(20181015, 134200)
;
SELECT
CONVERT(VARCHAR(10), CAST(CAST([next_run_date] AS VARCHAR(8)) AS DATE), 110) AS [Next Run Date],
STUFF(CAST(FORMAT([next_run_time],'000000') AS VARCHAR(4)),3,0,':') AS [Next Run Time]
FROM #Table
Returns:
Next Run Date Next Run Time
------------- -------------
09-01-2018 01:35
10-15-2018 13:42
You need to convert the bigint to a varchar first, then to a date:
CONVERT(date,CONVERT(varchar(10),[next_run_date]),110) AS 'Next Run'
You could also break up the number into parts and craft a date and time.
DECLARE #Date INT=20181014
DECLARE #Time INT=123456
SELECT CONVERT(DATE,
SUBSTRING(CONVERT(VARCHAR(20),#Date),1,4)+'/'+
SUBSTRING(CONVERT(VARCHAR(20),#Date),5,2)+'/'+
SUBSTRING(CONVERT(VARCHAR(20),#Date),7,2)
) AS [Date]
SELECT CONVERT(TIME,
SUBSTRING(CONVERT(VARCHAR(20),#Time),1,LEN(CONVERT(VARCHAR(20),#Time))-4)+':'+
SUBSTRING(CONVERT(VARCHAR(20),#Time),LEN(CONVERT(VARCHAR(20),#Time))-3,2)+':'+
SUBSTRING(CONVERT(VARCHAR(20),#Time),LEN(CONVERT(VARCHAR(20),#Time))-1,2)
) AS [Time]
select convert(datetime, cast(20181014 as varchar), 102)
Note :
CAST is part of the ANSI-SQL specification; whereas, CONVERT is not.
In fact, CONVERT is SQL implementation specific. CONVERT differences
lie in that it accepts an optional style parameter which is used for
formatting.

Better approach for nested loops in SQL Server

I have a nested loop that checks all the names and dates from descript column from table tmp13 and stores them as individual rows in other table (tmp14). The problem is that the while loop is executing for a long time. I don't know how to make it run faster. I have tried some suggests already from previous post, but I haven't been very successful. Can anyone give some suggestion to approach this horrible issue.
Here is my code checking the descript columns for names and date. Descript is a text column and can have multiple names and dates. I want to store those names and dates in separate rows.
DECLARE #Id INT
DECLARE #count INT
DECLARE #product_num INT
DECLARE #REQUESTED VARCHAR(50)
DECLARE #FirstDate VARCHAR(255)
DECLARE #RequestedBy VARCHAR(255)
DECLARE #name NVARCHAR(256)
DECLARE #date NVARCHAR(256)
DECLARE #desc NVARCHAR(256)
DECLARE #dateposition INT
DECLARE #nameposition INT
DECLARE #nameend INT
SELECT #count = MAX(id)
FROM #TMP13
SET #id = 1;
WHILE (#id <= #count)
BEGIN
SELECT #desc = descript FROM #TMP13 WHERE Id = #Id
SELECT #product_num = p_Num FROM #TMP13 WHERE Id = #Id
SELECT #REQUESTED = REQUESTED FROM #TMP13 WHERE Id = #Id
SELECT #FirstDate = DATE1 FROM #TMP13 WHERE Id = #Id
SELECT #RequestedBy = BY1 FROM #TMP13 WHERE Id = #Id
while (patindex('%[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9]%',#desc) > 0)
begin
set #dateposition = patindex('%[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9]%',#desc)
set #date = SUBSTRING(#desc,#dateposition,10)
set #nameposition = CHARINDEX('-', #desc)+2
set #nameend = CHARINDEX(' ', #desc, #nameposition)+1
set #name = SUBSTRING(#desc,#nameposition,#nameend-#nameposition)
insert into #TMP14
values (#Id,#product_num,#REQUESTED, #FirstDate ,#RequestedBY, #date, #name)
set #desc = SUBSTRING(#desc,#nameend,1024)
end
set #id = #id + 1;
end
select * from #tmp14;
---sample table
CREATE TABLE #Tmp13(
p_Num INTEGER NOT NULL PRIMARY KEY
REQUESTED varchar(50),
DATE1 VARCHAR(50),
BY1 VARCHAR(50),
DESCRIPT TEXT
);
INSERT INTO #tmp13 (p_Num, REQUESTED, DATE1, BY1, DESCRIPT)
VALUES (100, 'John', '5/30/2017', 'James', '05/30/2017 12:25am Eastern Standard Time - Mjames reported changes in the pages 05/30/2017 10:35AM JRachael agreed to work on the report and report to James 05/30/2017 10:00 AM James reports errors in page.',NULL);
INSERT INTO #tmp13(WO_NUM, Opendate, ClosedDate, Note)
VALUES (200, 'John', '6/1/2017', 'Rachael', '06/1/2017 3:20PM Eastern Standard Time - Rsubramaniam reported phone is not functional 06/1/2017 4:00PM Service took the phone and replaced it with new one');
OUTPUT:
Id product_num REQUESTED FirstDate RequestedBY date name date Name
1 100 John 5/30/2017 james 5/30/2017 mjames 5/30/2017 jRachael
Here's an option. This is only looking at parsing multiple dates and names from your column if it's following a consistent format. You'd need to adjust to fit your solution. And...
This will only work with the following:
Dates and names are stored in the field DESCRIPT in a consistent and repeatable format as: "dd/mm/yyyy time zone - name text dd/mm/yyyy
time zone - name text dd/mm/yyyy time zone - name text"
I'm not sure what sort of performance this will give you and if the format of how date and names are stored in that field change, it won't work. That's the importance of knowing if the format is consistent and repeatable.
In the example we're basically splitting the phase out into individual words and then filtering to get what you're after. Depending on version of SQL server I have included 2 difference options for how you can do that split.
SQL Server Version 2016+ since it'll use SPLIT_STRING
Another which should work back to 2012. It uses XML
There wasn't much sample data provide but based on your comments and replies, I'm making some assumptions and you may need to adjust for your specific needs.
We're after all occurrences of dates in the field
and also the name associated with a date and it comes right after the '-' after said date.
Here's an example:
DECLARE #tmp13 TABLE
(
[p_Num] INTEGER NOT NULL
, [DESCRIPT] NVARCHAR(MAX)
PRIMARY KEY([p_Num])
);
DECLARE #tmp13Parse TABLE
(
[Id] INT
, [Position] BIGINT
, [Value] NVARCHAR(500)
unique clustered ([Id], [Position])
);
--insert test data
INSERT INTO #tmp13 (
[p_Num]
, [DESCRIPT]
)
VALUES ( 100
, '05/30/2017 12:25am Eastern Standard Time - Mjames reported changes in the pages 05/30/2017 10:35AM Eastern Standard Time - JRachael agreed to work on the report and report to James 05/30/2017 10:00AM Eastern Standard Time - James reports errors in page.' )
, ( 200
, '05/29/2017 12:25am Central Stanard Time - TSmith reported changes in the pages 05/29/2017 10:35AM Central Stanard Time - JRachael agreed to work on the report and report to James 05/29/2017 10:00AM Central Stanard Time - GregNoName reports errors in page.' )
, ( 300
, '05/28/2017 12:25am Eastern Standard Time - Mjames reported changes in the pages 05/28/2017 10:35AM Eastern Standard Time - JName agreed to work on the report and report to James 05/28/2017 10:00AM Eastern Standard Time - James reports errors in page.' )
, ( 400
, '05/27/2017 12:25am Central Stanard Time - Mjames reported changes in the pages 05/27/2017 10:35AM Central Stanard Time - JRachael agreed to work on the report and report to James 05/27/2017 10:00AM Eastern Standard Time - AnotherName reports errors in page.' )
, ( 500
, '05/26/2017 12:25am Eastern Standard Time - MJohnson reported changes in the pages 05/26/2017 10:35AM Eastern Standard Time - FTestname agreed to work on the report and report to James 05/26/2017 10:00AM Eastern Standard Time - James reports errors in page.' )
, ( 600
, '05/25/2017 12:25am Eastern Standard Time - Mjames reported changes in the pages 05/25/2017 10:35AM Eastern Standard Time - JRachael agreed to work on the report and report to James 05/25/2017 10:00AM Eastern Standard Time - James reports errors in page.' )
, ( 700
, '05/24/2017 12:25am Eastern Standard Time - TTaylor reported changes in the pages 05/24/2017 10:35AM Eastern Standard Time - JRachael agreed to work on the report and report to James 05/24/2017 10:00AM Eastern Standard Time - TMoreTestNames reports errors in page.' );
--Basically what we are doing is loading a table with each individual word making sure we keep which Id it was associated with.
--along with the Position of where it was in the phrase.
--Two options below depending on SQL Version.
--SQL Version 2016+, we'll use SPLIT_STRING, code is a little more easier
INSERT INTO #tmp13Parse (
[Id]
, [Position]
, [Value]
)
SELECT [a].[p_Num]
, [b].[Position]
, [b].[Value]
FROM #tmp13 [a]
CROSS APPLY (
SELECT [Value]
, ROW_NUMBER() OVER ( ORDER BY (
SELECT 1
)
) AS [Position]
FROM STRING_SPLIT([a].[DESCRIPT], ' ') --this will handle returning a table based on how you split it, in this case a space.
) AS [b];
--Prior to SQL Version 2016 back to 2012, use this option which is using a XML to split the data.
INSERT INTO #tmp13Parse (
[Id]
, [Position]
, [Value]
)
SELECT [a].[p_Num]
, [ss].[Position]
, [ss].[Value]
FROM #tmp13 [a]
CROSS APPLY (
SELECT ROW_NUMBER() OVER ( ORDER BY (SELECT 1)) AS [Position]
, [y].[i].[value]('(./text())[1]', 'nvarchar(max)') AS [Value]
FROM (
SELECT [x] = CONVERT(XML, '<i>'+ REPLACE([a].[DESCRIPT], ' ', '</i><i>')+ '</i>').[query]('.')
) AS [a]
CROSS APPLY [x].[nodes]('i') AS [y]([i])
) AS [ss];
--After we have split the data we'll now go after the specific values
SELECT [a].[Id]
, [a].[Value] AS [Date]
, [ccc].[Value] AS [Name]
FROM #tmp13Parse [a]
--First cross apply - what is the position of '-' after my date field. add 1 since the next value should be the name I'm after.
CROSS APPLY (
SELECT MIN([aa].[Position]) + 1 AS [nameAnchorPosition]
FROM #tmp13Parse [aa]
WHERE [aa].[Id] = [a].[Id]
AND [aa].[Value] = '-'
AND [aa].[Position] > [a].[Position]
) AS [bb]
--Second cross apply - Now, based on where I identified '-' to be, plus 1, give me that value.
CROSS APPLY (
SELECT [cc].[Value]
FROM #tmp13Parse [cc]
WHERE [cc].[Id] = [a].[Id]
AND [cc].[Position] = [bb].[nameAnchorPosition]
) AS [ccc]
WHERE TRY_CONVERT(DATE, [a].[Value]) > '1900-01-01'; --will return all those values that are a date as starting point, long with their position.
I did a quick test on one of my servers with record set of 54000 using both options for splitting and parsing and both gave me results in 4-10 seconds. Your mileage may vary.

TSQL Datetime conversion looses a period of time

i'm playing around with a MsSQL Server for some days now and stumbled upon a strange behaviour when converting a datetime to/from a decimal.
SELECT [date] = GETDATE()
, [as decimal] = CAST(GETDATE() AS decimal)
, [from decimal] = CAST(CAST(GETDATE() AS decimal) AS datetime)
, [as float] = CAST(GETDATE() AS float)
, [from float] = CAST(CAST(GETDATE() AS float) AS datetime)
-- should be: 2009-08-15
, [from stored float] = CAST(CAST('40039.9583333333' AS float) AS datetime)
When i convert a datetime without adding anything specific the decimal will be handled as i would define it decimal(18, 0). So there is a data loss in some way.
If i directly convert a float back to datetime which was converted from a datetime (as shown in line 7 of my query) everything is fine.
But when i load a value from a database table, for example 40039.9583333333 which definitely was calculated from a user input (2009-08-15) and convert it back to a datetime, it'll add one day.
I wasn't able to find anything specific for this time loss.
Is somebody able to describe the problem behind this strange behaviour?
And, if possible: add an example on how to do those conversions correctly?
Thanks.
I used the values you specified '2009-08-15' and converted it to both decimal and float, which resulted in a value of 40038 for both. I used this value to convert back to datetime and both the decimal and float returns '2009-08-15 00:00:00.000'.
The value 40039.9583333333 results in, as Renan just posted :), '2009-08-16 22:59:59.997'.
I would question whether it was 'definitely was calculated from a user input (2009-08-15)' because that does not appear to be the case. There is more to it than shared.
-- Microsoft SQL Server 2014 - 12.0.4100.1 (X64)
DECLARE #dt datetime = '2009-08-15'
SELECT CAST(#dt AS decimal) -- 40038
SELECT CAST(#dt AS float) -- 40038
DECLARE #dec1 decimal = 40038;
SELECT CAST(#dec1 AS datetime) -- 2009-08-15 00:00:00.000
DECLARE #flo1 float = 40038;
SELECT CAST(#flo1 AS datetime) -- 2009-08-15 00:00:00.000
DECLARE #dec2 decimal = 40039.9583333333;
SELECT CAST(#dec2 AS datetime) -- 2009-08-17 00:00:00.000
DECLARE #flo2 float = 40039.9583333333;
SELECT CAST(#flo2 AS datetime) -- 2009-08-16 22:59:59.997
What was your input source into the DB? The underlying issue could be the starting reference point for the date.
As an example: From reading online, in Excel the date value '1900-01-01' is equal to 1 numerically.
However, in SQL Server the date value '1900-01-01' is equal to 0 numerically.
SELECT CAST(CAST('1900-01-01' AS DATETIME) AS FLOAT)
In SQL Server 40039.9583333333 is the result of SELECT CAST(CAST('2009-08-16 23:00' AS DATETIME) AS FLOAT)
You should check the inputs. Check which scale/code is being used to calculate the value that is stored on your table.

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.