View Column length Changed,when created with case and replace - sql

View column length (Postcode) has increased to varchar(8000)!, when created from the underlying table, it's column length is only varchar(8)
Database is SQL Server 2012.
create view v_testing as
select Postcode = CASE WHEN LEN(A.RealPostcode) = 0 THEN NULL
ELSE REPLACE(A.RealPostcode,' ','')
END,
A.RealPostcode
from dbo.Table A;

https://msdn.microsoft.com/en-us/library/ms186862.aspx
If string_expression is not of type varchar(max) or
nvarchar(max),REPLACE truncates the return value at 8,000 bytes. To
return values greater than 8,000 bytes, string_expression must be
explicitly cast to a large-value data type.
So just use cast function:
create view v_testing as
select Postcode = CASE WHEN LEN(A.RealPostcode) = 0 THEN NULL
ELSE CAST(REPLACE(A.RealPostcode,' ','') AS VARCHAR(8))
END,
A.RealPostcode
from dbo.Table A;

Related

SQL: converting a column of numeric and null values to FLOAT

I have a table with a column of varchar type. The column contains 568710 records of numeric (I mean the ISNUMERIC() returns 1) and 91 records of null values (i.e., the ISNUMERIC() returns 0). Now, I need to convert the column to FLOAT without losing the null records or replacing them with any other value. Is it possible in SQL?
When I use CONVERT(FLOAT, [Value]) conversion, I get the following error:
Msg 8114, Level 16, State 5, Line 48
Error converting data type varchar to float.
I read that the null can be converted to any type. So it should be possible.
You can use this
SELECT CONVERT(float, CASE WHEN ISNUMERIC(columnName) = 1 THEN columnName ELSE NULL END) FROM TableABC
Try :::
ALTER TABLE tablename
ADD NewFloatColumn FLOAT
UPDATE TableName
SET NewFloatColumn =
CASE WHEN ISNUMERIC(VarcharColumn) =1 THEN CAST (VarcharColumn AS float)
WHEN UPPER(VarcharColumn) = 'NULL' THEN null
END
Select (CASE WHEN ISNUMERIC(c) = 1
THEN (CASE WHEN c LIKE '%.%' THEN c ELSE c + '.00' END)
ELSE '0.00'
END)from table_name
I just spent some time scratching my head at the same problem. I was able to resolve this by converting first to int, then to float. Testing shows no data loss as my float column did not contain decimal, it simply had to match the dtype of another column for a later UNION operation.
This was completed on SQL Server 2016.
ALTER TABLE table1
ALTER COLUMN column1 int;
ALTER TABLE table1
ALTER COLUMN column1 float;

SQL Server : Nvarchar to Varchar

