他のテーブルへのいくつかのキーを含むテーブルがあります(各キーは複数の列で構成されています)。等しいキーを持つ行をグループ化したいのですが、allをグループ化したくありません。単純ではないGROUP BY
キーについてですが、たとえば、10のグループを作成できるようにしたいと考えています。したがって、特定のキーが50回表示された場合、このグループ化(10の5グループ)を実行すると、5つの結果が得られます。また、このグループ化がキー内でランダムに発生するようにします。
これを行う直接的な方法を知りませんでした。私が思いついたラウンドアバウト方式は、思ったように機能しません。私が思いついたラウンドアバウトの解決策は、値i
がそのキーのith
オカレンスを表す(ただしランダムな順序で)ような整数である各キーの新しい列を作成することでした。次に、整数の除算を実行して、キー内のすべてのn(たとえば10)行が同じ値になるようにし、GROUP BY
その値。
今説明したことを達成するためのより直接的な方法はありますか?これはかなり厄介で、新しいインデックス列を作成するときに問題が発生しました( この質問 で説明したとおり)。
編集:まず、これはMySQL用であることに注意してください。目標が明確でない場合に備えて、例を追加します。 MySQLのドキュメントには、ほとんどそこに を取得するメソッドが示されています 。
CREATE TABLE animals (
grp ENUM('fish','mammal','bird') NOT NULL,
id MEDIUMINT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (grp,id)
) ENGINE=MyISAM;
INSERT INTO animals (grp,name) VALUES
('mammal','dog'),('mammal','cat'),
('bird','penguin'),('fish','lax'),('mammal','whale'),
('bird','ostrich');
SELECT * FROM animals ORDER BY grp,id;
これは、私が望むものではありませんが、近くなるテーブルを作成します:
+--------+----+---------+
| grp | id | name |
+--------+----+---------+
| fish | 1 | lax |
| mammal | 1 | dog |
| mammal | 2 | cat |
| mammal | 3 | whale |
| bird | 1 | penguin |
| bird | 2 | ostrich |
+--------+----+---------+
私は本質的にGROUP BY
id、ただしmammal
のレコードにID 1〜10の「グループ」を1つ、ID 11〜20の別の「グループ」を作成する場合を除きます。ただし、これは既存のテーブル、そして私は必ずしも "犬"がID 1で表示されることを望みません。その最初の順序をランダムにしたいのですが、その後は決定論的です。
グループを動的に生成するために、ID列に対して少し計算を行うとどうでしょうか。
SELECT grp, FLOOR(id/10) AS id_grp
FROM animals
GROUP BY grp, id_grp
これにより、レコードのIDに基づいて10のグループが得られます。上記の動物の表を使用して、以下のデータを生成しました。
サンプルデータ
INSERT INTO animals VALUES
('mammal',10,'dog'),('mammal',11,'dog'),('mammal',12,'dog'),
('mammal',21,'cat'),('mammal',22,'cat'),('mammal',23,'cat'),
('mammal',24,'cat'),('mammal',25,'cat'),('mammal',26,'cat'),
('bird',30,'penguin'),('bird',31,'penguin'),('bird',32,'penguin'),
('bird',33,'penguin'),('fish',44,'lax'),('fish',45,'lax'),
('fish',46,'lax'),('fish',47,'lax'),('fish',48,'lax'),
('mammal',31,'whale'),*'fish',51,'lax'),('fish',52,'lax'),
('fish',53,'lax'),('fish',54,'lax'),('bird',10,'ostrich');
クエリ出力
+--------+--------+
| grp | id_grp |
+--------+--------+
| fish | 4 |
| fish | 5 |
| mammal | 1 |
| mammal | 2 |
| mammal | 3 |
| bird | 1 |
| bird | 3 |
+--------+--------+
7 rows in set (0.00 sec)
SQLでは通常、次のようになります。
集合体ではないため、GROUP BYは必要ありません
編集:
実際、 [〜#〜] ntile [〜#〜] は、「個別の値のセットごとにnバケット」を作成するのに十分です
私はまだ完全なソリューション(実際にはMySQLで動作する)をまだ見ていません。そのため、これはおそらく私が使用するソリューションです。
私はまだ誰かがこの答えを打つことができることを望んでいます。自分の答えを受け入れたくありません。私は以前にこれを言ったことがありますが、最初から2番目の方法を知っていました。 #1は私を悩ませているものです。 #1に答えることができる場合、実際には 別の質問 にも答えますが、この質問に他の方法で答えて#1をバイパスすることができる場合があります。
-- Change 'ValueField' to whatever provides your 'group' values
set @rownum := 0;
set @groupnum := 0;
set @lastGroup := 0;
select
ValueField,
Grouping,
count(1) as Count
from
(
-- We have a row number for each record
select
-- Set the record number
case when @lastGroup != ValueField
then @rownum := 0 else (@rownum := @rownum + 1)
end as Record,
-- Determine which group we are in
case
-- If the 'Group' changed, reset our grouping
when @lastGroup != ValueField
then @groupnum := 0
-- Determines the grouping value; group size is set to 10
when floor(@rownum / 10) != @groupnum
then @groupnum := @groupnum + 1
else @groupnum
end as Grouping,
-- Track the last Group
case
when @lastGroup != ValueField
then @lastGroup := ValueField
else @lastGroup
end as LastGroup,
-- Value field that will be aggregated
ValueField
from
YourTable
order by
ValueField
) as x
group by
ValueField,
Grouping;