1

こんばんは、私は Web プログラミングの初心者で、SQL クエリに固有の問題を解決するためにあなたの助けが必要です。私が使用しているデータベース エンジンは MySQL で、PHP 経由でアクセスします。ここでは、アイデアを修正するために、単純化したバージョンのデータベースについて説明します。teamsteams_information、の 3 つのテーブルを含むデータベースで作業するとしますattributes。より正確に:

1)teamsは、イタリアのサッカー チーム (アメリカン フットボールではなく、サッカー) に関するいくつかの基本的な情報を含むテーブルで、次の 3 つのフィールドで構成されています: 'id' ( int, primary key), 'name' (varchar, チーム名), nickname( Varchar, チーム ニックネーム) ;

2)は、 (チームがホーム マッチを行う都市)、(チーム キャプテンのフルネーム)、(ファンの数)attributesなど、サッカー チームに関する可能な情報のリストを含むテーブルです。このテーブルは、 id 、( 、属性の識別子)、(テキスト、属性の意味の説明) の3 つのフィールドで形成されます。このテーブルの各レコードは、サッカー チームの 1 つの可能な属性を表します。citycaptainf_number(int, primary key)attribute_namevarcharattribute_desc

3)teams_informationは、表にリストされているチームに関するいくつかの情報teamが利用可能な表です。このテーブルには、id ( int、主キー)、team_id( int、チームを識別する外部キー)、 attribute_id( 、テーブルintにリストされた属性の 1 つを識別する外部キー)、 ( 、属性の値) の 3 つのフィールドが含まれます。各レコードは、1 つのチームの 1 つの属性を表します。一般に、チームが異なれば情報の数も異なるため、一部のチームでは多数の属性を使用できますが、他のチームでは少数の属性しか使用できません。attributesattribute_valuevarchar

と の関係は 1 対多であり、との間teamsteams_informationは同じ関係が存在することに注意してください。attributesteams_information

さて、このモデルを考えると、私の目的は (おそらく ExtJS 4.1 を使用して) グリッドを実現してイタリアのサッカー チームのリストをユーザーに表示することです。このグリッドの各レコードは単一のサッカー チームを表し、すべての可能な属性を含みます。空 (考慮されたチームの場合、対応する属性が不明であるため) であり、その他の属性にはteams_information(考慮されたチームの) テーブルに格納された値が含まれます。上記のグリッドのフィールドによると、id、team_name、および「属性」テーブルにリストされているすべての異なる属性を表す多数のフィールドがあります。

私の質問は: SINGLE SQL クエリ (SELECTデータベース テーブルから必要なすべてのデータを取得するための適切なクエリ) を使用して、このようなグリッドを実現できますか? 同様のクエリを作成する方法を誰かに提案できますか (存在する場合)。

助けてくれてありがとう。

よろしく。

エンリコ。

4

4 に答える 4

3

あなたの質問に対する簡単な答えはノーです。MySQL には、探している結果セットを実現するための単純な構造はありません。

しかし、そのようなクエリを慎重に (苦労して) 作成することは可能です。これが例です。あなたなら解読できると思います。基本的に、返される属性ごとに、選択リストで相関サブクエリを使用しています。

SELECT t.id
     , t.name
     , t.nickname

     , ( SELECT v1.attribute_value 
           FROM team_information v1 
           JOIN attributes a1
             ON a1.id = v1.attribute_id AND a1.attribute_name = 'city'
          WHERE v1.team_id = t.id ORDER BY 1 LIMIT 1
       ) AS city

     , ( SELECT v2.attribute_value
           FROM team_information v2 JOIN attributes a2
             ON a2.id = v2.attribute_id AND a2.attribute_name = 'captain'
          WHERE v2.team_id = t.id ORDER BY 1 LIMIT 1
       ) AS captain

     , ( SELECT v3.attribute_value
           FROM team_information v3 JOIN attributes a3
             ON a3.id = v3.attribute_id AND a3.attribute_name = 'f_number'
          WHERE v3.team_id = t.id ORDER BY 1 LIMIT 1
       ) AS f_number

  FROM teams t
 ORDER BY t.id

「多値」属性の場合、属性の各インスタンスを個別に取得する必要があります。(LIMIT を使用して、最初のもの、2 番目のものなどを取得するかどうかを指定します。)

     , ( SELECT v4.attribute_value
           FROM team_information v4 JOIN attributes a4
             ON a4.id = v4.attribute_id AND a4.attribute_name = 'nickname'
          WHERE v4.team_id = t.id ORDER BY 1 LIMIT 0,1
       ) AS nickname_1st

     , ( SELECT v5.attribute_value
           FROM team_information v5 JOIN attributes a5
             ON a5.id = v5.attribute_id AND a5.attribute_name = 'nickname'
          WHERE v5.team_id = t.id ORDER BY 1 LIMIT 1,1
       ) AS nickname_2nd

     , ( SELECT v6.attribute_value
           FROM team_information v6 JOIN attributes a6
             ON a6.id = v6.attribute_id AND a6.attribute_name = 'nickname'
          WHERE v6.team_id = t.id ORDER BY 1 LIMIT 2,1
       ) AS nickname_3rd

