我有一个表,用于存储字段/值对进行比较,例如:
ID FieldName ValueA ValueB
---- ---------- ------- ------
1 Name ABC XYZ
1 StartDate 2015-05-04 2015-06-05
1 Amount 4 4
2 Name DEF UVW
2 StartDate 2015-03-22 2015-02-11
2 Amount 4 4
我正在尝试比较ValueA和ValueB的值,寻找不匹配的值。由于它们以varchar(max)的形式存储在表中,有时会出现不匹配的地方,即
ID FieldName ValueA ValueB
---- ---------- ------- ------
3 StartDate 2015-01-30 01/30/2015
因此,在比较之前,我使用CASE
语句来转换数据类型,即
Select *
From ComparisonTable
where
(case when FieldName = 'StartDate' then CAST(ValueA as datetime)
when FieldName = 'Amount' then CAST(ValueA as int)
else CAST(ValueA as varchar(max))
end)
=
(case when FieldName = 'StartDate' then CAST(ValueB as datetime)
when FieldName = 'Amount' then CAST(ValueB as int)
else CAST(ValueB as varchar(max))
end)
我收到一个错误
从字符转换日期和/或时间时转换失败字符串
我想这是因为在某个地方,StartDate值输入错误。然而,我进行了以下搜索:
Select *
From ComparisonTable
where FieldName = 'StartDate'
and
(ISDATE(ValueA) = 0
OR
ISDATE(ValueB) = 0)
对我来说,没有任何东西表明所有的日期值都存储正确。
我想知道是否有其他人也遇到过类似的问题,或者SQL/SQL Server中是否存在不允许在WHERE/CASE
语句中进行这些类型的数据类型转换的固有问题?
更新我尝试在一个简单的SELECT
:中使用相同的CASE
SELECT
(case when FieldName = 'StartDate' then CAST(ValueA as datetime)
when FieldName = 'Amount' then CAST(ValueA as int)
else CAST(ValueA as varchar(max))
end)
=
(case when FieldName = 'StartDate' then CAST(ValueB as datetime)
when FieldName = 'Amount' then CAST(ValueB as int)
else CAST(ValueB as varchar(max))
end)
WHERE FieldName IN ('StartDate','Amount')
而EVERYTHING返回为datetime,这意味着即使是int
值也被转换为日期,这让我相信这种类型的CASE
强制转换是不允许的。尽管CASE
表示要将"Name"字段转换为varchar
,但它却将所有内容转换为datetime。
如果这是标准的SQL Server行为,那么有什么变通方法可以用来进行这些转换吗?
我看到您正在尝试做什么,但不能对这样的单个值使用多个类型。它们都需要是相同的数据类型才能按照您尝试的方式进行操作。
这应该是您想要的,但这将导致较差的性能,因为没有索引可以用于这种类型的比较。
Select *
From ComparisonTable
Where
(
FieldName = 'StartDate'
And Cast(ValueA As DateTime) = Cast(ValueB As DateTime)
)
Or
(
FieldName = 'Amount'
And Cast(ValueA As Int) = Cast(ValueB As Int)
)
Or
(
FieldName Not In ('StartDate', 'Amount')
And Cast(ValueA As Varchar (Max)) = Cast(ValueB As Varchar (Max))
)
另一种选择是在数据类型转换后将所有内容转换为VARCHAR
:
Select *
From ComparisonTable
Where
(
case
when FieldName = 'StartDate' then CAST(CAST(ValueA as datetime) As Varchar (Max))
when FieldName = 'Amount' then CAST(CAST(ValueA as int) AS Varchar (Max))
else CAST(ValueA as varchar(max))
end
)
=
(
case
when FieldName = 'StartDate' then CAST(CAST(ValueB as datetime) AS Varchar(Max))
when FieldName = 'Amount' then CAST(CAST(ValueB as int) As Varchar (Max))
else CAST(ValueB as varchar(max))
end
)
我提出的一个解决方案是使用UNION ALL
来分离不同的类型:
SELECT *
FROM ComparisonTable
WHERE FieldName = 'StartDate'
AND CAST(ValueA as datetime) = CAST(ValueB as datetime)
UNION ALL
SELECT *
FROM ComparisonTable
WHERE FieldName = 'Amount'
AND CAST(ValueA as int) = CAST(ValueB as int)
UNION ALL
SELECT *
FROM ComparisonTable
WHERE FieldName = 'Name'
AND CAST(ValueA as varchar(max)) = CAST(ValueB as varchar(max))
它是有效的,但为了提高效率,我会将其与其他方法进行比较。