【问题标题】:SQL union between NULL and VARCHAR errorNULL 和 VARCHAR 错误之间的 SQL 联合
【发布时间】:2012-07-11 21:24:07
【问题描述】:

我有两个具有相同列的视图。第一个视图上的一个列是“即时”生成的,并设置为NULL,另一个视图上的同一列的值存储为varchar。我有一个如下所示的存储过程:

ALTER PROCEDURE [dbo].[mi_GetLearners]  
(@centrename nvarchar(200))  
AS  

SELECT [centrename]  
      ,[Name]  
      ,[Username] --generated on the fly as NULL
FROM  [DB1].[dbo].[vw_Learners]  
WHERE [centrename] = @centrename  

UNION  

SELECT [centrename]  
      ,[Name]   
      ,[Username] --values stored as varchar   
FROM  [Linked_Server].[DB2].[dbo].[vw_Learners]  
WHERE [centrename] = @centrename 

DB1 位于 SQL Server 2008 R2
DB2 在 SQL Server 2005 上

当我运行存储过程时,我收到以下错误:

Msg 245, Level 16, State 1, Line 1 转换时转换失败 将 varchar 值 'someusername' 转换为数据类型 int。

为什么在另一列设置为NULL 时尝试将值转换为int 数据类型?如果我改为将第二列从NULL 更改为' ',则存储的过程可以正常工作......我真的很困惑为什么选择语句中生成的varchar 列和NULL 列之间的联合会抛出这样的错误......有什么想法吗?

编辑:我正在寻找解释而不是解决方案......

编辑 2:运行以下代码:

CREATE VIEW vw_myview
AS
SELECT NULL AS MyColumn

EXECUTE sp_help vw_myview

返回:

    Type    Column_name
     int       MyColumn

【问题讨论】:

  • 发布您的表定义,列数据类型必须匹配才能使联合工作。

标签: sql sql-server-2008 tsql sql-server-2005 null


【解决方案1】:

问题在于NULL 是(在一些回旋余地内)每个 数据类型的成员。

当任何SELECT 查询正在运行时,每一列的内容必须是一种类型,并且只能是一种类型。当列中存在混合值(包括NULLs)时,显然可以通过检查非NULL值的类型来确定类型,并根据需要进行适当的转换。

但是,当所有行都包含特定列的NULL,并且NULL 没有被强制转换为特定类型时,则没有可使用的类型信息。所以,SQL Server 有点武断地决定了这个列的类型是int

create view V1
as
    select 'abc' as Col1,null as Col2
go
create view V2
as
    select 'abc' as Col1,CAST(null as varchar(100)) as Col2

V1 的列类型为 varchar(3)int

V2 具有 varchar(3)varchar(100) 类型的列。

【讨论】:

  • 看来你是对的......如果你在一个 select 语句中将一个列声明为 NULL(例如 select null as MyColumn)并且你没有强制转换为任何数据类型,SQL Server 会决定它是 int。
  • @sc0rp - 是的。你希望它是sql_variant,但它不是。
  • sql_variant 值都有一个底层数据类型,所以它只是一个 int 包装成一个变体......
  • @MartinSmith - 真的吗? “此数据类型也可以将 NULL 作为其基础值,但 NULL 值将没有关联的基本类型。”
【解决方案2】:

我希望字段的类型由联合中的第一个 SELECT 确定。您可以尝试更改两个选择的顺序或更改为 CAST(NULL AS VARCHAR(...))。

【讨论】:

  • 不是第一个SELECT。它查看所有分支,如果不同,则使用具有最高数据类型优先级的分支中的数据类型定义。 NULL 本身被视为int 可以通过SELECT NULL AS Col INTO NewTable 看到
【解决方案3】:

我认为您需要转换为相同的数据类型:

---
AS  

SELECT [centrename]  
      ,[Name]  
      ,CAST(NULL AS VARCHAR(MAX)) AS [Username] 
FROM  [DB1].[dbo].[vw_Learners]  
WHERE [centrename] = @centrename  

UNION  
---

【讨论】:

  • ...除了应该在[DB1].[dbo].[vw_Learners]的查询中完成。
猜你喜欢
  • 1970-01-01
  • 2013-01-30
  • 2013-09-01
  • 1970-01-01
  • 2015-12-20
  • 2013-08-11
  • 2013-10-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多