How can I use Sum for a string function? - sql

An Employee has multiple contract hours, I want to sum the total hours of the contract for each employee, but the data within the column of total contract hours is in this format: 35.00 - Contract hours
When trying to run the below script:
SELECT DISTINCT
EmpId
,Substring(Contract_Hours,1,5) AS TotalContractHours
,SUM(CAST(Substring(Contract_Hours,1,5) AS INT))
--OR ,SUM(CAST(Substring(Contract_Hours,1,5) AS decimal(1,1)))
FROM tbl.Employee
GROUP BY
EmpID
,Substring(Contract_Hours,1,5)
I am getting error:
Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the varchar value '28.00' to data
type int.
I tried to run it without the sum aggregate and it worked, so i think its something to do with the sum and data type that is not converting
what am I doing wrong? Please help

Since the hours is in format xx.yy you have 2 options:
1. Take only the integer part and cast as int:
SELECT EmpId
,Substring(Contract_Hours,1,2) AS TotalContractHours
,SUM(CAST(Substring(Contract_Hours,1,2) AS INT))
FROM tbl.Employee
GROUP BY
EmpID
,Substring(Contract_Hours,1,2)
2. Take whole part and cast as decimal:
SELECT EmpId
,Substring(Contract_Hours,1,5) AS TotalContractHours
,SUM(CAST(Substring(Contract_Hours,1,5) AS DECIMAL(18,2)))
FROM tbl.Employee
GROUP BY
EmpID
,Substring(Contract_Hours,1,5)

The Error is in the Substring. A Substring(1,2) will work
But, a (1,5) will not. Most likely due to the Decimal. You might have to Double Convert/Cast to Decimal, then, back to Integer
Like this:
SELECT DISTINCT
EmpId
,Substring(Contract_Hours,1,5) AS TotalContractHours
,SUM(Convert(int,CAST(Substring(Contract_Hours,1,5) AS decimal(18,2))))
--OR ,SUM(CAST(Substring(Contract_Hours,1,5) AS decimal(1,1)))
FROM tbl.Employee
GROUP BY
EmpID
,Substring(Contract_Hours,1,5)

If you truly are stuck with this terrible design, then I would attempt to wrap up your query to make it as safe as possible, e.g.:
SELECT
EmpId,
LEFT(Contract_Hours, 5) AS TotalContractHours,
SUM(CONVERT(INT, CASE WHEN ISNUMERIC(LEFT(Contract_Hours, 5)) = 1 THEN CONVERT(NUMERIC(19,2), LEFT(Contract_Hours, 5)) ELSE 0 END)) AS SummedHours
FROM
tbl.Employee
GROUP BY
EmpID,
LEFT(Contract_Hours, 5);
How does this work?
We don't need to bother with SUBSTRING as you always start at the leftmost position of the string,so LEFT is simpler. ISNUMERIC will tell us whether we end up with a number or not, to save us getting an exception by attempting to CONVERT something from a string to a number. So if the leftmost 5 characters are numeric, we CONVERT them to a 2dp decimal, then to an INT, then SUM them.

You could try turning the value into numerical value first. Subsequently convert it in decimal. With the following code it should work.
SUM(CAST(CAST(Contract_Hours AS decimal(10,2)) AS int))

Related

How can I use cast in SQL with multiple column selections?

I tried this to get our revenue:
SELECT
CAST(stays_in_week_nights AS int) +
CAST(stays_in_weekend_nights AS int) *
CAST(adr AS int) AS revenue
FROM
Hotels
I expected to get a number as the result of the calculation - but instead, I get this error:
Msg 245, Level 16, State 1, Line 2
Conversion failed when converting the varchar value '111.6' to data type int.
cast is as a decimal instead of as an int. Assuming it is the adr field that is the problem, it would be
SELECT
(CAST(stays_in_week_nights AS int) + CAST(stays_in_weekend_nights AS int))
* CAST(adr AS decimal(10,2)) AS revenue
FROM Hotels
What you would need for the two parameters in decimal(10,2) would depend on your data. Decimal(10,2) would give you 8 places before the decimal point and 2 after.
Also, you may want to add an extra set of parentheses to make sure you are calculating it correctly. Do you want (week+weekend) * adr or week + (weekend*adr)
What you are currently going to get is the second. Even if that is what you want, adding parentheses would clarify to the next developer that that is what you intended to do

Convert date to number data type

