将两个行值放入一列,将另一行值放入另一列,可以将更多行值添加到列中
Posted
技术标签:
【中文标题】将两个行值放入一列,将另一行值放入另一列,可以将更多行值添加到列中【英文标题】:Making TWO row values into one column, and another row value another column, with the possibility of adding more row values into columns 【发布时间】:2021-10-25 01:13:30 【问题描述】:我只知道 SQL 的基础知识,最近在工作中偶然发现了这种情况。我很难想象这个问题,但我会尽力解释它。 我有两张桌子:
表 A:
IDA SomeInfo
------- ----------
1 info1
2 info2
3 info3
4 info4
表 B:
IDB IDA VarName VarValue
------- ------- ------- ---------
1 1 Depth 2
2 1 Length 10
3 2 Depth2 3
4 2 Length 12
5 2 Height 35
6 3 Depth2 2
7 3 Length 11
8 3 Height 38
9 4 Depth 4
10 4 Length 16
我需要加入他们才能得到以下结果:
Depth
IDA SomeInfo Depth2 Length Height
------- -------- ------- ------- ---------
1 info1 2 10 0
2 info2 3 12 35
3 info3 2 11 38
4 info4 4 16 0
如您所见,我需要将 B 的行中的两个不同 VarNames 放入一列,并将其他 VarNames 作为不同的列。每个都有各自的 VarValue 和 IDA,然后当 IDA 没有 VarVal 时,它需要为 0。我在我的 c# 字符串查询中有以下代码,当我只需要处理“深度”和“深度2”:
SELECT
A.IDA, A.SomeInfo,
CASE
WHEN (B.VarValue IS NULL) THEN 0
WHEN B.VarName = 'Depth' OR B.VarName = 'Depth2' THEN B.VarValue
END AS Depth
FROM A LEFT JOIN
(
SELECT B.IDA, B.VarName, B.VarValue FROM B
WHERE (B.VarName = 'Depth' OR B.VarName = 'Depth2')
) B ON (A.IDA = B.IDA)
然后我需要添加更多的VarNames,所以我将代码更改如下:
SELECT DISTINCT
A.IDA, A.SomeInfo,
CASE
WHEN (B.VarName = 'Depth' OR B.VarName = 'Depth2') AND B.VarValue IS NULL THEN 0
WHEN B.VarName = 'Depth' OR B.VarName = 'Depth2' THEN B.VarValue
END AS Depth,
CASE
WHEN B.VarName = 'Length' AND B.VarValue IS NULL THEN 0
WHEN B.VarName = 'Length' THEN B.VarValue
END AS Length
CASE
WHEN B.VarName = 'Height' AND B.VarValue IS NULL THEN 0
WHEN B.VarName = 'Height' THEN B.VarValue
END AS Height
FROM A LEFT JOIN
(
SELECT B.IDA, B.VarName, B.VarValue FROM B
WHERE (B.VarName = 'Depth' OR B.VarName = 'Depth2' OR B.VarName = 'Length' OR
B.VarName = 'Height')
) B ON (A.IDA = B.IDA)
但现在我为每个 VarName 获得了一行。我应该怎么做才能完成这项工作?
编辑:这个问题中的两个答案都适用于我给出的示例,但标记的答案是最适合我的答案。我遇到了一个与 DB2 相关的问题,以及数据在 as400 中的结构方式,但我想通了,现在一切正常。感谢 T.S.和 Gordon Linoff 的答案。他们帮了我很多。
【问题讨论】:
【参考方案1】:您可以使用条件聚合:
select a.ida, a.someinfo,
sum(case when varname in ('Depth', 'Depth2') then varvalue end) as depth,
sum(case when varname in ('Length') then varvalue end) as length,
sum(case when varname in ('Height') then varvalue end) as depth
from tablea a left join
tableb b
on a.ida = b.ida
group by a.ida, a.someinfo;
Here 是一个 dbfiddle。
【讨论】:
这适用于我编写的示例,但由于某种原因,当我尝试在我正在开发的应用程序上使用它时,我得到了一些奇怪的异常......(我获取数据的表来自AS400,有点乱)你能详细说明一下这是如何工作的吗?具体来说,总和(case when)。也许如果我完全理解这是如何工作的,我可以解决我的问题。 @ArminAH 。 . .你不明白这其中的哪一部分?如果varvalue
不是数字,您可能想要使用max()
而不是sum()
。
我们为什么要用SUM或者MAX来封装CASE WHEN?我知道 SUM 只是对表达式中的值求和,而 MAX 返回表达式中的最大值。但我不明白这样做的意义。
@ArminAH 。 . .如果没有聚合函数,聚合查询将无法工作。
我明白了。谢谢你。这可能问得太多了,但是,您碰巧知道进行此聚合查询的另一种方法吗?其他人在使用 DB2 iSeries 的聚合查询时遇到了问题,就像我一样。 (具体来说,这篇文章中的 OP link)看起来我也遇到了类似的问题。【参考方案2】:
在伪代码中 - 使用内联视图
select a.IDA, a.SomeInfo, dep.depth, hei.Height, le.Length
from
TableA a left join
(select IDA, VarValue as depth from tableB where varName = 'depth' ) dep
on a.ida = dep.ida letf join
(select IDA, VarValue as height from tableB where varName = 'height' ) hei
on a.ida = hei.ida letf join
(select IDA, VarValue as Length from tableB where varName = 'Length' ) le
on a.ida = le.ida
毫无疑问,还有其他方法。我是老派
我不确定 DB 结构设置是什么。例如,我不知道 id 相同的IDA
可以同时拥有depth
和depth2
。如果只有其中一个值是可能的,那么您可以更改过滤器,如
select IDA, VarValue as depth from tableB where varName in ('depth', 'depth2')
但如果两者都可能,我们需要另一个连接,并在选择中COALESCE
。
Select ...., COALESCE(dep.depth, dep2.depth2) as depth
....
(select IDA, VarValue as depth from tableB where varName = 'depth' ) dep
on a.ida = dep.ida letf join
(select IDA, VarValue as depth2 from tableB where varName = 'depth2' ) dep2
on a.ida = dep2.ida letf join ...
【讨论】:
对您的代码(语法和表名)进行一些调整后,我可以让它运行,但没有完全工作。我在 IDA 2 和 3 的深度列中得到 NULL。这里它应该有“depth2”值。 @ArminAH 我在附加工作的答案中添加了解释以上是关于将两个行值放入一列,将另一行值放入另一列,可以将更多行值添加到列中的主要内容,如果未能解决你的问题,请参考以下文章
使用 Python pandas 根据条件将行值复制到另一列
将行值转换为列,其值来自 spark scala 中的另一列 [重复]