2012-05-25 12 views
5

मैं एक Oracle प्रश्न हैंएसक्यूएल सर्वर: ऑरैकल की नकल कैसे करें dense_rank क्वेरी रखें?

select max(m.id), 
     m.someId keep (DENSE_RANK FIRST ORDER BY m.UpdateDate desc) 
from MyTable m 
groupBy m.someId 

जो इस तरह के डेटा के लिए:

2 10 
4 20 
6 30 

तो, हर someId के लिए यह नवीनतम अद्यतन किया खोज करता है:

id UpdateDate someId 
1 20-01-2012 10 
2 20-01-2012 10 
3 01-01-2012 10 
4 10-02-2012 20 
5 01-02-2012 20 
6 01-04-2012 30 

मुझे बिल्कुल इस वापस आ जाएगी और उपयुक्त id वापस करता है। (और यदि नवीनतम तिथियों के लिए कई आईडी हैं तो यह नवीनतम आईडी लेता है)।

लेकिन SQL सर्वर के लिए यह क्वेरी वैसे ही काम करेगी? मेरा मतलब यह निर्माण keep (dense_rank first order by ..) है?

उत्तर

8

मुझे नहीं लगता कि आपकी विशेष क्वेरी SQL सर्वर चलाएगी। लेकिन आप ऐसा करने से एक ही परिणाम प्राप्त कर सकते हैं:

SELECT id, SomeId 
FROM ( SELECT *, ROW_NUMBER() OVER(PARTITION BY someId ORDER BY UpdateDate DESC, id DESC) Corr 
     FROM MyTable) A 
WHERE Corr = 1 
+0

मैं बिना यह एक इसे प्राप्त न करें .. इसे 'आईडीआईडी ​​द्वारा समूह' के बिना कैसे काम करना चाहिए? मेरी क्वेरी हमेशा मुझे 3 प्रविष्टियां लौटाएगी क्योंकि मेरे पास तालिका में 3 अलग-अलग हैं। आपकी क्वेरी परिणाम लौटाएगी जो अलग-अलग आईडीएस की मात्रा पर निर्भर नहीं है, इसलिए यह गलत होना चाहिए? – javagirl

+1

@javagirl - क्या आपने पहले इसे आजमाया था ?, यह काम करेगा। यह कैसे काम करता है, विश्लेषणात्मक कार्यों ('ओवर() ...') में 'भाग' हो सकता है और पूरे स्तर पर समूह करने की आवश्यकता नहीं है। यह तालिका पर मौजूद प्रत्येक पंक्ति के लिए एक मूल्य देता है। – Lamak

+0

मैंने मूल डेटा को गलत तरीके से पढ़ा। समस्या आईडी के बजाए विभाजन में कुछ डालकर तय की जाती है। –

1

एसक्यूएल सर्वर का समर्थन नहीं करता "रखना" का निर्माण, ताकि आप एक सबक्वेरी उपयोग करने की आवश्यकता:

select m.* 
from (select *, row_number() over (partition by m.someid ORDER BY m.UpdateDate desc) as seqnum 
     from MyTable m 
    ) m 
where seqnum = 1 

यह प्रत्येक के लिए पहली पंक्ति पाता है सबसे हालिया अपडेटडेट के साथ एमआईडी। फिर यह उस पंक्ति को बाहरी क्वेरी में चुनता है। ध्यान दें कि आपको इस विधि के साथ समूह की आवश्यकता नहीं है।

+0

पर नहीं लिया है, मुझे यह नहीं मिला .. इसे बिना किसी समूह द्वारा 'समूह' के बिना कैसे काम करना चाहिए। ? मेरी क्वेरी हमेशा मुझे 3 प्रविष्टियां लौटाएगी क्योंकि मेरे पास तालिका में 3 अलग-अलग हैं। आपकी क्वेरी परिणाम लौटाएगी जो अलग-अलग आईडीएस की मात्रा पर निर्भर नहीं है, इसलिए यह गलत होना चाहिए? – javagirl

+0

यह काम नहीं करेगा, परिणामस्वरूप प्रत्येक आईडी के प्रति एक पंक्ति होगी, और यही वह नहीं है जो ओप चाहता है। – Lamak

3

मैं वापस लौटता हूं और इस प्रश्न और उत्तर पर लौटता हूं। दुर्भाग्यवश कई स्थितियां हैं जब "रैंकिंग के लिए विंडो फ़ंक्शन" का उपयोग करके माइग्रेशन बहुत जटिल हो जाता है। उन स्थितियों हैं:

  1. कई-रखें DENSE_RANK विभिन्न आदेशों के आधार पर ओरेकल क्वेरी के चुनिंदा हिस्से में निर्माण ग्रुपिंग के सेट/रोलअप्स द्वारा
  2. समूहीकरण

इसलिए मैं इस सवाल का जवाब अतिरिक्त करने के लिए जोड़ देगा जानकारी। मूल डेटा SQLFIDDLE: http://sqlfiddle.com/#!6/e5c6d/6

1. पढ़ना ओरेकल समारोह:

select max(m.id), m.someId keep (DENSE_RANK FIRST ORDER BY m.UpdateDate desc) 
from MyTable m 
groupBy m.someId 

वहाँ हम समूह में m.id की अधिकतम का चयन करें (someId, अद्यतन किया) जहां अद्यतन किया सबसे बड़ी यह समूह (someId है)