ここでは例としてニックネームを使用します。アメリカのサッカー クラブには複数のニックネームがあることが多いためです。たとえば、シカゴ ファイアー サッカー クラブには、'The Fire'、'La Máquina Roja'、'Men in Red'、'CF97' などのニックネームがあります。 .)

あなたの質問への回答ではありませんが...

以前に何度も言いましたが、EAV データベースの実装を扱うのがどれだけ嫌いですか? IMO は非常に単純なクエリである必要がありますが、非常に複雑な、潜在的に明るい調光クエリの獣になります。

各「属性」が個別の列であるテーブルを作成する方がはるかに簡単ではないでしょうか? 次に、妥当な結果セットを返すクエリは、より妥当に見えます...

SELECT id, name, nickname, city, captain, f_number, ... FROM team

しかし、本当に身震いするのは、「より単純な」クエリを有効にするために、一部の開発者が LDQ をビューとしてデータベースに「隠す」必要があると判断する可能性があることです。

このルートに進む場合は、このクエリをビューとしてデータベースに保存する必要があるかもしれないという衝動に抵抗してください。

于 2012-06-21T21:14:34.880 に答える
1

ちょっと変わったルートで行きます。スペンサーの答えは素晴らしいもので、この問題にうまく対処していますが、根本的な問題はまだ残っています。

サイトに表示しようとしているデータは、データベースで過度に正規化されています。繰り返しますが、スペンサーの回答は問題をかなり強調しているため、詳しくは説明しません。

むしろ、データを少し非正規化するソリューションをお勧めします。

すべてのチーム データを、多数の列を持つ 1 つのテーブルに変換します。(質問でカバーされていないプレイヤー データがある場合、それは 2 番目のテーブルになりますが、今のところは省略します。)

確かに、たくさんの列があり、多くの行に対して多くの列が NULL である可能性があります。これは正規化されておらず、見栄えもよくありませんが、大きなメリットがあります。

クエリは次のようになります。

SELECT * FROM Teams

それでおしまい。それはウェブサイトに直接表示され、完了です。このスキーマを実現するためには多大な努力が必要になるかもしれませんが、時間をかけるだけの価値は十分にあります。

于 2012-06-22T20:44:59.147 に答える
0

私は、問題を解決するためのスペンサーのアイデアを一般化するための簡単なPHPスクリプトを作成しました。コードは次のとおりです。

<?php
    require_once('includes/db.config.php'); //this file performs connection to mysql

/*
 * Following function requires a table name ($table)
 * and a number of service fields ($num). Given those parameters
 * it returns the number of table fields (excluding service fields). 
 */

function get_fields_number($table,$num,$conn)
{   
    $query = "SELECT * FROM $table";
    $result = mysql_query($query,$conn);
    return mysql_num_fields($result)-$num; //remember there are $num service fields
}

/*
 * Following function requires a table name ($table) and an array
 * containing a list of service fields names. Given those parameters, 
 * it returns the list of field names. That list is contained within an array and
 * service fields are excluded.
 */

function get_fields_name($table,$service,$conn)
{
    $query = "SELECT * FROM $table";
    $result = mysql_query($query,$conn);
    $name = array(); //Array to be returned
    for ($i=0;$i<mysql_num_fields($result);$i++)
    {
        if(!in_array(mysql_field_name($result,$i),$service))
    {
       //currently selected field is not a service field
       $name[] = mysql_field_name($result,$i); 
    }
    }
    return $name;
}

//Below $conn is db connection created in 'db.config.php'

$query = "SELECT `name` FROM  `detail_arg` WHERE visibility = 0";
$res = mysql_query($query,$conn);
if($res===false)
{
    $err_msg = mysql_real_escape_string(mysql_error($conn));
    echo "{success:false,data:'".$err_msg."'}";
    die();
}
$arg = array(); //list of argument names
while($row = mysql_fetch_assoc($res))
{
    $arg[] = $row['name'];
}

//Following function writes the select subquery which is
    //necessary to build a column containing a single attribute.

function make_subquery($attribute) //$attribute contains attribute name
{
    $query = "";
    $query.="(SELECT incident_detail.arg_value ";
    $query.="FROM incident_detail ";
    $query.="INNER JOIN detail_arg ";
    $query.="ON incident_detail.arg_id = detail_arg.id AND      detail_arg.name='".$attribute."' ";
    $query.="WHERE incident.id = incident_detail.incident_id) ";
    $query.="AS $attribute";
    return $query;
}

/*

echo make_subquery("date"); //debug code

*/

$subquery = array(); //list of subqueries
for($i=0;$i<count($arg);$i++)
{
    $subquery[] = make_subquery($arg[$i]); 
}

$query = "SELECT "; //final query containing subqueries

$fields = get_fields_name("incident",array("id","visibility"),$conn); 
    //list of 'incident' table's fields

for($i=0;$i<count($fields);$i++)
{
    $query.="incident.".$fields[$i].", ";
}

//insert the subqueries

$sub = implode($subquery,", ");
$query .= $sub;

    $query.=" FROM incident ORDER BY incident.id";
echo $query;
?>
于 2012-06-25T08:44:04.973 に答える
0

あなたが言っているのは、属性テーブルの行を結果レコードセットの列として表示したいということだと思います。これが正しければ、SQL では PIVOT を使用します。SO をすばやく検索すると、MySql には PIVOT に相当するものがないことが示されているようです。

于 2012-06-21T20:50:37.193 に答える