2012-08-03 12 views
5

तालिका में अंतिम नहीं शून्य मान के स्तंभ नाम खोजें इसएक पंक्ति

 
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 LAST 
1 A7 
2 A3 
3 A8 

इस पर कोई मदद की तरह है?

+0

क्या मैं कह सकता हूं "वह स्कीमा भयानक लगती है"? :-) यह एक रिवर्स-प्राथमिकता सशर्त के साथ किया जा सकता है। –

उत्तर

2

इस स्कीमा के बारे में मेरी गलतफहमी के बावजूद, इस "रिवर्स प्राथमिकता" सशर्त पर विचार करें:

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 देखें) में गारंटी दी गई है इसलिए हम बिल्कुल पीछे की ओर inchworm :)

निर्दिष्ट प्रत्येक क्रम में, प्रत्येक WHEN खंड के लिए Boolean_expression का मूल्यांकन करता है।

इसके अलावा, शायद UNPIVOT (या ROLLUP [?] या मैनुअल UNION) का इस्तेमाल किया जा सकता है। यही कारण है, मूल्यों में स्तंभ नाम की नियत सेट पिवट है, तो यह एक साधारण क्वेरी .. कि है, अगर तालिका सामान्यीकृत था, यह आसानी से :-)

select 
    id, 
    max(colName) as lastNonNullColumn 
from <<normalized_derived_table>> 
where colValue is not null 
group by id 
+1

आपकी सीएएसई अभिव्यक्ति में सबसे अच्छा निष्पादन योजना है और कम से कम CPU लेता है। UNPIVOT संचालन के लिए एक महंगा SORT – ErikE

+0

इसकी कामकाजी जुर्माना की आवश्यकता होती है। आप सभी को धन्यवाद। – user1574813

2
यह कैसे के बारे में

किया जा सकता है है? यह डेटा को बदलने के लिए 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 

, SQL Fiddle with Demo

संपादित देखें वास्तव में यह है कि जटिल की जरूरत नहीं है:

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 

देखें SQL Fiddle with Demo

+0

आपके दोनों संस्करण काम करते हैं लेकिन स्तंभ नामों को क्रमबद्ध करने की आवश्यकता होती है (जिसमें ए 10 और ऊपर नहीं है)। मुझे पूरा यकीन है कि ओपी के कॉलम वास्तव में ए 1 - ए 9 नामित नहीं हैं। – ErikE

+0

@ErikE सच है, लेकिन पोस्ट की गई आवश्यकताओं के आधार पर, यह काम करेगा। अगर वे अपनी जरूरतों पर विस्तारित होते हैं जो सहायक होंगे। ओपी कहता है कि तालिका में कॉलम ए 1-ए 9 शामिल थे। – Taryn

+0

पर्याप्त मेला! दिए गए समस्या के लिए यह एक अच्छा जवाब है। – ErikE

1

यहाँ एक छद्म 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; 

हालांकि, जबकि वास्तविक आईओ और सीपीयू हैं प्राकृतिक UNPIVOT विधि की तुलना में बहुत खराब नहीं (कार्य योजना लागू करके बुरा लग रहा है, लेकिन असली सर्वर प्रभाव है कि बहुत खराब नहीं है), यह सबसे अच्छा कलाकार नहीं है। @pst द्वारा दी गई सरल केस अभिव्यक्ति है।

स्तंभ नाम है के रूप में हल हो सकता है मान लिया जाये कि, 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 अभिव्यक्ति संस्करण की तरह बहुत अधिक दिखता है, लेकिन ऐसा नहीं है। यह योजना बिल्कुल चुनिंदा दिखती है, एक टेबल ऑब्जेक्ट प्रति चयन कथन के साथ, और CASE अभिव्यक्ति के रूप में लगभग दो बार CPU लेता है।

परीक्षण किए गए सभी संस्करणों में लॉजिकल रीड की एक ही संख्या का उपयोग होता है, केवल सीपीयू में भिन्न होता है। मैंने परीक्षण करने के लिए 15,000 पंक्तियों का उपयोग किया।

आखिरकार, मैं अच्छी विवेक में नहीं हूं, आपको चेतावनी नहीं देता कि आपकी स्कीमा शायद सबसे अच्छी नहीं है। जबकि मैं यह नहीं बता सकता कि आपका डेटा क्या है, कि आप आखिरी बार खोजने की कोशिश कर रहे हैं शायद कॉलम कुछ जीवन चक्र के समय या चरणों का प्रतिनिधित्व करता है - और यह सही डेटाबेस डिज़ाइन नहीं है। इसके बजाय, डेटा unpivoted स्टोर करें। जब समय आता है कि आपको एक परिणाम सेट की आवश्यकता है जिसे पिवोट किया गया है, तो आप PIVOT कर सकते हैं। और, प्रति आईडी सबसे हालिया मूल्य के लिए पूछताछ थोड़ा आसान हो जाता है!

संबंधित मुद्दे