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

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

ただいまの
回答率

90.61%

  • Java

    13514questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • MySQL

    5701questions

    MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

SQLで、ユニークなレコード抽出をしたい

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,510
退会済みユーザー

退会済みユーザー

JAVAで、MySQLを使っています。

SQL文が組めなくて、困っています。

会社ID+社員ID+顧客IDの組み合わせのレコードが、複数存在するテーブルです。


下記のSQL文だと、
会社ID+社員ID+顧客IDの、各IDに該当するレコードが複数抽出されてしまいますが、

抽出したいのは、
関数の引数の 会社ID、社員ID、顧客IDに一致した、
会社ID+社員ID+顧客IDで、write_datetimeが一番大きい レコード。のパターンを全件抽出したいのです。




尚、各レコードには、会社ID+社員ID+顧客IDの組み合わせで、ユニークな index_id を持っています。

※iPara_company_id=1、iPara_user_id=1、iPara_customar_id=1など関数に渡す引数に一致したレコードだけ抽出したい。

■テーブルの例    ※後記「②」のパターンをわかりやすくしたテーブル例。
 id  index_id   company_id   user_id  customar_id  write_datetime   ・ ・・その他多数の項目
1    3               3                  1             1                  2015-08-01 15:11:23
2    1               1                  1             1                  2015-08-02 13:11:11
3    1               1                  1             1                  2015-08-03 09: 31:21    ←最終日時のこれを抽出
4    2               1                  1             1                  2015-08-04  13:11:11
5    2               1                  1             1                  2015-08-05 15:11:23
6    2               1                  1             1                  2015-08-06  13:11:11   ←最終日時のこれを抽出
7    4               5                  1             1                  2015-08-08  15:11:23
8    4               5                  1             1                  2015-08-08  16:12:11
9    5               1                  1             1                  2015-08-08  15:11:23
10  5               1                  1             1                  2015-08-08  16:12:11   ←最終日時のこれを抽出

※idは、プライマリーキー。
※DB構造が同じパターンの値が複数あり、無駄なつくりに見えるかもしれませんが、
 仕様書との観点から、他DB用SQLからのJOINや呼び出しで利便性を高めた結果、
 このような意見すると無駄に見えるパターンになっております。
 (熟練者の方なら、もっと良いテーブルがすぐに作れるのは承知しております)


■8/2 19:57 追記:
下記SQL文を作ったのですが、GROUP BYでレコードは、ユニークに抽出できているのですが、
最大日付(write_datetime)を拾ってこない状態です。

String strSQL =
          "SELECT *"
        + " FROM commpany_list"
        + " WHERE"
        + " id IN"
        + " (SELECT MAX(id)"
        + "    FROM commpany_list"
        + "    WHERE"
        + "            (company_id   = " + iPara_company_id        + ")"    // 会社ID
        + "    AND (user_id        = " + iPara_user_id         + ")"    // ユーザーID
        + "    AND (customer_id     = " + iPara_customer_id        + ")"    // 社員ID
        + "    AND (delete_flag = false)"                            // 削除フラグ
        + "    GROUP BY index_id, commpany_id, customer_id, user_id)"
        + " ORDER BY write_datetime DESC";


■8/22 9:18  S_Minecraft様のご要望で、関数へパラメーターを渡す部分を含めたソースを掲載。

