Using COALESCE
function but getting the following error:
Conversion failed when converting the varchar value 'X' to data type int.
I have to join two tables on two conditions. I want that if the second condition doesn't hold but there is a blank cell (not null but blank '') in Table 1 then to join to that row. If the second condition doesn't hold then to return a zero.
Join Table 1 and Table 2 - return Table 2 and column 3 from Table 1.
Table 1
(A, 1, X),
(A, 2, Y),
(A, 3, Z),
(A, , X),
(B, 1, X),
(B, 2, Z),
(B, 3, Y),
Table 2
(A, 1),
(A, 2),
(A, 3),
(A, 5),
(B, 1),
(B, 2),
(B, 3),
(B, 5)
I want to get a return of
(A, 1, X),
(A, 2, Y),
(A, 3, Z),
(A, 5, X),
(B, 1, X),
(B, 2, Z),
(B, 3, Y),
(B, 5, NULL)
Code:
DECLARE @table1 TABLE (letter1 CHAR(1), num1 INT, letter2 CHAR(1))
DECLARE @table2 TABLE (letter1 CHAR(1), num1 INT)
INSERT INTO @table1 VALUES
('A', 1, 'X'),
('A', 2, 'Y'),
('A', 3, 'Z'),
('A', null, 'X'),
('B', 1, 'X'),
('B', 2, 'Y'),
('B', 3, 'Z')
INSERT INTO @table2 VALUES
('A', 1),
('A', 2),
('A', 3),
('A', 5),
('B', 1),
('B', 2),
('B', 3),
('B', 5)
SELECT t2.*,
COALESCE(
(SELECT TOP 1 letter2 FROM @table1 WHERE letter1 = t2.letter1 AND num1 = t2.num1),
(SELECT TOP 1 letter2 FROM @table1 WHERE letter1 = t2.letter1 AND num1 IS NULL),
0
) AS missing_letter
FROM @table2 t2
答案 0 :(得分:2)
也许您需要:
select t1.*, t2.*
from table1 t1 outer apply
( select top (1) t2.*
from table2 t2
where t1.col1 = t.col1 and t1.col2 in ('', t2.col2)
order by t2.col2 desc
) t2;
答案 1 :(得分:2)
如果我理解正确,则与coalesce()
的关系较小,而与join
的关系较大:
select t2.*, coalesce(t1.letter2, t1def.letter2) as letter2
from table2 t2 left join
table1 t1
on t2.letter1 = t1.letter1 and t2.num1 = t1.num1 left join
table1 t1def
on t2.letter1 = t1def.letter1 and t1def.num1 is null;
答案 2 :(得分:2)
这里的问题是您的数据类型。 COALESCE
是CASE
表达式的简称。例如。 COALESCE('a',1,'c')
是以下方面的简称:
CASE WHEN 'a' IS NOT NULL THEN 'a'
WHEN 1 IS NOT NULL THEN 1
ELSE 'c'
END
文档(COALESCE (Transact-SQL)也对此进行了描述:
COALESCE
表达式是CASE
的语法快捷方式 表达。也就是说,代码COALESCE(expression1,...n)
是 查询优化器将其重写为以下CASE
表达式:CASE WHEN (expression1 IS NOT NULL) THEN expression1 WHEN (expression2 IS NOT NULL) THEN expression2 ... ELSE expressionN END
CASE
表达式紧跟Data type precedence,并且int
的数据类型优先级比varchar
高。因此,所有内容都会隐式转换为int
。这就是COALESCE
和CASE
表达式都将失败的原因,因为'a'
或'c'
都不能转换为int
。
因此,您需要将CONVERT
显式int
变成varchar
:
COALESCE('a',CONVERT(char(1),1),'c')
但是,文档(如上引用)也陈述如下:
这表示输入值(expression1,expression2, expressionN等)被多次评估。另外,遵守 在SQL标准中,包含子查询的值表达式为 被认为是不确定的,子查询将被评估两次。在 无论哪种情况,在第一个之间可以返回不同的结果 评价和后续评价。
例如,执行代码
COALESCE((subquery), 1)
时, 子查询被评估两次。结果,您可以得到与众不同 结果取决于查询的隔离级别。例如, 代码可以在NULL
隔离级别下返回READ COMMITTED
多用户环境。为确保返回稳定的结果,请使用SNAPSHOT ISOLATION
隔离级别,或将COALESCE
替换为ISNULL
功能。
考虑到您正在使用子查询,此处(嵌套)ISNULL
可能是更好的选择。
值得注意的是,由于功能相似,人们似乎对它们感到困惑,但是COALESCE
和ISNULL
的行为并不相同。 COALESCE
使用数据类型优先级,但是,ISNULL
隐式将第二个值强制转换为第一个参数的数据类型。因此ISNULL('a',1)
可以正常工作,但是COALESCE('a',1)
不能正常工作。
答案 3 :(得分:1)
只需将零更改为null。您不能在合并中混合数据类型:
SELECT t2.*,
COALESCE(
(SELECT TOP 1 letter2 FROM @table1 WHERE letter1 = t2.letter1 AND num1 = t2.num1),
(SELECT TOP 1 letter2 FROM @table1 WHERE letter1 = t2.letter1 AND num1 IS NULL),
null
) AS missing_letter
FROM @table2 t2
答案 4 :(得分:0)
如果COALESCE中的0替换为'0',则该查询有效。
这样,COALESCE不包含混合数据类型。
SELECT t2.*,
COALESCE(
(SELECT TOP 1 letter2 FROM @table1 t1 WHERE t1.letter1 = t2.letter1 AND t1.num1 = t2.num1),
(SELECT TOP 1 letter2 FROM @table1 t1 WHERE t1.letter1 = t2.letter1 AND t1.num1 IS NULL),
'0'
) AS missing_letter
FROM @table2 t2
ORDER BY t2.letter1, t2.num1;
您可以避免两次从table1检索数据。
通过使用外部申请。
由于预期结果的('B',5)为NULL,所以甚至不需要这种方式。
SELECT t2.letter1, t2.num1, t1.letter2 AS missing_letter
FROM @table2 AS t2
OUTER APPLY (
select top 1 t.letter2
from @table1 AS t
where t.letter1 = t2.letter1
and (t.num1 is null or t.num1 = t2.num1)
order by t.num1 desc
) AS t1
ORDER BY t2.letter1, t2.num1;
结果:
letter1 num1 missing_letter
------- ---- --------------
A 1 X
A 2 Y
A 3 Z
A 5 X
B 1 X
B 2 Y
B 3 Z
B 5 NULL