I am creating a new table, with various data type, one them in binary(n). When I execute the statement, I end up with the following
Implicit conversion from data type varchar to binary is not allowed, use CONVERT function.
My question: why do I get this error, when there is no data to convert, I am just creating a table?
Create Table EMP.DETAILS
(
ID INT NOT NULL,
TYPE INT,
Created datetime2,
Key_No varchar(5),
Batch_IN INT,
UN_ID BINARY(1) not null default '',
Source INT,
SITE CHAR(1)
)
When I execute the above statement, I get the error mentioned above, But it directs me to the CREATE TABLE line of the code.
The error says "Implicit conversion from data type varchar to binary is not allowed". You are trying to assign a default varchar character to a binary here:
UN_ID BINARY(1) not null default ''
If you absolutely need a default value for a binary column, you can set it directly as something like 0x00:
UN_ID BINARY(1) not null default 0x00
That will basically set your default to 0. You can also set it to an integer value:
UN_ID BINARY(1) not null default 0
And finally, if you absolutely need to to be an empty string, you can find the binary representation of '' with the following SELECT:
SELECT CONVERT(binary, '')
I'm pretty sure it's just 0, though.
Depending on what that column is being used for, though, it might be better suited as a tinyint, char(1), or something similar, rather than a binary(1).
Related
How come string can contain integer. Even if I assume string storing numeric values as string, but even i can use in it calculation and getting the result as well. Just to try I wrote 5 in inverted commas and still calculation works fine. Not sure how?
declare #x varchar(20)
declare #y int
select #x='5'
select #y=6
select #x+#y
SQL Server -- and all other databases -- convert values among types when the need arises.
In this case, you have + which can be either string concatenation or number addition. Because one argument is an integer, it is interpreted as addition, and SQL Server attempts to convert the string to a number.
If the string cannot be converted, then you will get an error.
I would advise you to do your best to avoid such implicit conversions. Use the correct type when defining values. If you need to store other types in a string, use cast()/convert() . . . or better yet, try_cast()/try_convert():
try_convert(int, #x) + #y
A varchar can contain any character from the collations codepage you are using. For the purposes of this answer, I'm going to assume you're using something like the collation SQL_Latin1_General_CP1_CI_AS (which doesn't have any "international" characters, like Kanji, Hiragana, etc).
You first declare the variable #x as a varchar(20) and put the varchar value '5' in it. This is not an int, it's a varchar. This is an important distinction as a varchar and a numerical data type (like an int) behave very differently. For example '10' has a lower value than '2', where as the opposite is true for 10 and 2. (This is one reason why using the correct data type is always important.)
Then the second variable you have is #y, which is an int and has the value 6.
Then you have your expression SELECT #x+#y;. This has 2 parts to it. Firstly, as you have 2 datatypes, Data Type Precedence comes into play. int has a higher precedence than a varchar, and so #x is implicitly converted to an int. Then the expression is calculated, uses + as an addition operator (not a concatenation operator). Therefore the expression is effectively derived like this:
#x + #y = '5' + 6 = CONVERT(int,'5') + 6 = 5 + 6 = 11
SQL Server uses the following precedence order for data types:
user-defined data types (highest)
sql_variant
xml
datetimeoffset
datetime2
datetime
smalldatetime
date
time
float
real
decimal
money
smallmoney
bigint
int
smallint
tinyint
bit
ntext
text
image
timestamp
uniqueidentifier
nvarchar (including nvarchar(max) )
nchar
varchar (including varchar(max) )
char
varbinary (including varbinary(max) )
binary (lowest)
I'm trying to filter some data - I have a column which looks like it is mainly smallint/int. Is there anyway I can run a where statement to say where not int or where not small int??
Microsoft SQL Server manager.
If you want a where clause that can tell you if the column contain information that can't be converted to int or smallint, you can use try_cast:
SELECT *
FROM <TableName>
WHERE TRY_CAST(<ColumnName> AS Int) IS NULL
You can change the int to smallint to get values that can't be converted to smallint but might be convertible to int.
Don't forget to replace <TableName> and <ColumnName> to the names of the relevant table and column.
The Try_Cast built in function will return null if the value in <ColumnName> is null or if it can't be converted to int (and since all smallint values can also be converted to int, it also can't be converted to smallint).
I have this SQL statement to create a table that stores the JSON string data and the event time found in that JSON string.
CREATE TABLE [dbo].[EventLog]
(
[EventID] INT NOT NULL IDENTITY(1,1),
[EventTime] AS CAST(JSON_VALUE(RawEvent, '$.EventTime') AS DATETIME ) PERSISTED,
[RawEvent] NVARCHAR(MAX) NOT NULL
)
However I get the following error below when I run this, I assume SQL Server does not know if the value fits DATETIME? is there a way to get this column defined?
Msg 4936, Level 16, State 1, Line 26
Computed column 'EventTime' in table 'Event' cannot be persisted because the column is non-deterministic.
You can use CONVERT with dates and have deterministic behavior as long as you specify certain date styles. As per the docs here, with the most common JavaScript date formats (since you are converting from JSON), you can use style 126 or 127, which are ISO8601 and ISO8601 with time zone. Your table, then, could be specified like this:
CREATE TABLE [dbo].[EventLog]
(
[EventID] INT NOT NULL IDENTITY(1,1),
[EventTime] AS CONVERT(DATETIME, JSON_VALUE(RawEvent, '$.EventTime'), 126) PERSISTED,
[RawEvent] NVARCHAR(MAX) NOT NULL
)
Alas, this is explained in the documentation:
CAST Deterministic unless used with datetime, smalldatetime, or sql_variant.
You may be able to parse the date and reconstruct the value using datefromparts() or datetimefromparts().
I'm facing a problem with SQL Server.
I've created a table like this:
create table Components
(
pk BIGINT NOT NULL PRIMARY KEY IDENTITY,
id VARCHAR(50),
descr VARCHAR(50),
in_m INT,
in_iy INT,
p_fw VARCHAR(5000)
);
and I'm trying to insert a couple of values:
insert into Components (id, descr, in_m, in_iy, p_fw)
values ('FW000_A', '0%', 0, 0, '[0.0,0.0,0.0]'),
('FW000_B', '1%', 1, 1, '[1.0,1.0,1.0]');
I get the following error:
Msg 245, Level 16, State 1, Line 111
Conversion failed when converting the varchar value '0%' to data type int.
even though the column descr is correctly defined as varchar(50).
Can anybody help me please? Why is SQL Server trying to convert my strings to int values?
What's missing from your question is that you have more than just the two values lines you've shown, and one of the other ones has an integer literal for the descr column, rather than a string.
This example produces the same error:
declare #t table (Descr varchar(50) not null)
insert into #t(Descr) values
('0%'),
(12)
What I believe happens is that SQL Server first tries to determine the data types for all columns in the values clause. Using data type precedence rules, it observes a varchar literal in one row and an int literal in the other, and so determines that the overall type for this column is int and attempts to perform the conversion that leads to the error.
During this process, it does not use any information about the target table into which the values are going to be placed, including the data types of the columns there.
run this and verify the data types;
sp_columns Components
Looks like 'descr' is really an integer
I have a table like this with a computed column:
CREATE TABLE PhoneNumbers
(
[PhoneNumberID] int identity(1,1) not null primary key clustered,
[Number] varchar(20), /* Entire number, like (800) 555-5000 */
[Digits] AS dbo.RegExReplace(Number, '[^0-9]', '') PERSISTED /* Like 8005555000 */
)
It's created fine, and the Digits column works great as expected, BUT it doesn't seem to behave as a "PERSISTED" column. When I do a query with Digits in the WHERE clause it's VERY slow. When I try to add an index to the Digits column I get: Column 'Digits' in table 'PhoneNumbers' is of a type that is invalid for use as a key column in an index.
It seems like that column isn't really being treated as PERSISTED and is being recomputed on every query and won't let me add an index.
The RegExReplace is a C# CLR function defined as follows:
[SqlFunction(IsDeterministic = true, IsPrecise = true)]
public static SqlString RegExReplace(SqlString expression, SqlString pattern, SqlString replace)
Any ideas on how to get that Digits column to act like a persisted column or allow me to add an index?!
Thank you!
Try a CAST:
CREATE TABLE PhoneNumbers
(
[PhoneNumberID] int identity(1,1) not null primary key clustered,
[Number] varchar(20), /* Entire number, like (800) 555-5000 */
[Digits] AS CAST(dbo.RegExReplace(Number, '[^0-9]', '') AS VARCHAR(20)) PERSISTED /* Like 8005555000 */
)
I believe that the problem is your CLR function is returning SqlString which ends up being nvarchar(4000) or similar - not indexable.
It's kind of a known "problem" with computed columns that the datatype is inferred from the expression. Mainly an issue with strings and "helper functions" which take varchar(max) and also with decimal operations where precision changes due to the calculations.
I have a little rule where I always CAST - it makes it explicit and avoids any ambiguity. Generally, columns which are known to be small should be explicitly small - varchar(max) seems to have a lot of performance overhead - even if you pass through a function which returns varchar(max) and takes varchar(max), cast back to the size you know, because it will perform a lot better.