I have a table with two columns, one is of type Varchar and the other in NVarchar.
I want to update all the rows so VarcharField = NVarcharField.
It won't let me because some of the rows contain chars that are not allowed in varchar column with the current code page.
How can I find these rows?
Is it possible to remove any char that doesn't fit the specific code page I'm using?
SQL Server 2012.
You can find the rows by attempting to convert the nvarchar() col to varchar():
select nvarcharcol
from t
where try_convert(varchar(max), nvarcharcol) is null;
Try this..
to find the rows with values that are not supported by varchar
declare #strText nvarchar(max)
set #strText = 'Keep calm and say தமிழன்டா'
select cast(#strText as varchar(max)) col1 , N'Keep calm and say தமிழன்டா' col2
Here #strText has non-english chars, When you try to cast that into varchar the non-english chars turns into ????. So the col1 and col2 are not equal.
select nvar_col
from tabl_name
where nvar_col != cast(nvar_col as varchar(max))
Is it possible to remove any char that doesn't fit the specific code page I'm using?
update tabl_name
set nvar_col = replace(cast(nvar_col as varchar(max)),'?','')
where nvar_col != cast(nvar_col as varchar(max))
Replace ? with empty string and update them.
If Gordon's approach doesn't work because you get question marks from TRY_CONVERT instead of the expected NULL, try this approach:
SELECT IsConvertible = CASE WHEN NULLIF(REPLACE(TRY_CONVERT(varchar(max), N'人物'), '?',''), '') IS NULL
THEN 'No' ELSE 'Yes' END
If you need it as filter for the rows that can't be converted:
SELECT t.*
FROM dbo.TableName t
WHERE NULLIF(REPLACE(TRY_CONVERT(varchar(max), t.NVarcharField), '?',''), '') IS NULL

Data type error when passing dynamic column names into SQL Server

I've run into an issue while executing a stored procedure from VBA: I want to pass in a column name as a string for the parameter, and then use a case statement to select the actual column name in the data.
This query works fine when the column name (#FACTOR) i'm passing through is an integer, but not when it's a varchar. I get a conversion error:
Error converting data type nvarchar to float.
Here's my code:
WITH T0 AS (
SELECT DISTINCT
CASE #FACTOR
WHEN 'DRVREC' THEN DRIVINGRECORD --OK
WHEN 'POAGE' THEN POAGE
WHEN 'ANNUALKM' THEN AMC_VH_ANNL_KM
WHEN 'DAILYKM' THEN AMC_VH_KM_TO_WRK
WHEN 'RATETERR' THEN AMC_VH_RATE_TERR --OK
WHEN 'BROKERNAME' THEN MASTERBROKER_NAME
WHEN 'DRVCLASS' THEN DRIVINGCLASS -- OK
WHEN 'VEHAGE' THEN VEH_AGE -- OK
WHEN 'YEARSLIC' THEN YRSLICENSE
WHEN 'COVERAGECODE' THEN COVERAGECODE
ELSE NULL END AS FACTOR FROM DBO.Automation_Data
),
...
...
Or perhaps the example below is more concise:
DECLARE #FACTOR varchar(50)
SELECT #FACTOR = 'NOT_A_VARCHAR'
SELECT CASE #FACTOR
WHEN 'A_VARCHAR' THEN COLUMNNAME1
WHEN 'NOT_A_VARCHAR' THEN COLUMNNAME2
ELSE NULL END AS FACTOR FROM dbo.myTable
^ This would work, but if #FACTOR = 'A_VARCHAR' then i get the error.
Thanks in advance!
UPDATE **********************************:
It appears to be an issue with the case statement itself?
When I only have the varchar option in my case statement, the query runs. When I un-comment the second part of the case statement I get the error.
DECLARE #FACTOR varchar(50)
SELECT #FACTOR = 'A_VARCHAR'
SELECT CASE #FACTOR
WHEN 'A_VARCHAR' THEN COLUMNNAME1
--WHEN 'NOT_A_VARCHAR' THEN COLUMNNAME2 ELSE NULL
END AS FACTOR FROM dbo.myTable
When you are selecting from multiple columns as a single column like you are doing, SQL returns the result as the highest precedence type. Same goes with coalesce etc. when a single result is to be returned from multiple data types.
If you try the code below for example, 3rd select will return the error you're getting, as it tries to convert abc to int (higher precedence). If you set #V to '123', error will go away, as the convert from '123' to int/float works. When you check the 'BaseType' of the result, you can see it shows the highest precedence data type of the mixed types.
DECLARE #F int = 1 --if you use float here error message will show ...'abc' to data type float.
DECLARE #V varchar(5) = 'abc'
DECLARE #O varchar = '1'
SELECT CASE WHEN #O = '1' THEN #F ELSE #V END --no error
SELECT SQL_VARIANT_PROPERTY((SELECT CASE WHEN #O = '1' THEN #F ELSE #V END), 'BaseType') --int/float
SET #O = '2'
SELECT CASE WHEN #O = '1' THEN #F ELSE #V END --error: Conversion failed when converting the varchar value 'abc' to data type int.
When you converted all your selects to nvarchar, nvarchar became the highest precedence data type, so it worked. But if you know some of your columns are float and some of them nvarchar, you only need to convert float columns to nvarchar. So this will work as well:
SET #O = '2'
SELECT CASE WHEN #O = '1' THEN CONVERT(NVARCHAR(5), #F) ELSE #V END
See SQL Data Type Precedence

SQL Server stored procedure convert varbinary to Base64String

I have been tasked to create a stored procedure which can look at a table and pull up the ObjectGUID and extensionAttribute6 column and do a compare.
Basically the objectGUID is a varbinary column and extensionAttribute6 is a nvarchar column. What I really need to do is pull up all records where extensionAttribute6 is not null, then take the value of objectGUID and convert it to a base-64 string value and compare that value with value in the column extensionAttribute6 of that record. If the value match, then insert a calculated column called Compliance (nvarchar(10)) and put True there, else put false there.
You can use XML to get Base64:
Getting records that decoded(objectGUID) = extensionAttribute6
SELECT *
FROM your_tab
WHERE extensionAttribute6 IS NOT NULL
AND CAST(CAST('' as XML).value('xs:base64Binary(sql:column("objectGUID"))', 'VARBINARY(MAX)') AS NVARCHAR(MAX)) = extensionAttribute6
And update:
UPDATE your_tab
SET Compliance = IIF(CAST(CAST('' as XML).value('xs:base64Binary(sql:column("objectGUID"))', 'VARBINARY(MAX)') AS NVARCHAR(MAX)) = extensionAttribute6, 'True', 'False')
For storing True/False you should use BIT datatype instead of string.
EDIT:
SELECT *
[Compliance] = IIF(CAST(CAST('' as XML).value('xs:base64Binary(sql:column("objectGUID"))', 'VARBINARY(MAX)') AS NVARCHAR(MAX)) = extensionAttribute6, 'True', 'False')
FROM your_tab

SQL for nvarchar 0 = '' & = 0?

I was searching for integers in a nvarchar column. I noticed that if the row contains '' or 0 it is picked up if I search using just 0.
I'm assuming there is some implicit conversion happening which is saying that 0 is equal to ''. Why does it assign two values?
Here is a test:
--0 Test
create table #0Test (Test nvarchar(20))
GO
insert INTO #0Test (Test)
SELECT ''
UNION ALL
SELECT 0
UNION ALL
SELECT ''
Select *
from #0Test
Select *
from #0Test
Where test = 0
SELECT *
from #0Test
Where test = '0'
SELECT *
from #0Test
Where test = ''
drop table #0Test
The behavior you see is the one describe din the product documentation. The rules of Data Type Precedence specify that int has higher precedence than nvarchar therefore the operation has to occur as an int type:
When an operator combines two expressions of different data types, the
rules for data type precedence specify that the data type with the
lower precedence is converted to the data type with the higher
precedence
Therefore your query is actually as follow:
Select *
from #0Test
Where cast(test as int) = 0;
and the empty string N'' yields the value 0 when cast to int:
select cast(N'' as int)
-----------
0
(1 row(s) affected)
Therefore the expected result is the one you see, the rows with an empty string qualify for the predicate test = 0. Further proof that you should never mix types freely. For a more detailed discussion of the topic, see How Data Access Code Affects Database Performance.
You are implicitly converting the field to int with your UNION statement.
Two empty strings and the integer 0 will result in an int field. This is BEFORE you insert into the nvarchar field, so the data type in the temp table is irrelevant.
Try changing the second select in the UNION to:
SELECT '0'
And you will get the expected result.