如何使用内部联接在SQL Server 2008中将varchar值转换为数据类型int

时间:2014-10-22 16:17:41

标签: sql sql-server sql-server-2008

我有两个查找表MyProvidersMyGroups。在我的存储过程中,我有一个临时表(用本例中的实际表替换)和数据。一列EntityId指提供者或组。 EntityTypeId在临时表中告诉我实体是1 = Provider还是2 = Group。 EntityId可以包含数字GroupId或字母数字ExternalProviderId

我想检查一下我的临时表中是否有来自clientOid + entityidmyprovider表的mygroup组合无效的记录。

create table MyProviders 
(
    id int, 
    clientoid varchar(20), 
    externalproviderid varchar(20), 
    name varchar(25)
)

create table MyGroups 
(
    id int, 
    clientoid varchar(20), 
    name varchar(25)
)

create table MyJobDetails 
(
     clientoid varchar(20), 
     entityid varchar(20), 
     entitytypeid int, 
     entityname varchar(30)
)

insert into MyJobDetails values ('M.OID', 'MONYE', 1, 'Mark')
insert into MyJobDetails values ('M.OID', 2, 1, 'Lori')
insert into MyJobDetails values ('M.OID', 2, 2, 'Group 1')
insert into MyJobDetails values ('M.OID', 44444, 2, 'Group 2')

insert into MyProviders values (1, 'M.OID', 'MONY', 'Richard')
insert into MyProviders values (2, 'M.OID', '2', 'Mike')
insert into MyProviders values (3, 'M.OID', '3', 'Lori')

insert into MyGroups values (1, 'M.OID', 'Group 1')
insert into MyGroups values (2, 'M.OID', 'Group 2')

我尝试了以下查询来确定是否存在无效实体。

select 
    COUNT(*) 
from 
    MyJobDetails as jd 
where 
    not exists (select 1 
                from MyProviders as p 
                where p.ClientOID = jd.ClientOID 
                  and p.ExternalProviderID = CAST(jd.EntityId as varchar(20)) 
                  and jd.EntityTypeId = 1)
    and not exists (select 1 
                    from MyGroups as g 
                    where g.ClientOID = jd.ClientOID 
                      and g.Id = jd.EntityId 
                      and jd.EntityTypeId = 2)

这可以正常工作,直到我在临时表中获得的字母数字数据在提供程序表中不存在。我收到以下错误消息:

  

转换varchar值时转换失败' MONYE'数据类型int。

我尝试更新其他线程中提到的解决方案以使用IsNumeric,但它也没有用。在此示例中,我需要为MONYE的一个无效条目返回1,该条目在MyProviderMyGroup表格中不存在。

另外,如果我能以更好的方式优化查询以实现我想要的目标吗?

3 个答案:

答案 0 :(得分:1)

在我看来,这是一个非常糟糕的设计

由于您引用了两个表中的一个,因此无法强制执行参照完整性。

为您的密钥设置不同的数据类型会让事情变得更糟糕。

我会用

  • 两个单独的外键MyJobDetails - 一个到MyProvidervarchar(20)),另一个到MyGroupint
  • 让它们都可以为空
  • 为这两个
  • 中的每一个建立正确的外键关系

这样,两者都可以是每个引用表的正确数据类型,您不再需要EntityTypeId列。

作为旁注:无论何时在SQL Server中使用Varchar,无论是定义参数,变量还是在CAST语句中使用它,我都建议始终明确定义varchar长度

或者你知道转换中varchar的长度是多少吗?

CAST(jd.EntityId as varchar)  

使用明确的长度 - 始终 - 这是一个好的,安全的做法:

CAST(jd.EntityId as varchar(15))  

答案 1 :(得分:0)

在第二个AND NOT EXISTS部分中,将g.Id(一个int)与jd.EntityId(一个varchar)进行比较。将g.Id转换为varchar。

and not exists (select 1 
                from #MyGroups as g 
                where g.ClientOID = jd.ClientOID 
                  and CAST(g.Id AS VARCHAR(20)) = jd.EntityId  
                  and jd.EntityTypeId = 2)

答案 2 :(得分:0)

试试这个

select count(*)
from (
    select clientoid,entityid from #MyJobDetails where entitytypeid=1
    except
    select p.ClientOID ,convert(varchar(200),p.ExternalProviderID) from #MyProviders p inner join #MyJobDetails jd on p.ClientOID = jd.ClientOID and p.ExternalProviderID = CAST(jd.EntityId as varchar(20)) where jd.EntityTypeId = 1
    except
    select g.ClientOID,convert(varchar(200),g.Id) from #MyGroups g inner join #MyJobDetails jd on g.ClientOID = jd.ClientOID and g.Id = jd.EntityId where jd.EntityTypeId = 2
)a