4

「お気に入りのプログラミング漫画」が何であるかを知る以外に、stackoverflowが役立つことはわかっていました:P

これは、 Bill Karwinによって受け入れられた回答です。

助けてくれてありがとう(私はあなたに二重投票したい)

私のクエリは次のようになりました(これが本当のクエリです)

SELECT 
    accepted.folio,
    COALESCE( inprog.activityin, accepted.activityin ) as activityin,
    inprog.participantin,
    accepted.completiondate 
FROM performance accepted
    LEFT OUTER JOIN performance inprog 
        ON( accepted.folio = inprog.folio 
            AND inprog.ACTIVITYIN 
            IN ( 4, 435 )                    -- both are ids for inprogress
            AND inprog.PARTICIPANTIN != 1  ) -- Ignore the "bot" participant
    LEFT OUTER JOIN performance closed
        ON( accepted.folio = closed.folio 
            AND closed.ACTIVITYIN IN ( 10,436, 4, 430  ) )  -- all these are closed or cancelled
WHERE accepted.ACTIVITYIN IN ( 3, 429 )      --- both are id for new 
AND accepted.folio IS NOT NULL
AND closed.folio IS NULL;

あとは、人間が読めるレポートを作成するために、他のテーブルと結合する必要があります。


元の投稿

こんにちは。

6時間くらい悩んでいます。DBクエリを使用するようになりました(私の長年の宿敵)

次のようないくつかのフィールドを持つデータテーブルがあります。

table performance( 
     identifier varchar, 
     activity    number, 
     participant number, 
     closedate   date, 
)

チケットの履歴を追跡するために使用されます

識別子: ( NAF0000001 ) のような顧客 ID です。

activity : チケットがどこにあるかの fk です (新規、進行中、拒否、クローズなど)

参加者: その時点でチケットに参加している人の fk です。

closedate : そのアクティビティが終了した日付です。

編集:終了日ではなく「完了日」と言うべきでした。これはアクティビティが完了した日付であり、チケットがクローズされたときは必要ありません。

たとえば、典型的な履歴は次のようになります。

識別子|活動|参加者|締め切り日
-------------------------------------------
NA00000001| 1| 1|2008/10/08 15:00|
-------------------------------------------
NA00000001| 2| 2|2008/10/08 15:20|
-------------------------------------------
NA00000001| 3| 2|2008/10/08 15:40|
-------------------------------------------
NA00000001| 4| 4|2008/10/08 17:05|
-------------------------------------------

参加者 1=ジョン、2=スコット、3=マイク、4=ロブ

および活動 1=新規、2=進行中、3=承認待ち、4=終了

など。そして、他の何十もの無関係な情報。

さて、私の問題は次のとおりです。

チケットがいつオープンされ、いつクローズされたかを知ることができるクエリを作成することができました

それはこのようなものです:

 select 
     a.identifier,
     a.participant,
     a.closedate as start,
     b.closedate as finish      
from 
    performance a,
    performance b
where
    a.activity = 1 -- new
    and b.activity = 4 -- closed
    and a.identifier = b.identifier

しかし、どのチケットがクローズされておらず、誰が出席しているのかわかりません。

これまでのところ、次のようなものがあります。

 select 
     a.identifier,
     a.participant,
     a.closedate as start
from 
    performance a        
where
    a.activity = 1 -- new
    and a.identifier not in ( select identifier from performance where activity = 4 ) --closed

つまり、開始した ( new = 1 ) が閉じていない ( closed = 4 ) すべての人を教えてください。

しかし、ここでの大きな問題は、チケットを開いた参加者を出力することですが、それに参加している参加者が必要です。そこで、「進行中」のアクティビティをクエリに追加します。

 select 
     a.identifier,
     a.participant,
     a.closedate as start
from 
    performance a,
    performance b        
where
    a.activity = 1 -- new        
    and a.identifier not in ( select identifier from performance where activity = 4 ) --closed
    and b.identifier = a.identifier
    and b.activity = 2  -- inprogress..

しかし、「新規」にあるすべての行が「進行中」であるとは限らず、そのクエリではそれらすべてを削除します。

必要なのは、すべての「進行中」の参加者を表示することです。チケットが「進行中」でない場合は、空として表示されます。

