8

Oracleクエリがあります

select max(m.id),
       m.someId keep (DENSE_RANK FIRST ORDER BY m.UpdateDate desc) 
from MyTable m 
groupBy m.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

正確にこれを返します:

2 10
4 20
6 30

したがって、someIdごとに、最新のupdateDateを検索し、適切なを返しますid。(そして、最新の日付に複数のIDがある場合は、最新のIDを使用します)。

しかし、SQLサーバーの場合、このクエリは同じように機能しますか?私はこの構造を意味しkeep (dense_rank first order by ..)ますか?

4

5 に答える 5

8

特定のクエリでSQLServerが実行されるとは思いません。ただし、これを行うと同じ結果を得ることができます。

SELECT id, SomeId
FROM (  SELECT *, ROW_NUMBER() OVER(PARTITION BY someId ORDER BY UpdateDate DESC, id DESC) Corr
        FROM MyTable) A
WHERE Corr = 1
于 2012-05-25T15:20:27.127 に答える
3

私はこの質問と答えに戻って戻ります。残念ながら、「ランキングのウィンドウ関数」を使用した移行が非常に複雑になる状況がいくつかあります。それらの状況は次のとおりです。

  1. さまざまな順序に基づくOracleクエリの選択部分の多くのKEEP-DENSE_RANK構造
  2. セット/ロールアップのグループ化によるグループ化

したがって、回答に追加情報を追加します。元のデータSQLFIDDLE:http ://sqlfiddle.com/#!6/e5c6d/6

1. oracle関数の読み取り:

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

そこで、グループ(someId、UpdateDate)で最大のm.idを選択します。ここで、UpdateDateはグループ(someId)で最大です。

2.エラーのため、単純な方法が機能しません。列'MyTable.UpdateDate'は、集計関数またはGROUP BY句のいずれにも含まれていないため、選択リストでは無効です。

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

3.改善された「まっすぐ進む」は効果がありません

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.クロスアプライ:

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#で記述したカスタムアグリゲートを配置する予定です。誰かが興味を持っているなら、私に連絡してください...カスタムアグリゲートはそのような問題の最良の解決策ですが、varcharの長さの点で不自然ではありません。varcharの長さごとに、「特殊な」集計関数を作成する必要があります。

于 2014-03-12T17:22:58.543 に答える
2

それは絶対に機能します。最初に試してから、議論してください。複数の注文がある場合は、これを行うことができます(Oracleで作成された例)。

--これはkeepdensity_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
于 2015-08-20T15:26:44.953 に答える
1

SQL Serverは「keep」構造をサポートしていないため、サブクエリを使用する必要があります。

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

これにより、最新のUpdateDateを持つ各m.idの最初の行が検索されます。次に、外部クエリでその行を選択します。このメソッドではgroupbyは必要ないことに注意してください。

于 2012-05-25T15:25:01.330 に答える
0

誰かがPostgresでOracleKEEPDENSE_RANKシミュレーションを探す場合:

CREATE TABLE myt (
  "id" INTEGER,
  "update_date" timestamp,
  "some_id" INTEGER
);

INSERT INTO myt
  ("id", "update_date", "some_id")
VALUES
  ('1', '2012-01-20', '10'),
  ('2', '2012-01-20', '10'),
  ('3', '2012-01-01', '10'),
  ('4', '2012-10-02', '20'),
  ('5', '2012-01-02', '20'),
  ('6', '2012-01-04', '30');                         


select
    some_id, 
    (array_agg(id order by update_date desc, id desc))[1]
from myt
group by some_id
order by some_id

ここに画像の説明を入力してください

于 2019-04-11T04:26:12.663 に答える