SQL服务器获取某行值作为列值
SQL Server get a certain row value as a column value
我有一个像这样的table:
| machine | type | value | id |
+-----------+--------+-----------+------+
| 1 | a | 0.34 | 1 |
| 1 | b | 0.23 | 2 |
| 1 | b | 0.26 | 3 |
| 1 | b | 0.35 | 4 |
| 1 | a | 0.15 | 5 |
| 1 | b | 0.45 | 6 |
| 1 | b | 0.55 | 7 |
并且我想获得一个 table,其中类型为“a”的行作为列(id 在这种情况下不相关)。例如:
| machine | value | value_col |
+-----------+--------+-----------+
| 1 | 0.23 | 0.34 |
| 1 | 0.26 | 0.34 |
| 1 | 0.35 | 0.34 |
| 1 | 0.45 | 0.15 |
| 1 | 0.55 | 0.15 |
我尝试了 SQL 服务器数据透视功能,但无法获得所需的结果。
分三步搞定,感觉还有更简洁的方法(但想不出来)
- 创建一个标识符来关联应该共享一个
a
值的所有行
- 使用 window 函数将
a
值复制到分区的其余部分
- 过滤以仅包含
b
行
例如...
WITH
a_partitioned AS
(
SELECT
*,
SUM(CASE WHEN type='a' THEN 1 ELSE 0 END) OVER (PARTITION BY machine ORDER BY id) AS a_partition
FROM
your_table
),
a_value_spread AS
(
SELECT
*,
MAX(CASE WHEN type = 'a' THEN value END) OVER (PARTITION BY machine, a_partition) AS a_value
FROM
a_partitioned
)
SELECT
*
FROM
a_value_spread
WHERE
type = 'b'
演示:https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=9037c0d3e6d46e05ecbcfdd3777808cd
编辑
这是我的 REALLY 肤浅的尝试,尝试用哪个答案可能具有最低的处理开销...
关联子查询版本中,数据的扫描占总成本的4%
- 所以,整个查询 'costs' ~20 索引扫描
解析函数版中,数据的扫描占总成本的12%
- 所以,整个查询 'costs' ~8.3 索引扫描
虽然这是一个非常小的数据集,而且是一个非常随意构造的数据集。
- 我会运行根据您的实际数据进行实际分析
- IF 性能很重要
(如果相关子查询方式是'fast enough',一定要用那个。)
使用CROSS APPLY()
获取最后的a
值
select t.machine, t.value, v.value_col
from tbl t
cross apply
(
select top 1 value_col = value
from tbl x
where x.id < t.id
and x.type = 'a'
order by id desc
) v
where t.type = 'b'
我有一个像这样的table:
| machine | type | value | id |
+-----------+--------+-----------+------+
| 1 | a | 0.34 | 1 |
| 1 | b | 0.23 | 2 |
| 1 | b | 0.26 | 3 |
| 1 | b | 0.35 | 4 |
| 1 | a | 0.15 | 5 |
| 1 | b | 0.45 | 6 |
| 1 | b | 0.55 | 7 |
并且我想获得一个 table,其中类型为“a”的行作为列(id 在这种情况下不相关)。例如:
| machine | value | value_col |
+-----------+--------+-----------+
| 1 | 0.23 | 0.34 |
| 1 | 0.26 | 0.34 |
| 1 | 0.35 | 0.34 |
| 1 | 0.45 | 0.15 |
| 1 | 0.55 | 0.15 |
我尝试了 SQL 服务器数据透视功能,但无法获得所需的结果。
分三步搞定,感觉还有更简洁的方法(但想不出来)
- 创建一个标识符来关联应该共享一个
a
值的所有行 - 使用 window 函数将
a
值复制到分区的其余部分 - 过滤以仅包含
b
行
例如...
WITH
a_partitioned AS
(
SELECT
*,
SUM(CASE WHEN type='a' THEN 1 ELSE 0 END) OVER (PARTITION BY machine ORDER BY id) AS a_partition
FROM
your_table
),
a_value_spread AS
(
SELECT
*,
MAX(CASE WHEN type = 'a' THEN value END) OVER (PARTITION BY machine, a_partition) AS a_value
FROM
a_partitioned
)
SELECT
*
FROM
a_value_spread
WHERE
type = 'b'
演示:https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=9037c0d3e6d46e05ecbcfdd3777808cd
编辑
这是我的 REALLY 肤浅的尝试,尝试用哪个答案可能具有最低的处理开销...
关联子查询版本中,数据的扫描占总成本的4%
- 所以,整个查询 'costs' ~20 索引扫描
解析函数版中,数据的扫描占总成本的12%
- 所以,整个查询 'costs' ~8.3 索引扫描
虽然这是一个非常小的数据集,而且是一个非常随意构造的数据集。
- 我会运行根据您的实际数据进行实际分析
- IF 性能很重要
(如果相关子查询方式是'fast enough',一定要用那个。)
使用CROSS APPLY()
获取最后的a
值
select t.machine, t.value, v.value_col
from tbl t
cross apply
(
select top 1 value_col = value
from tbl x
where x.id < t.id
and x.type = 'a'
order by id desc
) v
where t.type = 'b'