MySQL で SQL Server の機能を複製する良い方法はありますROW_NUMBER()
か?
例えば:
SELECT
col1, col2,
ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY col3 DESC) AS intRow
FROM Table1
次に、たとえば、1 に制限する条件を追加して、各ペアintRow
で最高の単一行を取得できます。col3
(col1, col2)
MySQL で SQL Server の機能を複製する良い方法はありますROW_NUMBER()
か?
例えば:
SELECT
col1, col2,
ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY col3 DESC) AS intRow
FROM Table1
次に、たとえば、1 に制限する条件を追加して、各ペアintRow
で最高の単一行を取得できます。col3
(col1, col2)
MySQL にはランキング機能はありません。あなたが得ることができる最も近いものは、変数を使用することです:
SELECT t.*,
@rownum := @rownum + 1 AS rank
FROM YOUR_TABLE t,
(SELECT @rownum := 0) r
私の場合、それはどのように機能しますか?col1 と col2 のそれぞれに 1 つずつ、2 つの変数が必要ですか? col1 が変更されたときに、Col2 をリセットする必要がありますか?
はい。Oracle の場合は、LEAD 関数を使用して次の値でピークに達することができます。ありがたいことに、Quassnoi は、MySQL に実装する必要のあるロジックをカバーしています。
(col1, col2) ペアごとに 1 つの最高の col3 を持つ行が必要です。
これはgroupwise maximumであり、最もよくある SQL の質問の 1 つです (簡単に思えるかもしれませんが、実際にはそうではないため)。
私はしばしばnull-self-joinにふっくらしています:
SELECT t0.col3
FROM table AS t0
LEFT JOIN table AS t1 ON t0.col1=t1.col1 AND t0.col2=t1.col2 AND t1.col3>t0.col3
WHERE t1.col1 IS NULL;
「col1、col2 が一致し、それより高い col3 を持つ行が他にないテーブル内の行を取得します。」(複数の行に同じ col1、col2、col3 がある場合、これと他のほとんどのグループごとの最大ソリューションは複数の行を返すことに気付くでしょう。それが問題である場合は、後処理が必要になる場合があります。)
私はいつもこのパターンに従ってしまいます。このテーブルを考えると:
+------+------+
| i | j |
+------+------+
| 1 | 11 |
| 1 | 12 |
| 1 | 13 |
| 2 | 21 |
| 2 | 22 |
| 2 | 23 |
| 3 | 31 |
| 3 | 32 |
| 3 | 33 |
| 4 | 14 |
+------+------+
この結果を得ることができます:
+------+------+------------+
| i | j | row_number |
+------+------+------------+
| 1 | 11 | 1 |
| 1 | 12 | 2 |
| 1 | 13 | 3 |
| 2 | 21 | 1 |
| 2 | 22 | 2 |
| 2 | 23 | 3 |
| 3 | 31 | 1 |
| 3 | 32 | 2 |
| 3 | 33 | 3 |
| 4 | 14 | 1 |
+------+------+------------+
このクエリを実行すると、変数を定義する必要はありません。
SELECT a.i, a.j, count(*) as row_number FROM test a
JOIN test b ON a.i = b.i AND a.j >= b.j
GROUP BY a.i, a.j
それが役立つことを願っています!
SELECT
@i:=@i+1 AS iterator,
t.*
FROM
tablename AS t,
(SELECT @i:=0) AS foo
また、クエリ コードを少し変更した Mosty Mostacho のソリューションにも投票します。
SELECT a.i, a.j, (
SELECT count(*) from test b where a.j >= b.j AND a.i = b.i
) AS row_number FROM test a
同じ結果が得られます。
+------+------+------------+
| i | j | row_number |
+------+------+------------+
| 1 | 11 | 1 |
| 1 | 12 | 2 |
| 1 | 13 | 3 |
| 2 | 21 | 1 |
| 2 | 22 | 2 |
| 2 | 23 | 3 |
| 3 | 31 | 1 |
| 3 | 32 | 2 |
| 3 | 33 | 3 |
| 4 | 14 | 1 |
+------+------+------------+
テーブルの場合:
+------+------+
| i | j |
+------+------+
| 1 | 11 |
| 1 | 12 |
| 1 | 13 |
| 2 | 21 |
| 2 | 22 |
| 2 | 23 |
| 3 | 31 |
| 3 | 32 |
| 3 | 33 |
| 4 | 14 |
+------+------+
クエリが JOIN と GROUP BY を使用せず、代わりにネストされた選択に依存するという唯一の違いがあります。
関数を定義します:
delimiter $$
DROP FUNCTION IF EXISTS `getFakeId`$$
CREATE FUNCTION `getFakeId`() RETURNS int(11)
DETERMINISTIC
begin
return if(@fakeId, @fakeId:=@fakeId+1, @fakeId:=1);
end$$
それから私はすることができます:
select getFakeId() as id, t.* from table t, (select @fakeId:=0) as t2;
これで、ビューでは使用できないサブクエリがなくなりました。
rownum
MySQL には,のような関数はありませんrow_num()
が、回避策は次のとおりです。
select
@s:=@s+1 serial_no,
tbl.*
from my_table tbl, (select @s:=0) as s;
私が最も効果的であることがわかった解決策は、次のようなサブクエリを使用することでした。
SELECT
col1, col2,
(
SELECT COUNT(*)
FROM Table1
WHERE col1 = t1.col1
AND col2 = t1.col2
AND col3 > t1.col3
) AS intRow
FROM Table1 t1
PARTITION BY 列は「=」と比較され、AND で区切られます。ORDER BY 列は「<」または「>」と比較され、OR で区切られます。
少しコストがかかっても、これは非常に柔軟であることがわかりました。
行番号機能を模倣することはできません。期待どおりの結果が得られるかもしれませんが、ある段階でがっかりする可能性が高くなります。mysqlのドキュメントには次のように書かれています:
SELECT などの他のステートメントでは、期待どおりの結果が得られる場合がありますが、これは保証されません。次のステートメントでは、MySQL が最初に @a を評価し、次に代入を行うと考えるかもしれません: SELECT @a, @a:=@a+1, ...; ただし、ユーザー変数を含む式の評価順序は定義されていません。
よろしく、ジョージ。
これにより、ROW_NUMBER() AND PARTITION BY が提供するのと同じ機能を MySQL で実現できます。
SELECT @row_num := IF(@prev_value=GENDER,@row_num+1,1) AS RowNumber
FirstName,
Age,
Gender,
@prev_value := GENDER
FROM Person,
(SELECT @row_num := 1) x,
(SELECT @prev_value := '') y
ORDER BY Gender, Age DESC
少し遅れていますが、答えを探している人にも役立つかもしれません...
行間/行番号の例 - 任意の SQL で使用できる再帰クエリ:
WITH data(row_num, some_val) AS
(
SELECT 1 row_num, 1 some_val FROM any_table --dual in Oracle
UNION ALL
SELECT row_num+1, some_val+row_num FROM data WHERE row_num < 20 -- any number
)
SELECT * FROM data
WHERE row_num BETWEEN 5 AND 10
/
ROW_NUM SOME_VAL
-------------------
5 11
6 16
7 22
8 29
9 37
10 46
また、少し遅れましたが、今日も同じニーズがあったので、Google で検索し、最終的に Pinal Dave の記事http://blog.sqlauthority.com/2014/03/09/mysql-reset-rowにある簡単な一般的なアプローチを見つけました。 -行番号ごとのグループごとのパーティション番号/
Paul の元の質問 (それは私の問題でもありました) に焦点を当てたかったので、私の解決策を実際の例として要約します。
2 つの列に分割したいので、反復中に SET 変数を作成して、新しいグループが開始されたかどうかを識別します。
SELECT col1, col2, col3 FROM (
SELECT col1, col2, col3,
@n := CASE WHEN @v = MAKE_SET(3, col1, col2)
THEN @n + 1 -- if we are in the same group
ELSE 1 -- next group starts so we reset the counter
END AS row_number,
@v := MAKE_SET(3, col1, col2) -- we store the current value for next iteration
FROM Table1, (SELECT @n := 0, @v := NULL) r -- helper table for iteration with startup values
ORDER BY col1, col2, col3 DESC -- because we want the row with maximum value
) x WHERE row_number = 1 -- and here we select exactly the wanted row from each group
3 は、MAKE_SET の最初のパラメーターで、SET に両方の値が必要であることを意味します (3=1|2)。もちろん、グループを構成する列が 2 つ以上ない場合は、MAKE_SET 操作を省略できます。造りは全く同じです。これは必要に応じて機能しています。明確なデモンストレーションをしてくれた Pinal Dave に感謝します。
これは、複数の列がある場合に RowNumber を作成するのに完全に機能します。この場合は 2 列です。
SELECT @row_num := IF(@prev_value= concat(`Fk_Business_Unit_Code`,`NetIQ_Job_Code`), @row_num+1, 1) AS RowNumber,
`Fk_Business_Unit_Code`,
`NetIQ_Job_Code`,
`Supervisor_Name`,
@prev_value := concat(`Fk_Business_Unit_Code`,`NetIQ_Job_Code`)
FROM (SELECT DISTINCT `Fk_Business_Unit_Code`,`NetIQ_Job_Code`,`Supervisor_Name`
FROM Employee
ORDER BY `Fk_Business_Unit_Code`, `NetIQ_Job_Code`, `Supervisor_Name` DESC) z,
(SELECT @row_num := 1) x,
(SELECT @prev_value := '') y
ORDER BY `Fk_Business_Unit_Code`, `NetIQ_Job_Code`,`Supervisor_Name` DESC