0

たとえば、列Aと列Bに値がある場合:

+---+---+
| A | B |
+---+---+
| 2 | 1 |
| 5 | 1 | 
| 6 | 1 |
| 1 | 2 |
| 5 | 2 |
| 0 | 2 |
| 2 | 3 |
| 7 | 3 |
| 4 | 3 |
| 5 | 4 |
+---+---+

Bの各グループから、Aから最大の数値を取得したいと思います。ただし、Bの数値が高くても、前のA値よりもA値が小さい結果は含めたくありません。これは言葉では意味がないことは知っていますが、これが最終結果を次のように見せたいものです。

+---+---+
| A | B |
+---+---+
| 6 | 1 |
| 7 | 3 |
+---+---+

これまでのところ、「select max(a)、b from table1 group by b」のようなものがありますが、これはBが高く、最大Aが小さいものを省略していません。PHPでそのクエリの結果を熟読し、A値が前のA値よりも小さいものを削除できることは知っていますが、可能であれば、すべてをmysqlクエリに入れたいと思います。

4

3 に答える 3

5

この手法は、それ自体の集約バージョンに対してテーブルを結合しますが、結合は1だけオフセットされるため、すべての行が前のBのMAX(A)値の知識に結合されます。次に、現在のAがそれらのいずれよりも大きい行と一致し、見つからない場合はその行は含まれません。次に、最終的な選択を集約して、目的の結果を取得します。

SELECT 
       MAX(source_row.A) as A, 
       source_row.B
  FROM ab as source_row
  LEFT JOIN (SELECT MAX(A) as A, B FROM ab GROUP BY B) AS one_back 
    ON one_back.B = source_row.B-1 
 WHERE (one_back.A IS NULL) 
    OR one_back.A < source_row.A
 GROUP BY B

私はこれをテストしました:-)

編集:追加の洞察

この種のソリューションをどのように考え出したかについて、少し洞察を共有したいと思いました。なぜなら、人々が「セットで考える」ことを始めることが重要だと思うからです...これは、JOINSに関して私が今まで読んだ中で最高のアドバイスであり、クエリが機能する中間の「セット」を想像する必要があります。これを説明するために、このクエリの重要な部分である中間の「セット」の表現を次に示します。それは、それ自体の集約バージョンに1つずつ「結合」されて存在するテーブルです。

+------+------+------------+------------+
| A    | B    | one_back.B | one_back.A |
+------+------+------------+------------+
|    2 |    1 |       NULL |       NULL |
|    5 |    1 |       NULL |       NULL |
|    6 |    1 |       NULL |       NULL |
|    1 |    2 |          1 |          6 |
|    5 |    2 |          1 |          6 |
|    0 |    2 |          1 |          6 |
|    2 |    3 |          2 |          5 |
|    7 |    3 |          2 |          5 |
|    4 |    3 |          2 |          5 |
|    5 |    4 |          3 |          7 |
+------+------+------------+------------+

そして、実際にメモリ内に作成されたセット(完全に結合されたバージョンが完全にメモリ内にあることはありません。MySQLは、行が「カット」されないことがわかるとすぐに行を削除できるためです。

+------+------+------------+------------+
| A    | B    | one_back.B | one_back.A |
+------+------+------------+------------+
|    2 |    1 |       NULL |       NULL |
|    5 |    1 |       NULL |       NULL |
|    6 |    1 |       NULL |       NULL |
|    7 |    3 |          2 |          5 |
+------+------+------------+------------+

そしてもちろん、元の行からAとBのみを選択して、そこからの結果を最終的な形式に集約します。

于 2012-07-13T02:32:31.143 に答える
1

より簡単な解決策は、変数を使用しaて前の行の値を格納し、各反復で比較を行うことです。bこれは、列にギャップがあり、数値が完全に順番に並んでいない場合も考慮に入れます。

SELECT @val:=a.a AS a, a.b
FROM
(
  SELECT MAX(a) AS a, b
  FROM tbl
  GROUP BY b
) a
WHERE a.a > IFNULL(@val,-1)
于 2012-07-13T02:48:40.550 に答える
0
Select Z.a, Z.b from
(select a, b, rank() over (order by b) as ranker from (select max(a) a, b  from table1 group by b) Y) Z left join
(select a, b, rank() over (order by b) as ranker from (select max(a) a, b  from table1 group by b) Y1) Z1
on Z.ranker = Z1.ranker + 1
where Z.a > isnull(Z1.a, -100000)
于 2012-07-13T02:33:40.150 に答える