How to convert or cast int to string in SQL Server - sql

Looking at a column that holds last 4 of someone's SSN and the column was originally created as an int datatype. Now SSN that begin with 0 get registered as 0 on the database.
How can I convert the column and it's information from an int into a string for future proof?

You should convert. CONVERT(VARCHAR(4), your_col)

If you specifically want zero-padded numbers, then the simplest solution is format():
select format(123, '0000')
If you want to fix the table, then do:
alter table t alter column ssn4 char(4); -- there are always four digits
Then update the value to get the leading zeros:
update t
ssn4 = format(convert(int, ssn4), '0000');
Or, if you just want downstream users to have the string, you can use a computed column:
alter table t
add ssn4_str as (format(ssn4, '0000'));

If you want to add leading zeros, use:
SELECT RIGHT('0000'+ISNULL(SSN,''),4)

First thing never store SSN or Zip Code as any numeric type.
Second you should fix the underlying table structure not rely on a conversion...but if you're in a jam this is an example of a case statement that will help you.
IF OBJECT_ID('tempdb..#t') IS NOT NULL
BEGIN
DROP TABLE #t
END
GO
CREATE TABLE #t(
LastFourSSN INT
)
INSERT INTO #t(LastFourSSN)
VALUES('0123'),('1234')
SELECT LastFourSSN --strips leading zero
FROM #t
SELECT -- adds leading zero to anything less than four charaters
CASE
WHEN LEN(LastFourSSN) < 4
THEN '0' + CAST(LastFourSSN AS VARCHAR(3))
ELSE CAST(LastFourSSN AS VARCHAR(4))
END LastFourSSN
FROM #t

If you are looking for converting values in the column for your purpose to use in application, you can use this following-
SELECT CAST(your_column AS VARCHAR(100))
--VARCHAR length based on your data
But if you are looking for change data type of your database column directly, you can try this-
ALTER TABLE TableName
ALTER COLUMN your_column VARCHAR(200) NULL
--NULL or NOT NULL based on the data already stored in database

Related

Conversion failed when converting the nvarchar value to data type int - Error Message