のようなもの

    識別子|活動|参加者|締め切り日
-------------------------------------------
NA00000002| 1| |2008/10/08 15:00|
-------------------------------------------
NA00000003| 1| |2008/10/08 15:20|
-------------------------------------------
NA00000004| 1| |2008/10/08 15:40|
-------------------------------------------
NA00000005| 2| 4|2008/10/08 15:40|
-------------------------------------------
NA00000006| 2| 4|2008/10/08 15:40|

この場合

NA002、NA003、NA004は「新規」のため、参加者は表示されません

その間

NA005 と NA006 は "inprgress (act = 2 )" であり、rob (参加者 4 ) が参加しています。

だから、左外部結合と呼ばれるものがあったことを覚えていますが、私はそれを決して理解していません。私が知りたいのは、「進行中」および「新規」であり、閉じられていない識別子を取得する方法です。

少し休むと頭がすっきりするのではないでしょうか。誰かがそれを行う方法を知っていれば、私はそれを感謝します。

ところで、私は試しました:

 select 
     a.identifier,
     a.participant,
     a.closedate as start
from 
    performance a
    left outer join
    performance b  
    on      
    b.identifier = a.identifier
where
    a.activity = 1 -- new        
    and a.identifier not in ( select identifier from performance where activity = 4 ) --closed
    and b.activity = 2  -- inprogress..

しかし、前と同じ結果が得られます(「新しい」レコードのみをドロップします)

4

9 に答える 9

3

通常、それらを記述するより良い方法は、EXISTS を使用することです。最初のものは次のようになります。

select * from performance p1
where not exists 
    ( select * from performance p2 
      where p2.identifier = p1.identifier and p2.activity = 4 )

この方法により、潜在的に で識別子の膨大なリストを作成する必要がなくなり、performance.identifier でキー付きルックアップを実行できます(select identifier from performance where activity=4)

于 2008-10-08T23:40:37.367 に答える
3

このようなことを試してください(私はテストしていません):

SELECT p_new.identifier, COALESCE(p_inprog.activity, p_new.activity) AS activity,
  p_inprog.participant, COALESCE(p_inprog.closedate, p_new.closedate) AS closedate
FROM performance p_new
  LEFT OUTER JOIN performance p_inprog 
    ON (p_new.identifier = p_inprog.identifier AND p_inprog.activity = 2)
  LEFT OUTER JOIN performance p_closed 
    ON (p_new.identifier = p_closed.identifier AND p_closed.activity = 4)
WHERE p_new.activity = 1
  AND p_closed.identifier IS NULL;

外部結合は実際よりも難しいと人々は信じていると思います。例えば:

A LEFT OUTER JOIN B ON (...condition...)

これは、B に一致する行があるかどうかに関係なく、A からすべての行を返します。B に一致する行がない場合は、A のその行の結果セットですべての列 B.* を NULL として扱います。結合条件は式にすることができます。 B の行が満たす必要があること、または満たしていない場合は結合に含まれません。したがって、A のより多くの行がソロになります。

于 2008-10-09T00:07:14.427 に答える
2

これでいいと思います。

最初の部分は、新規であり、クローズされておらず、進行中でもないすべてのレコードを取得します。2 番目の部分は、進行中のすべてのレコードを取得します。次にそれらを結合します。このクエリを 'SELECT * FROM' で囲むことにより、識別子で並べ替えることもできます。

select 
  a.identifier,
  a.participant,
  a.closedate as start
from 
  performance a
where
  a.activity = 1
  and not exists ( select identifier 
                   from performance b 
                   where b.activity = 4 
                   and b.identifier = a.identifier) 
  and not exists ( select identifier 
                   from performance c 
                   where c.activity = 2 
                   and c.identifier = a.identifier) 
UNION ALL
select 
  a.identifier,
  a.participant,
  a.closedate as start
from 
  performance a
where
  a.activity = 2
  and not exists ( select identifier 
                   from performance b 
                   where b.activity = 4 
                   and b.identifier = a.identifier); 
于 2008-10-09T00:00:49.960 に答える
1

これはどう:

SELECT * FROM (
  SELECT identifier,
         MAX(activity) activity,
         MAX(participant) KEEP (DENSE_RANK LAST ORDER BY activity)
    FROM performance
    GROUP BY identifier
)
WHERE activity in (1,2)

内部クエリは、各チケットとそれに対応する参加者の最新のアクティビティを提供します。外側のクエリは、アクティビティが「新規」または「進行中」のものにこれをフィルタリングします。

私は DENSE_RANK 関数が大好きです。

于 2008-10-09T13:47:21.273 に答える
1

必要なのは、最も古いレコード (おそらくアクティビティ = 1 のレコードであるとは限りません) と最新のレコード (アクティビティ番号に関係なく) であることをお勧めします。最新のレコードのアクティビティが 4 の場合、チケットはクローズされています。それ以外の場合、参加者はチケットの現在の所有者です。チケットを再度開くことができる場合、アクティビティ = 4 で照合するだけでバグが発生する可能性があります。

実際、あなたの例に基づいて、最も古いレコードさえ必要ないかもしれません。以下はどうでしょう。

SELECT
        identifier,
        activity,
        participant,
        closedate
    FROM
        performance a
    WHERE
        (a.identifier, a.closedate) in
            (select b.identifier, max(b.closedate)
                from performance b
                group by b.identifier
            )
;
于 2008-10-09T01:11:00.710 に答える
0

まず、複数のチケットを同時に開いている顧客を持つことができる場合、設計上の問題が発生する可能性があります。理想的には ticket_id を持っている必要があり、その後、identifier の代わりに ticket_id を使用して Andy のクエリを実行できます。

于 2008-10-08T23:49:06.473 に答える
0

クローズされていないチケット:

select identifier as closed_identifier 
  from performance where identifier not exists
  (select identifier from performance where activity=4)

参加チケット:

select identifier as inprogress_identifier, participant performance 
  from performance where activity=2

参加者が出席している未公開チケット:

select * from 
  (select identifier as notclosed_identifier 
    from performance where identifier not exists
    (select identifier from performance where activity=4)) closed 
left join 
  (select identifier as inprogress_identifier, participant performance 
    from performance where activity=2) attended 
on notclosed_identifier=inprogress_identifier
于 2008-10-09T00:01:59.863 に答える
0

この種のクエリを出発点として使用できる場合があります。

select x.identifier, 
       max(x.p_1) as new_participant, max(x.c_1) as new_date,
       max(x.p_2) as inprogress_participant, max(x.c_2) as inprogress_date,
       max(x.p_3) as approval_participant, max(x.c_3) as approval_date,
       max(x.p_4) as closing_participant, max(x.c_4) as closing_date
  from (
        select a.identifier, 
               decode (activity, 1, participant, null) as p_1,  decode (activity, 1, closedate, null) as c_1,
               decode (activity, 2, participant, null) as p_2,  decode (activity, 2, closedate, null) as c_2,
               decode (activity, 3, participant, null) as p_3,  decode (activity, 3, closedate, null) as c_3,
               decode (activity, 4, participant, null) as p_4,  decode (activity, 4, closedate, null) as c_4
          from performance a
        ) x
 group by x.identifier

アイデアは、テーブルを行からフィールドにシリアル化し、それに基づいてビューを作成することです。このビューに基づいてレポートを作成できます。

よろしく、

于 2008-10-09T03:59:41.693 に答える
0

他の人が構築する可能性のある簡単なアイデア (テストされていませんが、アイデアが伝わることを願っています):

まず、まだクローズされていないすべてのアクティビティを選択します (他の人が投稿したように)。

select id
from performance p1 where identifier not exists
  (select * from performance p2 where activity=4 and p1.id=p2.id)

次に、select 句にサブクエリを追加して、アクティビティに参加する人を追加できます。

select id,
 (select participant 
  from performance p3 
  where p3.activity=3 and p1.id=p2.id)
from performance p1 where identifier not exists
  (select * from performance p2 where activity=4 and p1.id=p2.id)

この ID のアクティビティ 3 レコードがない場合、サブクエリは null を返します。これはまさに必要なものです。

これがお役に立てば幸いです - 必要に応じて展開してください。

于 2008-10-09T07:51:04.503 に答える