I am trying to convert date to number like below, not sure which function works better.
Database used is SQL Server.
Table details
create table test
(
id varchar(255),
call_date varchar(255)
);
insert into test('26203', '14-Aug-2020');
I need output as 4405726203 -- its concatenation of date (14-Aug-2014) + id (26203)
This is too long for a comment.
SQL Server allows you to convert a datetime to a float. That would be:
select cast(dte as float)
from (values (convert(datetime, '14-Aug-2020'))) v(dte)
However, the corresponding floating point value is 44055 (https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=d142a64db0872e7572eb4fbd6d5d5fe7). It is a bit of mystery what your intention is.
You could subtract 2, but that seems arbitrary. You could calculate the number of days since 1899-12-30. But that also seems arbitrary.
In any case, once you figure out how to convert the date to the number you want, just use concat() to combine the values.
I have found the solution:
convert(varchar,CAST(CONVERT(datetime,call_date) as bigint)) + id
Under the hood, a SQL Server DateTime is a tuple of 2 32-bit integers:
The first integer is a count of days since since the epoch, which for SQL Server is 1 January 1900
The second integer is a count of milliseconds since start of day (00:00:00.000). Except that the count ticks up in 3- or 4-milliscond increments. Microsoft only knows why that decision was made.
You can get the count of days since the epoch with
convert( int, convert( date, t.call_date ) )
[wrap that in convert(varchar, ... ) to turn it into a string]
Looks like your id is already a varchar, so you can say:
select compound_key = convert(varchar,
convert(int,
convert(date,
call_date
)
)
)
+ t.id
from test t
I would suggest padding both fields with leading zeros to a fixed length so as to avoid possible collisions (assuming you're trying to generate a key here). Signed 32-bit integer overflows a 2.1 billion-ish, so 9 digits for each field is sufficient.
This works
select concat(datediff(d, 0, cast(call_date as date)), id)
from
(values ('26203','14-Aug-2020')) v(id, call_date);
Results
4405526203

How to convert nvarchar into int type for SQL Server

I tried to count the total the column [Trans Det Amt ex Tax] like the following:
SELECT
Loyalty_Type_Code,
COUNT([Loyalty_Number]),
FORMAT(SUM([Trans_Det_Amt_ex_Tax]), '##,###,###,##0')
FROM
CRM_POWERBI_RETAIL
WHERE
Trans_Hdr_Sale_Date BETWEEN '2019-01-01' AND '2019-10-31'
GROUP BY
Loyalty_Type_Code
UNION
SELECT
'TOTAL',
COUNT(*) AS CCC,
COUNT(*) AS BBB
FROM
CRM_POWERBI_RETAIL
I get this error:
Msg 245, Level 16, State 1, Line 39
Conversion failed when converting the nvarchar value '67,527,726,031' to data type int.
So I tried to convert this to INT type by using the following:
SELECT
CONVERT(INT, Trans_Det_Amt_ex_Tax)
FROM
CRM_POWERBI_RETAIL
But the result still said
Conversion failed when converting the nvarchar value '67,527,726,031' to data type int
Please let me know how to fix this.
Thank you for all answers.
Don't convert the value to a string:
SELECT Loyalty_Type_Code , COUNT([Loyalty_Number]),
SUM([Trans_Det_Amt_ex_Tax]))
FROM CRM_POWERBI_RETAIL
WHERE Trans_Hdr_Sale_Date BETWEEN '2019-01-01' AND '2019-10-31'
GROUP BY Loyalty_Type_Code
UNION
SELECT 'TOTAL', COUNT(*) AS CCC, COUNT(*) AS BBB
FROM CRM_POWERBI_RETAIL;
All the types in a UNION ALL need to be the same. If it sees a string and an integer -- as in the third column -- it will try to convert the string to an integer. That is not possible with commas.
Alternatively, you can convert both columns to strings. A simpler method uses GROUPING SETS:
SELECT COALESCE(Loyalty_Type_Code, 'Total'),
COUNT([Loyalty_Number]),
FORMAT(SUM([Trans_Det_Amt_ex_Tax]), '##,###,###,##0')
FROM CRM_POWERBI_RETAIL
WHERE Trans_Hdr_Sale_Date BETWEEN '2019-01-01' AND '2019-10-31'
GROUP BY GROUPING SETS ( Loyalty_Type_Code, () );
select CONVERT(bigint, Trans_Det_Amt_ex_Tax)
int cant hold number that big
If you want to convert the value to a string, try removing the commas and using a data type cast that is large enough to store that data:
SELECT CAST(REPLACE('67,527,726,031',',','') AS BIGINT);
This will strip the commas and store the data as a BIGINT.
I'm not 100% sure, but you may need to CAST the SUM as a larger data type if you're going to be adding up a lot of values.
DB Fiddle

SQl Server Converting to Date fails , DateTime works

I have a table with a varchar(25) column that holds a date value. A typical value is '11/04/2017'.
This query returns 0 rows
select *
from myTable
where isdate(inputDate) = 0
I am trying to find a max on this, using a date sort.
This query returns the expected result
;with gooddates as
(
select
medcomfolder, PatientId, PatientBirthday, InputDate
from
myTable
where
isdate(inputDate) = 1
)
select max(convert(datetime, inputDate))
from gooddates
This query returns an error.
;with gooddates as
(
select
medcomfolder, PatientId, PatientBirthday, InputDate
from
dwhFuData
where
isdate(inputdate) = 1
)
select max(convert(date, inputdate))
from gooddates
This is the returned error
Msg 241, Level 16, State 1, Line 274
Conversion failed when converting date and/or time from character string
The difference between the 2 queries is that the first is converting to a dateTime while the latter is converting to a date.
At this point, I can move forward w/ the dateTime option, but I am left wondering what I am missing.
I have checked that there are no embedded spaces, and all the columns have a len(InputDate) = 10 (there is NO time data included)
I selected distinct values,put them in excel, and did a date function on each row. I was hoping to get a #VALUE on 1 row. All the rows worked.
So there is nothing silly like '02/31/2019' going on.
How can a dateTime conversion pass when a simple date conversion does not?
My guess is that you have values that include a time stamp following the date (based on the fact that isdate() is always zero).
If so, one simple solution would be to use convert(date, left(inputdate, 10)). Another solution uses try_convert():
try_convert(date, inputdate)
To find the offending values:
select inputdate
from dwhFuData
where try_convert(date, inputdate) is null and inputdate is not null;

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)