0

2 番目に高いレコードを探していたとしましょう。

サンプル テーブル:

CREATE TABLE `my_table` (
    `id` int(2) NOT NULL AUTO_INCREMENT,
    `name` varchar(255) NOT NULL,
    `value` int(10),
    PRIMARY KEY (`id`)
);
INSERT INTO `my_table` (`id`, `name`, `value`) VALUES (NULL, 'foo', '200'), (NULL, 'bar', '100'), (NULL, 'baz', '0'), (NULL, 'quux', '300');

2 番目に高い値はfooです。この結果を得る方法はいくつありますか?

明らかな例は次のとおりです。

SELECT name FROM my_table ORDER BY value DESC LIMIT 1 OFFSET 1;

他の例を思いつきますか?

これを試してみましたLIMIT & IN/ALL/ANY/SOME subqueryが、サポートされていません。

SELECT name FROM my_table WHERE value IN (
    SELECT MIN(value) FROM my_table ORDER BY value DESC LIMIT 1
) LIMIT 1;
4

4 に答える 4

2

標準SQLでのEduardoのソリューション

select *
from (
  select  id, 
          name, 
          value, 
          row_number() over (order by value) as rn
  from my_table t
) t
where rn = 1 -- can pick any row using this

これは、MySQL を除く最新の DBMS で機能します。通常、このソリューションは、サブセレクトを使用するソリューションよりも高速です。また、2 番目、3 番目、... の行を簡単に返すこともできます (これも Eduardo のソリューションでも実現可能です)。

グループごとにカウントするように調整することもできるpartition byため ( a を追加)、「グループあたり最大 n」の問題を同じパターンで解決できます。

ここで遊ぶ SQLFiddle があります: http://sqlfiddle.com/#!12/286d0/1

于 2013-09-26T18:54:16.043 に答える
1
SELECT name 
FROM my_table 
WHERE value < (SELECT max(value) FROM my_table)
ORDER BY value DESC 
LIMIT 1


SELECT name 
FROM my_table 
WHERE value = (
  SELECT min(r.value)
  FROM (
    SELECT name, value 
    FROM my_table 
    ORDER BY value DESC 
    LIMIT 2
  ) r
)
LIMIT 1
于 2013-09-26T18:57:13.927 に答える
1

これは、正確に 2 番目に高い場合にのみ機能します。

SELECT * FROM my_table two
WHERE EXISTS (
        SELECT * FROM my_table one
        WHERE one.value  > two.value
                AND NOT EXISTS (
                SELECT * FROM my_table zero
                WHERE zero.value > one.value
                )
        )
LIMIT 1
        ;

これは、ウィンドウ関数 rank() を持たないプラットフォーム用にエミュレートします。1 つの定数を変更することで、ランク <> 2 に適合させることもできます。

SELECT one.*
        -- , 1+COALESCE(agg.rnk,0) AS rnk
FROM my_table one
LEFT JOIN (
        SELECT one.id , COUNT(*) AS rnk
        FROM my_table one
        JOIN my_table cnt ON cnt.value > one.value
        GROUP BY one.id
        ) agg ON agg.id = one.id
WHERE  agg.rnk=1 -- the aggregate starts counting at zero
        ;

両方のソリューションには、機能的な自己結合が必要です (mysql がそれらを許可するかどうかはわかりません。IIRC は、テーブルが更新または削除のターゲットである場合にのみ許可しません)。

以下はウィンドウ関数を必要としませんが、再帰クエリを使用してランキングを列挙します。

WITH RECURSIVE agg AS (
        SELECT one.id
        , one.value
        , 1 AS rnk
        FROM my_table one
        WHERE NOT EXISTS (
                SELECT * FROM my_table zero
                WHERE zero.value > one.value
                )
        UNION ALL
        SELECT two.id
        , two.value
        , agg.rnk+1 AS rnk
        FROM my_table two
        JOIN agg ON two.value < agg.value
        WHERE NOT EXISTS (
                SELECT * FROM my_table nx
                WHERE nx.value > two.value
                AND nx.value < agg.value
                )
        )
SELECT * FROM agg
WHERE rnk = 2
        ;

(明らかに、再帰クエリは mysql では機能しません)

于 2013-09-26T22:24:09.527 に答える
1

次のようにインライン初期化を使用できます。

select * from (
  select  id, 
          name, 
          value, 
          @curRank := @curRank + 1 AS rank 
  from    my_table t, (SELECT @curRank := 0) r
  order by value desc
) tb
where tb.rank = 2
于 2013-09-26T18:29:02.307 に答える