web-dev-qa-db-ja.com

あるテーブルのカンマ区切りのIDを別のテーブルのIDに関連付ける方法は?

varchar(255)フィールドがJdatabasecommasで区切られた値を含むテーブル。正確には、カンマで区切られた数値が含まれています。

Table 1

カスタム[〜#〜] php [〜#〜]モジュールを使用して個々の値を取得したい。実際には、IDのコンマ区切りリストに存在するIDを持つ別のテーブルからレコード(データを取得)を選択する必要があります。

enter image description here

これを達成するための最良の方法は何でしょうか?

4
saibbyweb

最初にカンマを選択し、次にIDがその文字列内にあるかどうかを確認するだけの2つの単純なクエリ。ちょうどテストされ、$db->loadResult()からフェッチされた$commas文字列値を持つMySql IN()関数を使用して機能します。

もっと簡単なことはできません。

// First get all commas
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$query->select($db->qn('Commas'))
      ->from($db->qn('#__classes_attended'))
      ->where($db->qn('Id') . ' = 1');
$db->setQuery($query);

$commas = $db->loadResult();


// Select them from second table
$query = $db->getQuery(true);
$query->clear();
$query->select($db->qn('Data_needed'))
      ->from($db->qn('#__jdatabse_table_2'))
      ->where($db->qn('Id') . ' IN (' . $commas . ')');
$db->setQuery($query);

$results = $db->loadObjectList();
5
Adam M.

これを達成するための最良の方法は何でしょうか?

この質問について、私が共有しなければならない「ベストプラクティス」は2つあります。

  1. 必要以上にデータベースにアクセスしないでください。

    クエリロジックは単一のクエリにベイクできるため、そうする必要があります。このインスタンスで呼び出すヒーローは FIND_IN_SET() です。 INと同じように機能しますが、 INは、カンマ区切りの列値では機能しません です。

    生のクエリ:( db-fiddle.com demo

    _SELECT name
    FROM `#__table2`
    WHERE FIND_IN_SET(id, (SELECT classes_attended FROM `#__table1` WHERE id = 1))
    _

    *これはサブクエリの代わりにJOINとして実行することもできます(スニペットの上のstackoverflowリンクに示されているように)が、1つの行に一度だけ関連付ける必要があるため、この方法をお勧めします。

    Joomla/PHP構文:(ローカルでテスト済み。クエリダンプとエラーチェックが含まれます)

    _$id = 1;
    try {
        $db = JFactory::getDbo();
    
        $subquery = $db->getQuery(true)
                       ->select($db->qn("classes_attended"))
                       ->from($db->qn("#__table1"))
                       ->where($db->qn("id") . " = " . (int)$id);
    
        $query = $db->getQuery(true)
                    ->select($db->qn("name"))
                    ->from($db->qn("#__table2"))
                    ->where("FIND_IN_SET(" . $db->qn("id") . ", (" . $subquery . "))");
    
        $db->setQuery($query);
        JFactory::getApplication()->enqueueMessage($query->dump(), 'info');  // don't show your rendered query to the public
        if (!$result = $db->loadColumn()) {
            echo "<p>No Rows Found</p>";
        } else {
            echo "<pre>";
            var_export($result);  // prints indexed single-dimensional array of values
            echo "</pre>";
        }
    } catch (Exception $e) {
        JFactory::getApplication()->enqueueMessage("Query Syntax Error: " . $e->getMessage(), 'error');  // don't show $e->getMessage() to public
    }
    _
  2. データ構造を正規化します。

    FIND_IN_SET()の使用は、データベース設計が最適化されていないことを示しています。

    私の言葉を理解しないでください Bill Karwin -文字通り書いた人 悪いSQLコーディング慣行に関する本 を聞いてください。

    このクエリをインデックスで最適化することはできません。これは、値のコンマ区切りのリストを格納することがリレーショナルデータベースで悪い考えである理由の1つです。

    ソース: https://stackoverflow.com/a/44183060/29434

    この場合のデータの正規化とは、新しいテーブルを作成し、_classes_attended_データをidおよび_class_attended_を含む行に抽象化することを意味します。そうすることで、データのクエリが容易になり、より複雑なクエリを効率よく作成できるようになります。

    _    id    |    classes_attended
    -----------------------------------
         1    |        1,3,6,7
    _

    なる

    _    id    |    class_attended
    ---------------------------------
         1    |          1
         1    |          3
         1    |          6
         1    |          7
    _

    正規化 に関する初心者向けのリンクを以下に示します。

1
mickmackusa