My Query
Select * from MyTable
The table consists 300k rows.
It runs for 200k+ rows and this error pops up.
How to handle this to get the full data?
Does MyTable have any computed columns?
Table consists of a computed column with the name IsExceeds which is given below for your reference.
This is the computed column formula:
(CONVERT([int],[Pro_PCT])-CONVERT([int],replace([Max_Off],'%','')))
Field Definitions:
[Pro_PCT] [nvarchar](50) NULL,
[Max_Off] [nvarchar](50) NULL,
[IsExceeds] AS (CONVERT([int],[Pro_PCT])-CONVERT([int],replace([Max_Off],'%','')))
Kindly convert in float then convert into int.
declare #n nvarchar(20)
set #n='11.11'
if (isnumeric(#n)=0)
SELECT 0
else
SELECT CAST(CONVERT(float, #n) as int) AS n
Why are you storing amounts as strings? That is the fundamental problem.
So, I would suggest fixing your data. Something like this:
update mytable
set max_off = replace(max_off, '%');
alter table mytable alter pro_pct numeric(10, 4);
alter table mytable alter max_off numeric(10, 4);
(Without sample data or an example of the data I am just guessing on a reasonable type.)
Then, you can define IsExceeds as:
(Pro_PCT - Max_Off)
Voila! No problems.
Based on the formula - either Pro_PCT or Max_Off contains the value 11.11 (well, with an extra % for Max_Off. Perhaps they also contain other values that can't be converted to int.
Here's what you can do to find all the rows that will cause this problem:
Select *
from MyTable
where try_cast(Pro_PCT as int) is null
or try_cast(replace([Max_Off],'%','') as int) is null
After you've found them, you can either fix the values or change the calculation of the computed column to use try_cast or try_convert instead of convert.
Check the bad data with
select * from MyTable where isnumeric( Max_Off ) = 0

SQL - How to change data type float to nvarchar and remove scientific notation

How do I change the data type float to nvarchar in order to remove the scientific notation and still keep precision? Consider the following:
CREATE TABLE ConversionDataType (ColumnData FLOAT);
INSERT INTO ConversionDataType VALUES (25566685456126);
INSERT INTO ConversionDataType VALUES (12345545546845);
INSERT INTO ConversionDataType VALUES (12345545545257);
When I do a simple read I get the following data, as expected:
select * from ConversionDataType
ColumnData
------------------------------------
25566685456126
12345545546845
12345545545257
Now when I try update the data type to an nvarchar, it gets stored in scientific notation which is something I don't want:
update ConversionDataType
set ColumnData = CAST(ColumnData AS NVARCHAR)
The result set is as follows:
25566700000000
12345500000000
12345500000000
It replaces some digits and adds zeros after the 6th index. How can I go about this? I had a look at the Convert function but that is only for converting date time data types.
Being valid what others said in comment, if you just want to convert float to varchar without scientific notation, you need to convert to numeric. You can try this:
SELECT CAST(CAST(CAST(25566685456126291 AS FLOAT) AS NUMERIC) AS NVARCHAR)
Output:
C1
------------------------------
25566685456126292
Whereas
SELECT CAST(CAST(25566685456126291 AS FLOAT) AS NVARCHAR) AS C1
gives:
C1
------------------------------
2.55667e+016
If you need to change datatype, I think you should add a new column, update it and (if you want) delete the old column and rename the new column at the end.
CREATE TABLE TEST1 (C1 FLOAT)
INSERT INTO TEST1 VALUES (25566685456126291);
ALTER TABLE TEST1 ADD C2 VARCHAR(18)
UPDATE TEST1 SET C2=CAST(CAST(C1 AS NUMERIC) AS VARCHAR)
SELECT * FROM TEST1
Output:
C1 C2
---------------------- ------------------
2.55666854561263E+16 25566685456126292
FLOAT was a very bad decision as this is not a precise data type. If you wanted to store the phone numbers as numbers, you'd have to go for DECIMAL instead.
But you'll have to use NVARCHAR instead. And this is the only reasonable design, as phone numbers can have leading zeros or start with a plus sign. So the first thing is to introduce an NVARCHAR column:
ALTER TABLE ConversionDataType ADD ColumnDataNew NVARCHAR(30);
The function to convert a number into a string in SQL Server is FORMAT. It lets you state the format you want to use for the conversion, which is integer in your case (a simple '0'):
update ConversionDataType set ColumnDataNew = format(ColumnData, '0');
At last remove the old column and then rename the new one with the same name. SQL Server lacks an ALTER TABLE syntax to rename a column, so we must call sp_RENAME instead (at least this is what I have read on the Internet; here is a link to the docs: https://msdn.microsoft.com/de-de/library/ms188351.aspx).
ALTER TABLE ConversionDataType DROP COLUMN ColumnData;
EXEC sp_RENAME 'ConversionDataType.ColumnDataNew', 'ColumnData', 'COLUMN';
Here you can see the results: http://rextester.com/GLLB27702
SELECT CONVERT(NVARCHAR(250), StudentID) FROM TableA
StudentID is your Float Column of database
or Simply use
SELECT CONVERT(NVARCHAR(250), yourFloatVariable)

Converting varchar datatype to datetime datatype using SQL 2012 management studio

I have a column which has ddmmmyyyy:hh:mm:ss.nnnnnn it is stored as varchar(25). I need to save it as datetime in the same column. I have tried using
update tablename
set columnname = (SUBSTRING(columnname,1,2) + '-' + SUBSTRING(columnname,3,3) + '-' +
SUBSTRING(columnname,6,4) + ' ' + SUBSTRING(columnname,11,8));
and then
alter table tablename
alter columnname datetime;
but later it shows up the 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.
How do I change it any other opinion or any modification for the above query. Please help. Thank you.
As per your given string format, you should use datetime2 data type
Your string format is almost correct, only 1 colon is extra after Year.
If you fix that thing, you can directly cast the varchar field into datetime2. For example first you can replace the extra colon with space by running following query,
UPDATE myTable
SET targetColumn = STUFF ( targetColumn , 10, 1, ' ')
-- ddmmmyyyy:hh:mm:ss.nnnnnn
-- \
-- this colon is extra which is at 10th position
After this you can directly ALTER your table and change the data type to datetime2.
Important: data in all the lines must contain valid date
Here is a test which shows how you can convert
CREATE TABLE testTable(testCol varchar(25));
INSERT INTO testTable(testCol)
VALUES('03Jan2014 18:33:39.999999');
ALTER TABLE testTable ALTER COLUMN testCol datetime2;
SELECT *
FROM testTable
DROP TABLE testTable;
It has already been answered here: Is there a way to convert a varchar to DATETIME in SQL SERVER 2008?
He uses: convert(datetime,'24/05/2012 09:56:06',103)
Although you might have to do some substrings to adapt to a format covered by convert: http://www.sql-server-helper.com/tips/date-formats.aspx
Add a new column
alter table t
add n datetime
Update the new column
update t
set n = datetimefromparts(
cast(substring(o,6,4) as int),
case substring(o,3,3)
when 'jan' then 1
...
when 'dec' then 12
end,
cast(substring(o,1,2) as int),
cast(substring(o,11,2) as int),
cast(substring(o,14,2) as int),
cast(substring(o,17,2) as int),
cast(substring(o,20,6) as int)
)
If you need to drop the old column
alter table t
drop column o

SQL How to Split One Column into Multiple Variable Columns

I am working on MSSQL, trying to split one string column into multiple columns. The string column has numbers separated by semicolons, like:
190230943204;190234443204;
However, some rows have more numbers than others, so in the database you can have
190230943204;190234443204;
121340944534;340212343204;134530943204
I've seen some solutions for splitting one column into a specific number of columns, but not variable columns. The columns that have less data (2 series of strings separated by commas instead of 3) will have nulls in the third place.
Ideas? Let me know if I must clarify anything.
Splitting this data into separate columns is a very good start (coma-separated values are an heresy). However, a "variable number of properties" should typically be modeled as a one-to-many relationship.
CREATE TABLE main_entity (
id INT PRIMARY KEY,
other_fields INT
);
CREATE TABLE entity_properties (
main_entity_id INT PRIMARY KEY,
property_value INT,
FOREIGN KEY (main_entity_id) REFERENCES main_entity(id)
);
entity_properties.main_entity_id is a foreign key to main_entity.id.
Congratulations, you are on the right path, this is called normalisation. You are about to reach the First Normal Form.
Beweare, however, these properties should have a sensibly similar nature (ie. all phone numbers, or addresses, etc.). Do not to fall into the dark side (a.k.a. the Entity-Attribute-Value anti-pattern), and be tempted to throw all properties into the same table. If you can identify several types of attributes, store each type in a separate table.
If these are all fixed length strings (as in the question), then you can do the work fairly simply (at least relative to other solutions):
select substring(col, 1+13*(n-1), 12) as val
from t join
(select 1 as n union all select union all select 3
) n
on len(t.col) <= 13*n.n
This is a useful hack if all the entries are the same size (not so easy if they are of different sizes). Do, however, think about the data structure because semi-colon (or comma) separated list is not a very good data structure.
IF I were you, I would create a simple function that is dividing values separated with ';' like this:
IF EXISTS (SELECT * FROM sysobjects WHERE id = object_id(N'fn_Split_List') AND xtype IN (N'FN', N'IF', N'TF'))
BEGIN
DROP FUNCTION [dbo].[fn_Split_List]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[fn_Split_List](#List NVARCHAR(512))
RETURNS #ResultRowset TABLE ( [Value] NVARCHAR(128) PRIMARY KEY)
AS
BEGIN
DECLARE #XML xml = N'<r><![CDATA[' + REPLACE(#List, ';', ']]></r><r><![CDATA[') + ']]></r>'
INSERT INTO #ResultRowset ([Value])
SELECT DISTINCT RTRIM(LTRIM(Tbl.Col.value('.', 'NVARCHAR(128)')))
FROM #xml.nodes('//r') Tbl(Col)
RETURN
END
GO
Than simply called in this way:
SET NOCOUNT ON
GO
DECLARE #RawData TABLE( [Value] NVARCHAR(256))
INSERT INTO #RawData ([Value] )
VALUES ('1111111;22222222')
,('3333333;113113131')
,('776767676')
,('89332131;313131312;54545353')
SELECT SL.[Value]
FROM #RawData AS RD
CROSS APPLY [fn_Split_List] ([Value]) as SL
SET NOCOUNT OFF
GO
The result is as the follow:
Value
1111111
22222222
113113131
3333333
776767676
313131312
54545353
89332131
Anyway, the logic in the function is not complicated, so you can easily put it anywhere you need.
Note: There is not limitations of how many values you will have separated with ';', but there are length limitation in the function that you can set to NVARCHAR(MAX) if you need.
EDIT:
As I can see, there are some rows in your example that will caused the function to return empty strings. For example:
number;number;
will return:
number
number
'' (empty string)
To clear them, just add the following where clause to the statement above like this:
SELECT SL.[Value]
FROM #RawData AS RD
CROSS APPLY [fn_Split_List] ([Value]) as SL
WHERE LEN(SL.[Value]) > 0

String manipulation SQL

I have a row of strings that are in the following format:
'Order was assigned to lastname,firsname'
I need to cut this string down into just the last and first name but it is always a different name for each record.
The 'Order was assigned to' part is always the same.......
Thanks
I am using SQL Server. It is multiple records with different names in each record.
In your specific case you can use something like:
SELECT SUBSTRING(str, 23) FROM table
However, this is not very scalable, should the format of your strings ever change.
If you are using an Oracle database, you would want to use SUBSTR instead.
Edit:
For databases where the third parameter is not optional, you could use SUBSTRING(str, 23, LEN(str))
Somebody would have to test to see if this is better or worse than subtraction, as in Martin Smith's solution but gives you the same result in the end.
In addition to the SUBSTRING methods, you could also use a REPLACE function. I don't know which would have better performance over millions of rows, although I suspect that it would be the SUBSTRING - especially if you were working with CHAR instead of VARCHAR.
SELECT REPLACE(my_column, 'Order was assigned to ', '')
For SQL Server
WITH testData AS
(
SELECT 'Order was assigned to lastname,firsname' as Col1 UNION ALL
SELECT 'Order was assigned to Bloggs, Jo' as Col1
)
SELECT SUBSTRING(Col1,23,LEN(Col1)-22) AS Name
from testData
Returns
Name
---------------------------------------
lastname,firsname
Bloggs, Jo
on MS SQL Server:
declare #str varchar(100) = 'Order was assigned to lastname,firsname'
declare #strLen1 int = DATALENGTH('Order was assigned to ')
declare #strLen2 int = len(#str)
select #strlen1, #strLen2, substring(#str,#strLen1,#strLen2),
RIGHT(#str, #strlen2-#strlen1)
I would require that a colon or some other delimiter be between the message and the name.
Then you could just search for the index of that character and know that anything after it was the data you need...
Example with format changing over time:
CREATE TABLE #Temp (OrderInfo NVARCHAR(MAX))
INSERT INTO #Temp VALUES ('Order was assigned to :Smith,Mary')
INSERT INTO #Temp VALUES ('Order was assigned to :Holmes,Larry')
INSERT INTO #Temp VALUES ('New Format over time :LootAt,Me')
SELECT SUBSTRING(OrderInfo, CHARINDEX(':',OrderInfo)+1, LEN(OrderInfo))
FROM #Temp
DROP TABLE #Temp