表查找最后不为空值的列名是这个样子连续
ID A1 A2 A3 A4 A5 A6 A7 A8 A9 1 YE YE YE NULL YE YE YE NULL NULL 2 YE YE YE NULL NULL NULL NULL NULL NULL 3 YE YE YE YE YE YE YE YE NULL
其中ID是主键。
我想连续获取最后不为空值的列名,结果是这样的
ID LAST 1 A7 2 A3 3 A8
任何帮助?
表查找最后不为空值的列名是这个样子连续
ID A1 A2 A3 A4 A5 A6 A7 A8 A9 1 YE YE YE NULL YE YE YE NULL NULL 2 YE YE YE NULL NULL NULL NULL NULL NULL 3 YE YE YE YE YE YE YE YE NULL
其中ID是主键。
我想连续获取最后不为空值的列名,结果是这样的
ID LAST 1 A7 2 A3 3 A8
任何帮助?
尽管我对这个模式的疑虑,认为这是“反向优先”条件:
select
id,
case
-- first match terminates search
when A9 is not null then 'A9'
when A8 is not null then 'A8'
when A7 is not null then 'A7'
..
else null
as lastNonNullColumn
from ..
评价的顺序TSQL(见CASE)保证,所以我们只尺蠖向后:)
按照指定的顺序,为每个WHEN子句计算布尔表达式。
另外,或许UNPIVOT
(或ROLLUP
[?]或手动UNION
)可以被使用。也就是说,转动固定集列名的入值,那么它是一个简单的查询。即,如果表是标准化的,这可以很容易地:-)
select
id,
max(colName) as lastNonNullColumn
from <<normalized_derived_table>>
where colValue is not null
group by id
您的CASE表达式具有最佳的执行计划并且占用最少的CPU。 UNPIVOT行动需要昂贵的SORT – ErikE 2012-08-03 19:51:44
其工作正常。谢谢你们。 – user1574813 2012-08-04 09:18:38
这个怎么样呢?它使用UNPIVOT
来转换数据,然后您将选择非空/空白的最大最大值。
;with cte as
(
select id
, last
, value
, row_number() over(partition by id order by last) rn
from
(
select id,
isnull(a1, '') as a1,
isnull(a2, '') as a2,
isnull(a3, '') as a3,
isnull(a4, '') as a4,
isnull(a5, '') as a5,
isnull(a6, '') as a6,
isnull(a7, '') as a7,
isnull(a8, '') as a8,
isnull(a9, '') as a9
from t
) x
unpivot
(
value
for last in (a1, a2, a3, a4, a5, a6, a7, a8, a9)
) u
)
select id, max(last) as last
from cte
where value != ''
group by id
编辑,其实它并不需要那么复杂:
select id
, max(last) last
from
(
select id, a1, a2, a3, a4, a5, a6, a7, a8, a9
from t
) x
unpivot
(
value
for last in (a1, a2, a3, a4, a5, a6, a7, a8, a9)
) u
group by id
这里是一个伪UNPIVOT版本,让您指定列的顺序(如果列名不按其位置排序)。
SELECT
T.ID,
X.Name
FROM
T
CROSS APPLY (
SELECT TOP 1 Name FROM (
VALUES (1, 'A1', T.A1), (2, 'A2', T.A2), (3, 'A3', T.A3), (4, 'A4', T.A4),
(5, 'A5', T.A5), (6, 'A6', T.A6), (7, 'A7', T.A7), (8, 'A8', T.A8),
(9, 'A9', T.A9)
) X (Pos, Name, Col)
WHERE Col IS NOT NULL
ORDER BY X.Pos DESC
) X;
然而,在实际的IO和CPU都没有比自然UNPIVOT方法差得多(执行计划看起来不错,但真正的服务器的影响是不是差很多),这是不是最好的表演。 @pst给出的简单CASE表达式是。
假设列名可以被作为排序,在UNPIVOT可以简化甚至更多:
SELECT ID, Max(Last)
FROM T UNPIVOT (Value FOR Last IN (A1, A2, A3, A4, A5, A6, A7, A8, A9)) U
GROUP BY ID;
最后,这里是一个疯狂的版本,我想到的是不幸的性能比别人差:
SELECT
T.ID,
Coalesce(
(SELECT 'A9' WHERE T.A9 IS NOT NULL),
(SELECT 'A8' WHERE T.A8 IS NOT NULL),
(SELECT 'A7' WHERE T.A7 IS NOT NULL),
(SELECT 'A6' WHERE T.A6 IS NOT NULL),
(SELECT 'A5' WHERE T.A5 IS NOT NULL),
(SELECT 'A4' WHERE T.A4 IS NOT NULL),
(SELECT 'A3' WHERE T.A3 IS NOT NULL),
(SELECT 'A2' WHERE T.A2 IS NOT NULL),
(SELECT 'A1' WHERE T.A1 IS NOT NULL)
) LastNotNullColumn
FROM T
ORDER BY ID
从理论上讲,引擎可以提出一个看起来更像CASE表达式版本的计划,但事实并非如此。该计划看起来非常疯狂,每个select语句有一个表对象,并且需要大约两倍于CASE表达式的CPU。
我测试过的所有版本都使用相同数量的逻辑读取,仅在CPU中有所不同。我用了15,000行来测试。
最后,我不能良心没有警告你,你的模式可能不是最好的。虽然我无法告诉你的数据是什么,但你试图找到最后一个数据可能表明这些列代表了某个生命周期的时间或阶段 - 这不正确的数据库设计。相反,请将数据存储为未知状态。当时间到了,你需要一个枢轴结果集,你可以PIVOT。而且,查询每个ID的最新值会变得更简单一些!
我可以说“模式看起来很糟糕”吗? :-)可以使用反向优先条件来完成。 – 2012-08-03 18:44:14