0

私を夢中にさせているクエリを作成しようとしています。どこから解決すればよいのかわかりませんでしたが、少し調べた後、サブクエリで遊んでみました。今、それが私の問題を解決するかどうか、または解決する場合は、私が望むものを作成する方法がわからないところまで来ています。

これは、現在のテーブルの非常に単純なビューです (tbl_1 と呼びます)。

---------------------------------
|  row |  name  |  other_names  |
|-------------------------------|
|   1  |   A    |    B, C       |
|   2  |   B    |    C          |
|   3  |   A    |    C          |
|   4  |   D    |    E          |
|   5  |   C    |    A, B       |
---------------------------------

私が扱っているアイテムの中には複数の名前 (ブランド名、他の国での名前、コードネームなど) を持つものがありますが、最終的にはそれらの異なる名前はすべて同じアイテムを指しています。私はもともと、次の行に沿って検索クエリを実行していました。

SELECT * FROM tbl_1
WHERE name LIKE '%A%'
OR other_names LIKE '%A%';

どちらが行 1 と行 3 を返します。しかし、A = B = C として、クエリは行 2 も返す必要があることにすぐに気付きました。すべての名前を何らかの方法で 1 つの行に結合する別のテーブルを構築するなど、派手なクエリ以外の代替提案を受け入れますが、そのようなものはエラーが発生しやすく、非効率的であると考えています。

さらに、InnoDB を使用して MySQL 5.5.23 を実行し、PHP と Python で記述された他のコードを使用しています。

ありがとう!

2012 年 5 月 26 日更新:
サブクエリを使用するという当初の考えに戻りましたが、どこかで取得したと思ったときに、クエリが外部から評価され、サブクエリが評価されるという文書化された MySQL の問題に遭遇しました。行ごとに実行され、現実的な時間では終了しません。これが私がやろうとしていたことです:

SELECT * FROM tbl_1
WHERE name = ANY
    (SELECT name FROM tbl_1 WHERE other_names LIKE '%A%' or name LIKE '%A%')
OR other_names = ANY 
    (SELECT name FROM tbl_1 WHERE other_names LIKE '%A%' or name LIKE '%A%')

サンプルテーブルを使用して必要なものを返しますが、前述のMySQLの問題/バグにより、サブクエリが独立したクエリではなく依存クエリと見なされます。その結果、最終的にタイムアウトになるため、実際のテーブル (〜 250,000 行) でクエリをテストできませんでした。

この問題の主な回避策は、サブクエリではなく結合を使用することであると読みましたが、それを自分がやろうとしていることにどのように適用するかわかりません。考えれば考えるほど、PHP/Python を使用してサブクエリを個別に実行し、結果の配列を使用して必要なメイン クエリを作成する方がよいかもしれません。ただし、列内の用語が私の例ほど適切ではないため、一部の結果を見逃す可能性があると考えています (用語の一部は複数の単語であり、一部は括弧で囲まれ、他の名前は必ずしもカンマではありません)。分離など)。

または、次のような必要なリンクを作成する別のテーブルを作成することを考えています。

| 1 | A | B, C|
| 2 | B | C, A|
| 3 | C | A, B|

しかし、私が扱っているデータと、そのデータが存在する標準化されていない形式を考えると、言うは易く行うは難しだと思います。

現時点で私が強く検討しているルートは、簡単に作成できるリンク (つまり、name:other_names の比率が 1:1) を使用して別のテーブルを作成することです。 other_names 列。結果を簡素化し、おそらく全体的なパフォーマンスを向上させるために、LIKE の使用を排除/制限し、ユーザーが少なくとも 1 つの正確な名前を知っていることを要求することもあります。

結論として、私は自分が制御できない入力データを操作するのが嫌いです。

4

2 に答える 2

1

偶然この質問に出くわしたので、私の提案が関連しているかどうかはわかりませんが、これは「ユニオン検索」のようなものに適しているようです。

