web-dev-qa-db-ja.com

MYSQL文字列をGROUP_CONCATからIN()が理解できる(配列、like、expression、list)に分割します

この質問は次のように続きます MYSQL結合結果セットはwhere句のIN()中に結果をワイプしましたか?

だから、質問の短いバージョン。 GROUP_CONCATによって返された文字列を、IN()がループする複数の項目のリストとして扱うコンマ区切りの式リストに変換するにはどうすればよいですか?

N.B. MySQLドキュメントは、IN()で使用される「(comma、separated、lists)」を「式リスト」として参照しているように見えます。興味深いことに、IN()のページは多かれ少なかれMySQLドキュメントの唯一のページのようです。式リストを参照してください。したがって、配列または一時テーブルを作成することを目的とした関数がここで使用されるかどうかはわかりません。


質問の長い例ベースのバージョン:次のような2テーブルDBから:

SELECT id, name, GROUP_CONCAT(tag_id) FROM person INNER JOIN tag ON person.id = tag.person_id GROUP BY person.id;
+----+------+----------------------+
| id | name | GROUP_CONCAT(tag_id) |
+----+------+----------------------+
|  1 | Bob  | 1,2                  |
|  2 | Jill | 2,3                  |
+----+------+----------------------+

文字列を使用するため、これを(1 = X)AND(2 = X)..と論理的に同等として扱うにはどうすればよいですか。

SELECT name, GROUP_CONCAT(tag.tag_id) FROM person LEFT JOIN tag ON person.id = tag.person_id 
GROUP BY person.id HAVING ( ( 1 IN (GROUP_CONCAT(tag.tag_id) ) ) AND ( 2 IN (GROUP_CONCAT(tag.tag_id) ) ) );
Empty set (0.01 sec)

... GROUP_CONCATの結果がリストとして扱われるものに、ボブの場合は次のようになります。

SELECT name, GROUP_CONCAT(tag.tag_id) FROM person INNER JOIN tag ON person.id = tag.person_id AND person.id = 1 
GROUP BY person.id HAVING ( ( 1 IN (1,2) ) AND ( 2 IN (1,2) ) );
+------+--------------------------+
| name | GROUP_CONCAT(tag.tag_id) |
+------+--------------------------+
| Bob  | 1,2                      |
+------+--------------------------+
1 row in set (0.00 sec)

...そしてジルにとって、それは以下と同等です:

SELECT name, GROUP_CONCAT(tag.tag_id) FROM person INNER JOIN tag ON person.id = tag.person_id AND person.id = 2 
GROUP BY person.id HAVING ( ( 1 IN (2,3) ) AND ( 2 IN (2,3) ) );
Empty set (0.00 sec)

...したがって、全体的な結果は、HAVING COUNT(DISTINCT ...)を使用しないすべてのリストされたタグを必要とする排他的な検索句になりますか?

(注:このロジックはANDなしで機能し、文字列の最初の文字に適用されます。例:.

SELECT name, GROUP_CONCAT(tag.tag_id) FROM person LEFT JOIN tag ON person.id = tag.person_id 
  GROUP BY person.id HAVING ( ( 2 IN (GROUP_CONCAT(tag.tag_id) ) ) );
+------+--------------------------+
| name | GROUP_CONCAT(tag.tag_id) |
+------+--------------------------+
| Jill | 2,3                      |
+------+--------------------------+
1 row in set (0.00 sec)

IN()を使用する代わりに、FIND_IN_SET()を使用することもオプションでしょうか?

http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_find-in-set

mysql> SELECT FIND_IN_SET('b','a,b,c,d');
    -> 2

これは、質問の問題の例に基づいた完全な例であり、質問の以前の編集で質問者によってテストされたことが確認されています。

SELECT name FROM person LEFT JOIN tag ON person.id = tag.person_id GROUP BY person.id 
  HAVING ( FIND_IN_SET(1, GROUP_CONCAT(tag.tag_id)) ) AND ( FIND_IN_SET(2, GROUP_CONCAT(tag.tag_id)) );
+------+
| name |
+------+
| Bob  |
+------+
38
Wolph

分割区切り文字を使用して文字列を配列として渡し、その結果を処理する関数で展開できます。

簡単な例として、「one | two | tree | four | five」のような文字列配列があり、2つが配列に含まれているかどうかを知りたい場合は、次のように実行できます。

create function str_in_array( split_index varchar(10), arr_str varchar(200), compares varchar(20) )
  returns boolean
  begin
  declare resp boolean default 0;
  declare arr_data varchar(20);

  -- While the string is not empty
  while( length( arr_str ) > 0  ) do

  -- if the split index is in the string
  if( locate( split_index, arr_str ) ) then

      -- get the last data in the string
    set arr_data = ( select substring_index(arr_str, split_index, -1) );

    -- remove the last data in the string
    set arr_str = ( select
      replace(arr_str,
        concat(split_index,
          substring_index(arr_str, split_index, -1)
        )
      ,'')
    );
  --  if the split index is not in the string
  else
    -- get the unique data in the string
    set arr_data = arr_str;
    -- empties the string
    set arr_str = '';
  end if;

  -- in this trivial example, it returns if a string is in the array
  if arr_data = compares then
    set resp = 1;
  end if;

 end while;

return resp;
end
|

delimiter ;

このメソッドで動作する便利なmysql関数のセットを作成したいと思います。興味のある方はご連絡ください。

その他の例については、 http://blog.idealmind.com.br/mysql/how-to-use-string-as-array-in-mysql-and-work-with/ にアクセスしてください。

4
Idealmind