質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.05%

下記ロジックを満たすSQL(SELECT)を教えていただけますでしょうか

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,461

score 21

下記ロジックを満たすSQL(SELECT)を教えていただけますでしょうか。
データベースタイプはオラクルとなっております。


今入力値として、入力1:SY番号 , 入力2 : 出力数
があるものとします。

ここでは説明のため、仮にSY番号が"sy1" 出力数が"1"とします。


ロジック1:テーブルAから入力1にヒットするSE番号を取得
(例:se1取得)

【テーブルA】
SY番号、SE番号
 sy1 、se1
  sy2 、se2
  sy3 、se3

ロジック2:テーブルBからロジック1で取得したSE番号に対応したZU番号を取得
(例:zu1取得)

【テーブルB】
SE番号、ZU番号
  se1 、zu1
  se2 、zu1
  se3 、zu1
  se4 、zu2
  se5 、zu2
  se6 、zu2

ロジック3:テーブルCからロジック1で取得したSE番号に対応した最大DT(大きいほうのレコード値)を取得
(例:1/3 10:10:12)

【テーブルC】
ID   、SE番号、DT
1101 、 se3 、1/1 10:10:10
1102 、 se3 、1/1 10:10:10
1201 、 se2 、1/2 10:10:11
1202 、 se2 、1/2 10:10:11
1301 、 se1 、1/3 10:10:12
1302 、 se1 、1/3 10:10:12
1401 、 se5 、1/4 10:10:13
1402 、 se5 、1/4 10:10:13
1501 、 se4 、1/5 10:10:14
1502 、 se4 、1/5 10:10:14
1601 、 se6 、1/6 10:10:15
1602 、 se6 、1/6 10:10:15

ロジック4:テーブルBからロジック2で取得したZU番号に対応した全SE番号を取得
(例:se1,se2,se3を取得)

【テーブルB】
SE番号、ZU番号
  se1 、zu1
  se2 、zu1
  se3 、zu1
  se4 、zu2
  se5 、zu2
  se6 、zu2

ロジック5:テーブルCからロジック4で取得した各SE番号に対応した最大DT(大きいほうのレコード値)を取得
(例:1/1 10:10:10,1/2 10:10:11,1/3 10:10:12を取得)

【テーブルC】
ID  、SE番号、DT
1101 、 se3 、1/1 10:10:10
1102 、 se3 、1/1 10:10:10
1201 、 se2 、1/2 10:10:11
1202 、 se2 、1/2 10:10:11
1301 、 se1 、1/3 10:10:12
1302 、 se1 、1/3 10:10:12
1401 、 se5 、1/4 10:10:13
1402 、 se5 、1/4 10:10:13
1501 、 se4 、1/5 10:10:14
1502 、 se4 、1/5 10:10:14
1601 、 se6 、1/6 10:10:15
1602 、 se6 、1/6 10:10:15


ロジック6:ロジック5で取得した各DTをロジック3で取得したDTを基準にしてそれよりも
      前の日時の各DTを取得する。
(例:1/1 10:10:10,1/2 10:10:11取得)


ロジック7:ロジック6で取得した各DTを昇順でソートする。
(例:1/1 10:10:10,1/2 10:10:11)


ロジック8:ロジック7でソートした各DTの中から、ロジック3で取得したDTから近い順に
      見て、入力2の出力数の数だけ選択及び取得する
(例:1/2 10:10:11を取得)


ロジック9:ロジック8で取得した各DTに紐付いたSE番号をテーブルCより取得
(例:SE2を取得)


かなり細かく段階を分けてロジックを書いておりますが、効率よくまとめてSQLを記述するとなると、おそらくですがどこかのロジックは短縮又は不要になったりするかとおもいます。

その辺りを含めまして最も効率よく一度のSQL文だけでSELECTできるSELECT文を記述して教えていただけますでしょうか。

おそらくサブクエリを使用すると思いますが、サブクエリ数も最低限の数だけ使用するなど工夫をいただけると幸いです。

以上、宜しくお願い致します。 
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

とりあえずこんな感じで

SELECT
      dat.se_num