public int getAllCompany_Pattern_List(
        int iPara_company_id
      , int iPara_user_id
      , int iPara_customer_id
      )
{
    try    {
        // DBオープン
        DB.open();

        // リストを抽出。
        if (iPara_customer_id <= 0) {
            // ★★★①のパターン★★★
            // iPara_customer_id <= 0 の時は、パターンや抽出条件にcustomer_idを入れない。
            String strSQL =
                      "SELECT *"
                    + " FROM commpany_list"
                    + " WHERE"
                    + " id IN"
                    + " (SELECT MAX(id)"
                    + "    FROM commpany_list"
                    + "    WHERE"
                    + "        (company_id    = " + iPara_company_id        + ")"    // 会社ID
                    + "    AND (user_id        = " + iPara_user_id               + ")"    // ユーザーID
                    + "    AND (delete_flag  = false)"                            // 削除フラグ
                    + "    GROUP BY index_id, company_id, user_id)"
                    + " ORDER BY write_datetime DESC";

            // SELECT用のSQL実行メソッド
            DB.executeQuery(strSQL);
        }
        else {
            // ★★★②のパターン★★★
            String strSQL =
                      "SELECT *"
                    + " FROM commpany_list"
                    + " WHERE"
                    + " id IN"
                    + " (SELECT MAX(id)"
                    + "    FROM commpany_list"
                    + "    WHERE"
                    + "            (company_id   = " + iPara_company_id    + ")"        // 会社ID
                    + "    AND (user_id           = " + iPara_user_id            + ")"        // ユーザーID
                    + "    AND (customer_id    = " + iPara_customer_id    + ")"    // 顧客ID
                    + "    AND (delete_flag = false)"                            // 削除フラグ
                    + "    GROUP BY index_id, company_id, customer_id, user_id)"
                    + " ORDER BY write_datetime DESC";

            // SELECT用のSQL実行メソッド
            DB.executeQuery(strSQL);
        }
    以下省略
    }
    catch(・・・
}

以上


■追記: 8/22 11:31
下記SQLで、「②」のパターンが正常に抽出でき、解決。
あとは、「①」のパターンの抽出のSQL。

String strSQL = "SELECT * FROM commpany_list AS m"
+ "WHERE m.delete_flag = false"
+ "AND m.company_id = " + iPara_company_id
+ "AND m.user_id = " + iPara_user_id
+ "AND m.customar_id = " + iPara_customar_id
+ "AND NOT EXISTS ("
+ " SELECT 1 FROM commpany_list AS s"
+ " WHERE m.index_id = s.index_id"
+ " AND m.delete_flag = false"
+ " AND m.write_datetime < s.write_datetime"
+ ")"
+ "ORDER BY m.write_datetime DESC";

-------------------------------------------------------

「①」のパターンのテーブル例。
■テーブルの例    ※上記「①」のパターンをわかりやすくしたテーブル例。
 id  index_id   company_id   user_id  customar_id  write_datetime   ・ ・・その他多数の項目
1    1               1                  1             0                  2015-08-01 15:11:23
2    1               1                  1             0                  2015-08-02 13:11:11
3    1               1                  1             0                  2015-08-03 09: 31:21    ←最終日時のこれを抽出
4    2               1                  1             0                  2015-08-04  13:11:11
5    2               1                  1             0                  2015-08-05 15:11:23
6    2               1                  1             0                  2015-08-06  13:11:11   ←最終日時のこれを抽出
7    4               5                  1             0                  2015-08-08  15:11:23
8    4               5                  1             0                  2015-08-08  16:12:11
9    5               1                  1             0                  2015-08-08  15:11:23
10  5               1                  1             0                  2015-08-08  16:12:11   ←最終日時のこれを抽出
11  6               3                  1             1                  2015-08-01 15:11:23
12  7               1                  1             1                  2015-08-02 13:11:11
13  7               1                  1             1                  2015-08-03 09: 31:21    ←最終日時のこれを抽出
14  8               1                  1             1                  2015-08-04  13:11:11
15  8               1                  1             1                  2015-08-05 15:11:23
16  8               1                  1             1                  2015-08-06  13:11:11    ←最終日時のこれを抽出
17  9               5                  1             1                  2015-08-08  15:11:23
18  9               5                  1             1                  2015-08-08  16:12:11
19  10             1                  1             1                  2015-08-08  15:11:23
20  10             1                  1             1                  2015-08-08  16:12:11    ←最終日時のこれを抽出

以上


■追記:8/22 13:25
上記「①」の抽出ができました。

String strSQL = "SELECT * FROM commpany_list AS m"
+ "WHERE m.delete_flag = false"
+ "AND m.company_id = " + iPara_company_id
+ "AND m.user_id = " + iPara_user_id
//+ "AND m.customar_id = " + iPara_customar_id       ← ここをコメントアウトしただけ。
+ "AND NOT EXISTS ("
+ " SELECT 1 FROM commpany_list AS s"
+ " WHERE m.index_id = s.index_id"
+ " AND m.delete_flag = false"
+ " AND m.write_datetime < s.write_datetime"
+ ")"
+ "ORDER BY m.write_datetime DESC";

以上
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 4

checkベストアンサー

0

会社ID+社員ID+顧客IDで、write_datetimeが一番大きい レコード。のパターンを全件抽出
条件を満たす全ての行がほしいのですよね?
目的がこれなら、PHPからの変数は不要だと思いますよ。

ほかの方のSQLと同じような感じですが
company_id,user_id,customer_idこれらが一致していながら、自身より大きなwrite_datetimeが存在しない行を抽出する主旨のSQLです。
SELECT *
FROM commpany_list AS m
WHERE m.delete_flag = false 
AND NOT EXISTS (
  SELECT 1
  FROM commpany_list AS s
  WHERE m.company_id = s.company_id
  AND m.user_id = s.user_id
  AND m.customer_id = s.customer_id
  AND m.delete_flag = false
  AND m.write_datetime < s.write_datetime
) 
ORDER BY write_datetime DESC
※動作テストはしていませんので、エラーを含むかも知れません
※全く同じ日付で最新日の行が複数存在する場合、ID毎に2行以上抽出してしまいます。
※相関サブクエリを使っているので、データ量が多いとレスポンスが悪くなります。

もし可能なら、JAVAのコード経由ではなくて、開発用DBで直接SQLを実行して結果を確認してから組み込んだほうが混乱が少なくてすむと思います。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/08/21 21:58

    SQLありがとうございます。
    関数に渡される引数に一致したレコードのパターンの最終日付の物を抽出したいのです。
    データパターンをみていただくとわかるように、複数の行が一致します。

    質問が悪くて大変申し訳ありません。
    せっかくSQLを書いていただいたのに、本当に申し訳ございません。

    キャンセル

  • 2015/08/21 22:35

    むむむ?それだとhy3さんのコードで良さそうに思いますけども…。
    >関数の引数の 会社ID、社員ID、顧客IDに一致した、 会社ID+社員ID+顧客IDで、write_datetimeが一番大きい レコード。

    例えば「会社ID+社員ID+顧客IDで、write_datetimeが一番大きい レコードのうちcompany_id=1、user_id=1、customar_id=1これらの条件を満たすもの」
    こういったことですよね?これは必然的に1件だけになるように思えます。

    キャンセル

  • 2015/08/21 22:42

    あ、すみません。データ見直してて少し理解しました。
    > 会社ID+社員ID+顧客IDの組み合わせで、ユニークな index_id を持っています。
    このようにありますが、この3つが同じでもindex_idの異なるレコードがあるんですね。

    キャンセル

  • 2015/08/21 23:05 編集

    逆にindex_idが同じなのに、company_id,user_id,customar_idの組み合わせが異なるレコードは有り得ますか?
    サンプルデータを見る限りでは無いようですが、こういったデータです。
    index_id,company_id,user_id,customar_id
    1,1,1,1
    1,2,1,1
    1,1,1,1
    1,2,3,4

    もし無ければ次のコードでいけそうに思います。
    String strSQL = "SELECT * FROM commpany_list AS m"
    + "WHERE m.delete_flag = false"
    + "AND m.company_id = " + iPara_company_id
    + "AND m.user_id = " + iPara_user_id
    + "AND m.customar_id = " + iPara_customar_id
    + "AND NOT EXISTS ("
    + " SELECT 1 FROM commpany_list AS s"
    + " WHERE m.index_id = s.index_id"
    + " AND m.delete_flag = false"
    + " AND m.write_datetime < s.write_datetime"
    + ")"
    + "ORDER BY m.write_datetime DESC";

    キャンセル

  • 2015/08/22 08:54

    「index_idが同じなのに、company_id,user_id,customar_idの組み合わせが異なるレコードは有り得ますか?」いえ、ありません。

    SQLありがとうございます。
    今から、さっそっく、組み込んでみます。

    本当に助かります。自分が未熟なばかりにいろいろご伝授いただき、
    ありがとうございます。

    キャンセル

  • 2015/08/22 11:28

    SQLの実行結果ですが、無事に、正常に抽出できました。
    ありがとうございます。
    大変助かりました。心から感謝させていただきます。

    あとは、 if (iPara_customer_id <= 0) { のパターンの場合の
    SQLです。

    キャンセル

  • 2015/08/22 13:31

    SQL文ありがとうございます。
    そのままソースへ反映できる形でかいていただいたので、+ や ダブルくぉーてしょんで囲ったり、非常に楽にソースへ反映できました。

    ご報告です。
    質問の「①」が解決しました。下記のように一か所コメントアウトしただけです。
    String strSQL = "SELECT * FROM commpany_list AS m"
    + "WHERE m.delete_flag = false"
    + "AND m.company_id = " + iPara_company_id
    + "AND m.user_id = " + iPara_user_id
    + "AND m.customar_id = " + iPara_customar_id
    + "AND NOT EXISTS ("
    + " SELECT 1 FROM commpany_list AS s"
    + " WHERE m.index_id = s.index_id"
    + " AND m.delete_flag = false"
    + " AND m.write_datetime < s.write_datetime"
    + ")"
    + "ORDER BY m.write_datetime DESC";


    本来なら、一つのSQLでやりやりたかったのですが、
    そのすべを知らないので、とりあえず、2つのSQLでいきます。

    ほんとにSQLのご提供ありがとうございました。
    大変助かりました。大変お手数をおかけいたしました。

    キャンセル

0

SELECT * FROM company_list
WHERE index_id IN(SELECT MAX(write_datetime) FROM company_list GROUP BY company_id, user_id, customer_id)
たぶん、これでいけるかなと思います

あと、わりとどうでもいいですが、「customar」のスペルは「customer」なので一応…

17:01 sqlを修正

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/08/21 13:52

    ご回答ありがとうございます。
    つづりは、例として書いたので、間違えました。

    レコード例も追記しました。

    SQLありがとうございます。

    キャンセル

  • 2015/08/21 16:29

    今から、このSQLで試してみます。

    キャンセル

  • 2015/08/21 16:30

    WHERE index_id の後ろに、関数に渡されたパラメーターを指定すれば
    よろしいですよね、やってみます。

    キャンセル

  • 2015/08/21 16:45

    残念ですが、プログラムに組み込めませんでした。
    せっかく、書いていただいたのに申し訳ございません。

    パラメータの指定場所や、 FROM consultation_list や FROM History という未知のテーブルをどうかいけつしてよいかわからなかったためです。

    キャンセル

  • 2015/08/21 17:00

    すみません、HISTORYはこれを自分が以前つくってきたものから引っ張ってきたので直すのを忘れてました
    上の回答に修正しました
    パラメータの指定とありますが、よくわからないので、該当のソースを見せていただけませんか?

    キャンセル

  • 2015/08/22 08:55

    承知しました。ソースを載せさせていただきます。
    ご配慮ありがとうございます。

    キャンセル

0

下記が欲しいということでしょうか?
・会社IDなどの条件指定は無し
・全レコードの中から会社ID/社員ID/顧客IDで一意となるレコードを抽出
・上記の中から、それぞれ「write_datetime」が最大となるもの

下記のようなSQLでいけるでしょうか。
試していないのと、あまりレスポンスなど気にせず要件のみ満たせるように書きましたので
必要に応じて修正してください。

SELECT
    company_id,
    user_id,
    customar_id
FROM
    (
        SELECT
            company_id,
            user_id,
            customar_id,
            MAX(write_datetime) write_datetime
        FROM
            consultation_list
        WHERE
            delete_flag = false
        GROUP BY
            company_id,
            user_id,
            customar_id
    ) A
    INNER JOIN consultation_list B
    A.company_id     = B.company_id
    A.user_id        = B.user_id
    A.customar_id    = B.customar_id
    A.write_datetime = B.write_datetime

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/08/21 13:54

    SQLありがとうございます。
    お手数をおかけしてもうしわけありません。

    早速、試してみます。
    ありがとうございました。

    キャンセル

  • 2015/08/21 16:28

    結果のご報告です。
    残念ながら、SQLを組むことができませんでした。
    どこに関数にわたされた引数をしてよいのかわからなくて、
    あちこちに、いれてみたのですが、思うように抽出されませんでした。

    お手数をおかけしました。

    キャンセル

0

3つのIDを関数の引数に指定しているということは、特定の一つの組み合わせについて、最新のレコードを1件取得できれば良いということですか?
それであれば、以下のように直せば良いのではないでしょうか。

String sql = "SELECT * FROM commpany_list" 
+ " WHERE" 
+ "     company_id  = " + iPara_company_id
+ " AND user_id     = " + iPara_user_id
+ " AND customar_id = " + iPara_customar_id
+ " AND delete_flag = false"
+ " ORDER BY write_datetime DESC"
+ " LIMIT 1";

降順にソートした上で最初の1件だけを取得すれば、それが最新のレコードと考えられます。
質問の意図を間違って理解していたら申し訳ありません。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/08/21 17:19

    ご回答ありがとうございます。
    1件だけではなく、組み合わせのパターンの日付が最大のレコードを全部です。

    SQLありがとうございます。
    お手数をおかけしました。

    キャンセル

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

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

関連した質問

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

  • Java

    13514questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • MySQL

    5701questions

    MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。