いちばん失敗した人決定戦

添付の図に記載したテーブル構造に関するSQLの質問です。
(何度も同じ質問すいません。)

図中のテーブルCのレコードをとりたいと思っています。
ただし、TableAのId=1に対応するもののみを取得したいです。

そこで、↓のようなSQL文を実行してみました。
=====
SELECT
tablea.Name as Name_A,
tableb.Name as Name_B,
tableb.DateTime as DateTime_B,
tablec.Id as Id_C,
tablec.Name as Name_C
FROM tablec
inner join tabled on tabled.Id_C = tablec.Id
inner join tableb on tableb.Id = tabled.Id_b
inner JOIN tablea on tablea.Id = tableb.Id_A
where tablea.Id=1
====

そうすると、当然ですが、tablecのレコードが重複してしまうことがあります。
具体的には、TableCのId=1,2が重複してしまいます。
図の「SQL文の実行結果(1)」に書いています。


そこで、重複してしまうレコードに関しては、tableb.DateTimeが最も新しいものを1つだけ選択したいと思っています。
なので、今度は↓のようなSQL文を実行しました。
====
SELECT
tablea.Name as Name_A,
tableb.Name as Name_B,
max(tableb.DateTime) as DateTime_B,
tablec.Id as Id_C,
tablec.Name as Name_C
FROM tablec
inner join tabled on tabled.Id_C = tablec.Id
inner join tableb on tableb.Id = tabled.Id_b
inner JOIN tablea on tablea.Id = tableb.Id_A
where tablea.Id=1
group by tablec.Id
order by tableb.datetime desc
;
====
そうすると、図の「SQL文の実行結果(2)」のような結果が得られます。
この場合、おおむね期待通りの結果が得られますが、tableb.nameの値が全てXXXになってしまっています。

期待する結果は図の「期待する結果」に書いた通りのものです。
どうしたら、期待する結果を得ることができるでしょうか?
よろしくお願いいたします。

「SQL文に関する質問です。よろしくお願い」の質問画像

質問者からの補足コメント

  • 画像がつぶれて見えなくなってしまったので、↓にアップロードしました。
    https://imgur.com/y676vrH

    図の中の「SQL文の実行結果(1)」を見て、表の中の「Id_C」は1,2,3の三つあり、
    そのため、欲しいデータはこれらId_C=1,2,3のものになります。

    んで、Id_C=1,2に関しては、レコードが複数あるので、それら複数のうち、
    DateTime_Bが一番新しいレコードを選択します。
    なので、最終的に欲しいものは「期待する結果」に記載したものとなります。

    最悪、「SQL文の実行結果(1)」を取得して、そのあと何らかのプログラムを使えば
    「期待する結果」に書いたものが取得できますが、SQLだけでできる方法があれば、
    それも知っておきたいという感じです。

      補足日時:2022/02/27 20:28

A 回答 (2件)

本来、GROUP BY には集約関数以外の列を全部記述する必要があります。


SQLとして正しいのは、GROUP BY に列を追加した
GROUP BY tablea.Name,tableb.Name,tablec.Id,tablec.Name
あるいは、Group BY で指定した列だけをSELECTに記述した
SELECT max(tableb.DateTime) as DateTime_B,tablec.Id as Id_C
になります。
で、どちらも、あなたが欲しいデータとは違います。

MySQLでは、GROUP BY に独自の拡張がされていて、全部記述する必要がなくなっています。
ただし、GROUP BY で指定した組合せに対して、1対多で対応している列
(今回なら、 id_C と id_B の関係)
の場合、どの値が選ばれるかは保証しない、ということです。


MySQL 8以降なら、 Window関数が使えるので
・Row_NUMBER() でid_C毎に行番号を付けて、 行番号=1だけを抽出
・Window関数版の max() でid_C毎に最大日時を付けて、 tableB.DateTime=Datetimeの最大 だけを抽出
とかできます。
    • good
    • 2

画像が見えず把握できませんけど(知恵袋なら拡大表示もできるのに)、前回までの様子から



>tablea.Id=1

>tableb.DateTimeが最も新しいもの
が両立する事はないのではないかと思いましたけど、今回の質問でテーブルのデータは見直されたのでしょうか?
それともあくまで今まで通りのデータ群から抽出しようとしているのか?
(無理と思えるのですが・・・素人目では)

コード以前に抽出できるかどうかフローチャートなどで検証されてみては?
仮にそれで抽出可能であったと言うのであれば、それを提示してみる。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!