2012-05-25 13 views
5

私はOracleのクエリこのようなデータのためにSQL Server:Oracleのdense_rankクエリを真似る方法を教えてください。

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

持っている:それは最新updateDateを検索すべてのsomeIdのために、そう

2 10 
4 20 
6 30 

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を返します。 (最新の日付のIDが複数ある場合は、最新のIDが必要です)。

しかし、SQLサーバーの場合、このクエリは同じ方法で動作しますか?私はこの建設を意味するkeep (dense_rank first order by ..)

答えて

8

特定のクエリでSQL Serverが実行されるとは思われません。しかし、あなたはこれをやって同じ結果を得ることができます。

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 

これは、それぞれの最初の行を見つけます:

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

Iを維持せずに、この1をそれを得ることはありません..それはどのように 'いくつかのグループ'なしで動作するはずだったのですか?テーブルに3つの異なるsomeIdsがあるので、私のクエリは常に私に3つのエントリを返します。あなたのクエリは、異なるsomeIdsの量に依存しない結果を返すので、間違っているはずですか? – javagirl

+1

@javagirl - 最初に試しましたか?それはうまくいくでしょう。どのように機能するかについては、分析関数( 'OVER()...')は 'PARTITION BY'を持つことができ、全体のレベルでグループ化する必要はありません。テーブルにあるすべての行の値を返します。 – Lamak

+0

元のデータを誤読しました。この問題はididではなくsomeidをパーティションに入れることで修正されています。 –

1

SQL Serverは、サブクエリを使用する必要があるので、構築「続ける」をサポートしていません。最新のUpdateDateを持つm.id。次に、外部クエリの行を選択します。この方法でグループを作成する必要はありません。

+0

私はそれを取得しない..どのように 'someId' ?テーブルに3つの異なるsomeIdsがあるので、私のクエリは常に私に3つのエントリを返します。あなたのクエリは、異なるsomeIdsの量に依存しない結果を返すので、間違っているはずですか? – javagirl

+0

これはうまくいきません。その結果、各IDごとに1つの行があり、それはopが望むものではありません。 – Lamak

3

この質問と回答に戻ります。残念ながら、「ランク付けのためのウィンドウ関数」を使用する移行が非常に複雑になるいくつかの状況があります。

セット/ロールアップをグループ化することによって、異なる順序に基づいて のOracleクエリの選択部分に

  • グループ

    1. 多くKEEP-DENSE_RANK構造そこで私は、追加の答えに追加します。これらの状況があります情報。 オリジナルデータ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、UpdateDate)UpdateDateが最大のそれはグループ(someIdがあります)

      2.まっすぐ進むべき道はエラーのためが動作しません:列「MyTable.UpdateDateは」選択は無効ですリストは集約関数またはGROUP BY句のいずれにも含まれていないためです。 '直進' improoved

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

      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 noneffectiveあります。クロスが適用されます。

      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.は今より複雑なテーブルと、より複雑なクエリを取得することができます: ORACLE:http://sqlfiddle.com/#!4/c943c/23 のSQL SERVER:http://sqlfiddle.com/#!6/dc7fb/1/0 (データは事前​​に生成され、それは両方のサンドボックスで同じです -

      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 
      ) 
      

      Oracleのクエリ:

      結果) 表を比較するのは簡単です
      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) 
      

      実際にそこに私は、C#でwroted私のカスタム集計を置くことを計画しています。もし誰かが興味があれば、私に連絡してください...カスタム集計は、このような問題の最良の解決策ですが、それはvarcharの長さの点で未妥協ではありません。 varcharの長さごとに、 "特殊な" aggreate関数を作成する義務があります

  • 0

    これは絶対に動作します。最初に試してから、議論してください。 あなたは、この(Oracleで作られた一例)を行うことができますすることで、複数のオーダーがある場合:

    -

    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キープして、この1 - 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 
    
    関連する問題