Reputation: 226
I have created a simple table to store name-value-pairs.
create table ifr_nvpairs
(
name varchar(255) PRIMARY KEY,
type char(5),
string varchar(255),
bit_value bit,
int_value bigint,
dec_value decimal(12,2),
float_value float,
date_value datetime,
char_value varchar(255)
);
There is a constraint and triggers to ensure that an
insert ifr_nvpairs(name,bit_value) values ('bitValue',1);
results in
bitValue BIT 1 true (null) (null) (null) (null) (null)
I skip those here for brevety and give you some complete inserts:
INSERT INTO "ifr_nvpairs" ("name", "type", "string", "bit_value", "int_value", "dec_value", "float_value", "date_value", "char_value") VALUES ('bitValue', 'BIT ', '1', true, null, null, null, null, null);
INSERT INTO "ifr_nvpairs" ("name", "type", "string", "bit_value", "int_value", "dec_value", "float_value", "date_value", "char_value") VALUES ('charValue', 'CHAR ', 'Hugo ist nett!', null, null, null, null, null, 'Hugo ist nett!');
INSERT INTO "ifr_nvpairs" ("name", "type", "string", "bit_value", "int_value", "dec_value", "float_value", "date_value", "char_value") VALUES ('dateValue', 'DATE ', '2020-01-13 00:00:00.000', null, null, null, null, '2020-01-13 00:00:00', null);
INSERT INTO "ifr_nvpairs" ("name", "type", "string", "bit_value", "int_value", "dec_value", "float_value", "date_value", "char_value") VALUES ('decValue', 'DEC ', '8.15', null, null, 8.15, null, null, null);
INSERT INTO "ifr_nvpairs" ("name", "type", "string", "bit_value", "int_value", "dec_value", "float_value", "date_value", "char_value") VALUES ('floatValue', 'FLOAT', '3.14159', null, null, null, 3.14, null, null);
INSERT INTO "ifr_nvpairs" ("name", "type", "string", "bit_value", "int_value", "dec_value", "float_value", "date_value", "char_value") VALUES ('intValue', 'INT ', '42', null, 42, null, null, null, null);
For convinience of the users I wanted to create a select which returns the value in the stored type.
My approach was
select
case type
when 'BIT' then bit_value
when 'INT' then int_value
when 'DEC' then dec_value
when 'FLOAT' then float_value
when 'DATE' then date_value
when 'CHAR' then char_value
end result
from ifr_nvpairs where name='bitValue';
I wouldn't be surprised if there was an error. But the result is always a datetime.
Why? And is there possible construct in SQL to select an heterogen type?
TIA Jo
Upvotes: 3
Views: 478
Reputation: 95561
A CASE
expression uses Data type precedence (Transact-SQL) to determine the return data type:
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)
The type with the highest precedence will be returned, which in this case, is datetime
(with a precedence of 6).
As for your question "And is there possible construct in SQL to select an heterogen type?", as mentioned in the comments, sql_variant
does exist, but I recommend against it. It has very few use cases and any comparisons require that the value is explicitly converted. As you can't use syntax like CONVERT(SQL_VARIANT_PROPERTY(YourColumn,'BaseType'),YourColumn)
you would have to use dynamic SQL to do this, and you still can't have multiple data types in a single column.
If you need to display different data types, do so in different columns.
Upvotes: 1
Reputation: 1269773
A SQL select
query returns a fixed set of columns. Each column has a fixed type, determined when the query is compiled.
A case
expression returns a single type as well. By the rules of type conversion, that type is generally the "most specific" (these are the rules of SQL). With the plethora of types you have provided, the result of the rules appears to be a datetime
.
You cannot return multiple different types in a single column unless you specify the value as a sql_variant
(which is really just another type).
You cannot do what you want with regular SQL. One possibility is dynamic SQL. Another would be a different approach that didn't require such logic.
Upvotes: 2