表查找最後不爲空值的列名是這個樣子連續
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