2. सीधे आगे रास्ता त्रुटि के कारण काम नहीं करता: स्तंभ 'MyTable.UpdateDate' का चयन में अमान्य है सूची क्योंकि यह या तो कुल कार्य या ग्रुप बाय क्लॉज में निहित नहीं है।

SELECT FIRST_VALUE(id) OVER(PARTITION BY someId ORDER BY UpdateDate DESC, id DESC) first_in_orderedset , someId 
FROM MyTable 
GROUP BY someId 

3. improoved 'सीधे आगे' noneffective

SELECT someId, MIN(first_in_orderedset) 
FROM 
(SELECT FIRST_VALUE(id) OVER(PARTITION BY someId ORDER BY UpdateDate DESC, id DESC) first_in_orderedset , someId 
    FROM MyTable) t 
GROUP BY someId; 

4 है। पार लागू होते हैं: ऑरेकल:: http://sqlfiddle.com/#!4/c943c/23 एसक्यूएल सर्वर:

SELECT grouped.someId, orderedSet.FirstUpdateDate, maxInSet.first_in_orderedset FROM 
(
    SELECT mt.someId 
    FROM MyTable mt 
    GROUP BY mt.someId 
) grouped CROSS APPLY 
( 
    SELECT top 1 mt2.UpdateDate as FirstUpdateDate 
    FROM MyTable mt2 
    WHERE mt2.someId=grouped.someId 
    ORDER BY UpdateDate desc 
) orderedSet CROSS APPLY 
( 
    SELECT max(mt3.id) as first_in_orderedset 
    FROM MyTable mt3 
    WHERE mt3.someId=grouped.someId and mt3.UpdateDate=orderedSet.FirstUpdateDate 
) maxInSet; 

5. अब और अधिक जटिल तालिका मिलता है और अधिक जटिल क्वेरी की सुविधा देता है http://sqlfiddle.com/#!6/dc7fb/1/0 (डेटा pregenerated है और यह दोनों सैंडबॉक्स में एक ही है -

CREATE TABLE AlarmReports (
    id int PRIMARY KEY, 
    clientId int, businessAreaId int , projectId int, taskId int, 
    process1Spent int, process1Lag int, process1AlarmRate varchar2(1) null, 
    process2Spent int, process2Lag int, process2AlarmRate varchar2(1) null, 
    process3Spent int, process3Lag int, process3AlarmRate varchar2(1) null 
) 

ओरेकल क्वेरी:

यह परिणाम) तालिका की तुलना करने के लिए आसान है
SELECT clientId, businessAreaId, projectId, 
    sum(process1Spent), 
    sum(process2Spent), 
    sum(process3Spent), 
    MIN(process1AlarmRate) KEEP (DENSE_RANK FIRST ORDER BY process1Lag DESC), 
    MIN(process2AlarmRate) KEEP (DENSE_RANK FIRST ORDER BY process2Lag DESC), 
    MIN(process3AlarmRate) KEEP (DENSE_RANK FIRST ORDER BY process3Lag DESC) 
FROM AlarmReports 
GROUP BY GROUPING SETS ((),(clientId),(clientId, projectId),(businessAreaId),(clientId,businessAreaId)) 

SQL क्वेरी:

(to be continued) 
वास्तव में वहाँ

मैं अपने कस्टम सी # साथ wroted कुल डाल करने के लिए योजना बनाई है। अगर कोई दिलचस्पी लेता है, तो कृपया मुझसे संपर्क करें ... कस्टम समेकित ऐसी समस्याओं का सबसे अच्छा समाधान है लेकिन यह वर्चर्स लम्बाई के मामले में अवांछित नहीं है। प्रत्येक वर्कर लंबाई के लिए आपको "विशेष" aggreate फ़ंक्शन

0

बनाने के लिए बाध्य किया जाएगा जो पूरी तरह से काम करेगा। पहले कोशिश करें, फिर बहस करें। आप एक से अधिक आदेश आप इस (Oracle पर किए गए उदाहरण) कर सकते हैं द्वारा जब:

- dense_rank

WITH a AS (SELECT 1 s1, 4 s2, 'a' c, 10 g FROM dual UNION all 
      SELECT 2 s1, 2 s2, 'b' c, 10 g FROM dual UNION ALL 
      SELECT 3 s1, 1 s2, 'c' c, 20 g FROM dual UNION ALL 
      SELECT 4 s1, 3 s2, 'd' c, 20 g FROM dual) 
SELECT g, 
     MAX(c) KEEP (DENSE_RANK FIRST ORDER BY s1) s1, 
     MAX(c) KEEP (DENSE_RANK FIRST ORDER BY s2) s2 
    FROM a 
GROUP BY g 

रखें के साथ इस एक - dense_rank रखने

WITH a AS (SELECT 1 s1, 4 s2, 'a' c, 10 g FROM dual UNION all 
       SELECT 2 s1, 2 s2, 'b' c, 10 g FROM dual UNION ALL 
       SELECT 3 s1, 1 s2, 'c' c, 20 g FROM dual UNION ALL 
       SELECT 4 s1, 3 s2, 'd' c, 20 g FROM dual) 
SELECT g, 
     MAX(DECODE(s1, 1, c)) s1, 
     MAX(DECODE(s2, 1, c)) s2 
    FROM (SELECT g,c, 
       ROW_NUMBER() OVER (PARTITION BY g ORDER BY s1) s1, 
       ROW_NUMBER() OVER (PARTITION BY g ORDER BY s2) s2 
      FROM a) b 
GROUP BY g 
संबंधित मुद्दे