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

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

新規登録して質問してみよう
ただいま回答率
85.50%
MySQL

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

Java

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

Q&A

解決済

4回答

5185閲覧

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

退会済みユーザー

退会済みユーザー

総合スコア0

MySQL

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

Java

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

0グッド

1クリップ

投稿2015/08/21 04:09

編集2015/08/22 04:27

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";

以上

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

会社ID+社員ID+顧客IDで、write_datetimeが一番大きい レコード。のパターンを全件抽出

条件を満たす全ての行がほしいのですよね?
目的がこれなら、PHPからの変数は不要だと思いますよ。

ほかの方のSQLと同じような感じですが
company_id,user_id,customer_idこれらが一致していながら、自身より大きなwrite_datetimeが存在しない行を抽出する主旨のSQLです。

SQL

1SELECT * 2FROM commpany_list AS m 3WHERE m.delete_flag = false 4AND NOT EXISTS ( 5 SELECT 1 6 FROM commpany_list AS s 7 WHERE m.company_id = s.company_id 8 AND m.user_id = s.user_id 9 AND m.customer_id = s.customer_id 10 AND m.delete_flag = false 11 AND m.write_datetime < s.write_datetime 12) 13ORDER BY write_datetime DESC

※動作テストはしていませんので、エラーを含むかも知れません
※全く同じ日付で最新日の行が複数存在する場合、ID毎に2行以上抽出してしまいます。
※相関サブクエリを使っているので、データ量が多いとレスポンスが悪くなります。

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

投稿2015/08/21 12:35

編集2015/08/21 12:47
hirohiro

総合スコア2068

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2015/08/21 12:58

SQLありがとうございます。 関数に渡される引数に一致したレコードのパターンの最終日付の物を抽出したいのです。 データパターンをみていただくとわかるように、複数の行が一致します。 質問が悪くて大変申し訳ありません。 せっかくSQLを書いていただいたのに、本当に申し訳ございません。
hirohiro

2015/08/21 13: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件だけになるように思えます。
hirohiro

2015/08/21 13:42

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

2015/08/21 14:06 編集

逆に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/21 23:54

「index_idが同じなのに、company_id,user_id,customar_idの組み合わせが異なるレコードは有り得ますか?」いえ、ありません。 SQLありがとうございます。 今から、さっそっく、組み込んでみます。 本当に助かります。自分が未熟なばかりにいろいろご伝授いただき、 ありがとうございます。
退会済みユーザー

退会済みユーザー

2015/08/22 02:28

SQLの実行結果ですが、無事に、正常に抽出できました。 ありがとうございます。 大変助かりました。心から感謝させていただきます。 あとは、 if (iPara_customer_id <= 0) { のパターンの場合の SQLです。
退会済みユーザー

退会済みユーザー

2015/08/22 04: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のご提供ありがとうございました。 大変助かりました。大変お手数をおかけいたしました。
guest

0

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

java

1String sql = "SELECT * FROM commpany_list" 2+ " WHERE" 3+ " company_id = " + iPara_company_id 4+ " 5 AND user_id = " + iPara_user_id 6+ " AND customar_id = " + iPara_customar_id 7+ " AND delete_flag = false" 8+ " ORDER BY write_datetime DESC" 9+ " LIMIT 1";

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

投稿2015/08/21 07:54

hy3

総合スコア594

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2015/08/21 08:19

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

0

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

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

SQL

1SELECT 2 company_id, 3 user_id, 4 customar_id 5FROM 6 ( 7 SELECT 8 company_id, 9 user_id, 10 customar_id, 11 MAX(write_datetime) write_datetime 12 FROM 13 consultation_list 14 WHERE 15 delete_flag = false 16 GROUP BY 17 company_id, 18 user_id, 19 customar_id 20 ) A 21 INNER JOIN consultation_list B 22 A.company_id = B.company_id 23 A.user_id = B.user_id 24 A.customar_id = B.customar_id 25 A.write_datetime = B.write_datetime 26

投稿2015/08/21 04:51

izuminao

総合スコア15

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2015/08/21 04:54

SQLありがとうございます。 お手数をおかけしてもうしわけありません。 早速、試してみます。 ありがとうございました。
退会済みユーザー

退会済みユーザー

2015/08/21 07:28

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

0

sql

1SELECT * FROM company_list 2WHERE 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 04:45

編集2015/08/21 08:01
S_Minecraft

総合スコア29

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2015/08/21 04:52

ご回答ありがとうございます。 つづりは、例として書いたので、間違えました。 レコード例も追記しました。 SQLありがとうございます。
退会済みユーザー

退会済みユーザー

2015/08/21 07:29

今から、このSQLで試してみます。
退会済みユーザー

退会済みユーザー

2015/08/21 07:30

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

退会済みユーザー

2015/08/21 07:45

残念ですが、プログラムに組み込めませんでした。 せっかく、書いていただいたのに申し訳ございません。 パラメータの指定場所や、 FROM consultation_list や FROM History という未知のテーブルをどうかいけつしてよいかわからなかったためです。
S_Minecraft

2015/08/21 08:00

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

退会済みユーザー

2015/08/21 23:55

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問