FROM(
    SELECT
        , D.se_num
        , B.zu_num
                -- 基準より前の人で基準に近い順だから古い方からナンバリング
        , ROW_NUMBER() OVER(ORDER BY E.dt DESC) ord
    FROM B
        -- 指定されたSEのZUを求める
    JOIN A
    ON A.se_num = B.se_num
    AND A.se_num = [sy1]
        -- 指定されたSEのDTを求める
    JOIN C
    ON A.se_num = C.se_num
        -- 同じZUのSEを求める
    JOIN B AS D
    ON D.zu_num = B.zu_num
        -- 同じZUのSEで基準のDTより前のDTを求める
    JOIN C AS E
    ON D.se_num = E.se_num
    AND C.dt > E.dt
) dat
-- ナンバリングされた値が指定された値より小さいものを取得
WHERE dat.ord <= [1]
-- 日付が新しい順になっているので古い順からがよかったらナンバリングの逆順
ORDER BY dat.ord DESC

確認はしていないけどいけるはず
同じ部署の先輩を近い順に指定人数分出したいとかそんな感じですか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/06/22 08:31

    有難う御座います。
    これから検証して問題がなければベストアンサーとさせていただきます。

    キャンセル

  • 2015/06/22 19:50

    kutsulog様

    私の認識不足がありまして、テーブルCの情報に誤りがありました。
    ID列が不足しておりました。
    このため同じSE番号が複数行あります。
    従いまして、ロジック3とロジック5において、DTを取得するときに
    各SE番号で最大のDTを取得するという条件が加わります。
    大変申し訳ありませんが、上記内容を含めて最終形のSQLを記述いただけますでしょうか?


    【テーブルC】
    ID 、SE番号、DT
    1101 、 se3 、1/1 10:10:10
    1102 、 se3 、1/1 10:10:12
    1201 、 se2 、1/2 10:10:11
    1202 、 se2 、1/2 10:10:12
    1301 、 se1 、1/3 10:10:12
    1302 、 se1 、1/3 10:10:13
    1401 、 se5 、1/4 10:10:13
    1402 、 se5 、1/4 10:10:14
    1501 、 se4 、1/5 10:10:14
    1502 、 se4 、1/5 10:10:15
    1601 、 se6 、1/6 10:10:15
    1602 、 se6 、1/6 10:10:16

    キャンセル

  • 2015/06/22 22:12

    それではこれでいかがでしょう?

    -- IDごとに最大のDTを求めるCTE
    WITH C2(se_num, DT)
    AS (
    SELECT
    se_num
    , MAX(DT) DT
    FROM C
    GROUP BY
    se_num
    )
    SELECT
    dat.se_num
    FROM(
    SELECT
    , D.se_num
    , B.zu_num
    -- 基準より前の人で基準に近い順だから古い方からナンバリング
    , ROW_NUMBER() OVER(ORDER BY E.dt DESC) ord
    FROM B
    -- 指定されたSEのZUを求める
    JOIN A
    ON A.se_num = B.se_num
    AND A.se_num = [sy1]
    -- 指定されたSEのDTを求める
    JOIN C2
    ON A.se_num = C2.se_num
    -- 同じZUのSEを求める
    JOIN B AS D
    ON D.zu_num = B.zu_num
    -- 同じZUのSEで基準のDTより前のDTを求める
    JOIN C2 AS E
    ON D.se_num = E.se_num
    AND C2.dt > E.dt
    ) dat
    -- ナンバリングされた値が指定された値より小さいものを取得
    WHERE dat.ord <= [1]
    -- 日付が新しい順になっているので古い順からがよかったらナンバリングの逆順
    ORDER BY dat.ord DESC

    すべて聞くのではなく、
    少しは考えてみて分からないところを聞いた方が実になりますよ?

    キャンセル

  • 2015/06/23 21:06

    kutsulogs様

    ご回答ありがとうございます。

    おっしゃるとおり多少考えてわからなければ聞きたい所なのですが、
    納期が迫っておりまして、時間が取れずにいます。

    但し、いただいた回答の中で、初めて触れること(join,row_number,with等)
    はそれらをインターネットで調べて理解しながら使用するようにしております。

    また、大変申し訳ないのですが、これらのSQLは続きがありまして、得られた
    SELECT結果を繰り返し実行する処理がございます。こちらに関してもご教授
    いただきたいので、是非別に建てる質問へのご回答もどうぞ宜しくお願い致します。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.05%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る