SELECT は非常に簡単で高速です。ただし、挿入と更新は比較的複雑であり、おそらくコード内ループ (更新された行 > 0) が必要になるでしょう... およびいくつかのデータベース呼び出し

テーブルの例:

---------------------------
|  row |  name  |  group  |
|-------------------------|
|   1  |   A    |    1    |
|   2  |   B    |    1    |
|   4  |   C    |    1    |
|   5  |   D    |    2    |
|   6  |   X    |    1    |
|   7  |   Z    |    2    |
---------------------------

選択: SELECT name FROM tblWHERE group= (SELECT groupFROM tblWHERE nameLIKE '%A%')


挿入関係 K = T: (疑似コードっぽい..)

SELECT groupas gk WHERE name = K; SELECT groupas gt WHERE name = T;

(gk empty result) と (gt empty result) の場合、新しいグループで両方を挿入します

---------------------------
|  row |  name  |  group  |
|-------------------------|
|   1  |   A    |    1    |
|   2  |   B    |    1    |
|   4  |   C    |    1    |
|   5  |   D    |    2    |
|   6  |   X    |    1    |
|   7  |   Z    |    2    |
|   8  |   K    |    3    |
|   9  |   T    |    3    |
---------------------------

if (gk empty result) and (gt NOT empty result) insert t with group = gx.group

---------------------------
|  row |  name  |  group  |
|-------------------------|
|   1  |   A    |    1    |
|   2  |   B    |    1    |
|   4  |   C    |    1    |
|   5  |   D    |    2    |
|   6  |   X    |    1    |
|   7  |   Z    |    2    |
|   8  |   K    |    2    |
|   9  |   T    |    2    |
---------------------------

(他の場合も同様)

両方が空でない場合は、一方のグループを他方のグループに更新します

UPDATE tbl1SET グループ = gt WHERE グループ = gk

于 2013-01-02T13:08:30.730 に答える
0

無制限の深さの名前アイデンティティをサポートするクエリは考えられません。ただし、限られた数の「再帰」で作業できる場合は、次のようなクエリを使用することを検討してください。指定したクエリから始めて、名前の同一性を持つすべての行を取得します。

SELECT a.* FROM tbl_1 a
WHERE a.name='A'
OR a.other_names LIKE '%A%'
UNION
SELECT b.* FROM tbl_1 a
JOIN tbl_1 b ON a.other_names LIKE '%' || b.name || '%' OR b.other_names LIKE '%' || a.name || '%'
WHERE a.name='A'
OR a.other_names LIKE '%A%';

このクエリは行 2 を返しますが、例では「B」を「other_name」として持つ追加の行は返しません。したがって、別のクエリを結合する必要があります。

SELECT a.* FROM tbl_1 a
WHERE a.name='A'
OR a.other_names LIKE '%A%'
UNION
SELECT b.* FROM tbl_1 a
JOIN tbl_1 b ON a.other_names LIKE '%' || b.name || '%' OR b.other_names LIKE '%' || a.name || '%'
WHERE a.name='A'
OR a.other_names LIKE '%A%';
UNION
SELECT c.* FROM tbl_1 a
JOIN tbl_1 b ON (a.other_names LIKE '%' || b.name || '%' OR b.other_names LIKE '%' || a.name || '%')
JOIN tbl_1 c ON (b.other_names LIKE '%' || c.name || '%' OR c.other_names LIKE '%' || b.name || '%')
WHERE a.name='A'
OR a.other_names LIKE '%A%';

ご覧のとおり、クエリは深さが増すにつれて急速に成長および加速し、私が美しいと呼ぶものでもありません。しかし、それはあなたのニーズに合うかもしれません。私は MySQL 関数の使用経験はあまりありませんが、それらを使用して無制限の深さで動作する、より洗練されたソリューションを作成できると思います。Python を使用してプログラムで問題を解決することも検討してください。

于 2012-05-25T11:19:58.943 に答える