8

問題

People、Phones、Emails の 3 つのテーブルがあります。各人は一意の ID を持ち、各人は複数の番号または複数の電子メールを持つことができます。

簡略化すると、次のようになります。

    +---------+----------+
    | ID      | Name     |
    +---------+----------+
    | 5000003 | Amy      |
    | 5000004 | George   |
    | 5000005 | John     |
    | 5000008 | Steven   |
    | 8000009 | Ashley   |
    +---------+----------+

    +---------+-----------------+
    | ID      | Number          |
    +---------+-----------------+
    | 5000005 | 5551234         |
    | 5000005 | 5154324         |
    | 5000008 | 2487312         |
    | 8000009 | 7134584         |
    | 5000008 | 8451384         |
    +---------+-----------------+

+---------+------------------------------+
| ID      | Email                        |
+---------+------------------------------+
| 5000005 | Smithley@goodmail.com.com    |
| 5000005 | Smithley.j@gmail.com         |
| 5000008 | Smithley@gmail.com           |
| 5000008 | tech@goodmail.com            |
| 5000008 | feler@campus.uni.com         |
| 8000009 | Ashley.hill86@gmail.com      |
| 5000004 | georgestanko@hotmail.com     |
+---------+------------------------------+

重複することなくそれらを結合しようとしています。People とのメールのみ、または People との電話のみに参加しようとすると、うまく機能します。

SELECT People.Name, People.ID, Phones.Number
    FROM People 
    LEFT OUTER JOIN Phones ON People.ID=Phones.ID 
    ORDER BY Name, ID, Number;
+----------+---------+-----------------+
| Name     | ID      | Number          |
+----------+---------+-----------------+
| Steven   | 5000008 | 8451384         |
| Steven   | 5000008 | 24887312        |
| John     | 5000005 | 5551234         |
| John     | 5000005 | 5154324         |
| George   | 5000004 | NULL            |
| Ashley   | 8000009 | 7134584         |
| Amy      | 5000003 | NULL            |
+----------+---------+-----------------+

SELECT People.Name, People.ID, Emails.Email
    FROM People 
    LEFT OUTER JOIN Emails ON People.ID=Emails.ID 
    ORDER BY Name, ID, Email;
+----------+---------+------------------------------+
| Name     | ID      | Email                        |
+----------+---------+------------------------------+
| Steven   | 5000008 | Smithley@gmail.com           |
| Steven   | 5000008 | tech@goodmail.com            |
| Steven   | 5000008 | feler@campus.uni.com         |
| John     | 5000005 | Smithley@goodmail.com.com    |
| John     | 5000005 | Smithley.j@gmail.com         |
| George   | 5000004 | georgestanko@hotmail.com     |
| Ashley   | 8000009 | Ashley.hill86@gmail.com      |
| Amy      | 5000003 | NULL                         |
+----------+---------+------------------------------+

ただし、People でメールと電話に参加しようとすると、次のようになります。

SELECT People.Name, People.ID, Phones.Number, Emails.Email
    FROM People 
    LEFT OUTER JOIN Phones ON People.ID = Phones.ID
    LEFT OUTER JOIN Emails ON People.ID = Emails.ID 
    ORDER BY Name, ID, Number, Email;

+----------+---------+-----------------+------------------------------+
| Name     | ID      | Number          | Email                        |
+----------+---------+-----------------+------------------------------+
| Steven   | 5000008 | 8451384         | feler@campus.uni.com         |
| Steven   | 5000008 | 8451384         | Smithley@gmail.com           |
| Steven   | 5000008 | 8451384         | tech@goodmail.com            |
| Steven   | 5000008 | 24887312        | feler@campus.uni.com         |
| Steven   | 5000008 | 24887312        | Smithley@gmail.com           |
| Steven   | 5000008 | 24887312        | tech@goodmail.com            |
| John     | 5000005 | 5551234         | Smithley@goodmail.com        |
| John     | 5000005 | 5551234         | Smithley.j@gmail.com         |
| John     | 5000005 | 5154324         | Smithley@goodmail.com        |
| John     | 5000005 | 5154324         | Smithley.j@gmail.com         |
| George   | 5000004 | NULL            | georgestanko@hotmail.com     |
| Ashley   | 8000009 | 7134584         | Ashley.hill86@gmail.com      |
| Amy      | 5000003 | NULL            | NULL                         |
+----------+---------+-----------------+------------------------------+

何が起こるか - Person が 2 つの番号を持っている場合、彼のすべてのメールが 2 回表示されます (並べ替えることができません!つまり、@last で削除することはできません)。

私が欲しいもの:

要するに、@last で遊んで、このようなものになりたいのですが、ORDER 列を正しい方法で配置しないと @last は機能しません。これは大きな問題のように思えます。メール欄。上記の例からわかるように:

スティーブンは 2 つの電話番号と 3 つの電子メールを持っています。数値を使用した JOIN 電子メールは各電子メールで発生するため、ソートできない重複値 (SORT BY は機能しません)。

**THIS IS WHAT I WANT**
+----------+---------+-----------------+------------------------------+
| Name     | ID      | Number          | Email                        |
+----------+---------+-----------------+------------------------------+
| Steven   | 5000008 | 8451384         | feler@campus.uni.com         |
|          |         | 24887312        | Smithley@gmail.com           |
|          |         |                 | tech@goodmail.com            |
| John     | 5000005 | 5551234         | Smithley@goodmail.com        |
|          |         | 5154324         | Smithley.j@gmail.com         |
| George   | 5000004 | NULL            | georgestanko@hotmail.com     |
| Ashley   | 8000009 | 7134584         | Ashley.hill86@gmail.com      |
| Amy      | 5000003 | NULL            | NULL                         |
+----------+---------+-----------------+------------------------------+

多くの電子メールがある可能性があるため、電子メールと番号を別々の表に保持するのが最善であると言われました。それで、それがとても一般的なことなら、簡単な解決策がないのは何ですか?

PHPソリューションにも満足しています。

私が今までに知っていることは、それを満足させますが、それほどきれいではありません.

GROUP_CONTACT でそれを行うと、満足のいく結果が得られますが、見栄えがよくありません。「Email type = work」をその隣に置くことはできません。

   SELECT People.Ime,  
    GROUP_CONCAT(DISTINCT Phones.Number),  
    GROUP_CONCAT(DISTINCT Emails.Email)  
    FROM People 
    LEFT OUTER JOIN Phones ON People.ID=Phones.ID
    LEFT OUTER JOIN Emails ON People.ID=Emails.ID
    GROUP BY Name;
+----------+----------------------------------------------+---------------------------------------------------------------------+
| Name     | GROUP_CONCAT(DISTINCT Phones.Number)         | GROUP_CONCAT(DISTINCT Emails.Email)                                 |
+----------+----------------------------------------------+---------------------------------------------------------------------+
| Steven   | 8451384,24887312                             | Smithley@gmail.com,tech@goodmail.com,feler@campus.uni.com           |
| John     | 5551234,5154324                              | Smithley@goodmail.com,Smithley.j@gmail.com                          |
| George   | NULL                                         | georgestanko@hotmail.com                                            |
| Ashley   | 7134584                                      | Ashley.hill86@gmail.com                                             |
| Amy      | NULL                                         | NULL                                                                |
+----------+----------------------------------------------+---------------------------------------------------------------------+
4

3 に答える 3

1

あなたが望むものは実際にはあなたが望むものではありません、それが理にかなっているなら...あなたはデータベース出力でプログラム的に何かを現実的に行うことができない、あなたはそれで何かをする必要があります(あなたがクエリを実行しているだけでない限り)データベースに直接)。

そして、あなたが「PHPソリューションにも満足している」と言ったので。...本当に必要なのは、PHPの「ユーザー」オブジェクトのようなものです(これはもちろんすべて架空のものです)。

<?php

class User {

  private $_id;
  private $_telNos = array();
  private $_emails = array();

  public function __construct($iUserId = null, $oDatabaseAbstractionObject = null) {
    if(!is_null($iUserId)) $this->setId($iUserId);
    if(!is_null($oDatabaseConnectionObject)) $this->load($iUserId, $oDatabaseAbstractionObject);
  }

  public setId($iUserId) {
    $this->_id = (int) $iUserId;
  }

  public getId() {
    return $this->_id;
  }

  /* telephone and email setters and getters */

  public function load($iUserId, $oDatabaseAbstractionObject) {
    /* error trapping - for example if $iUserId is null */

    $this->setTelNos($oDatabaseAbstractionObject->readTelNos($iUserId));
    $this->setEmails($oDatabaseAbstractionObject->readEmails(iUserId));
  }
}

?>

次に、データベース抽象化オブジェクトは、ユーザー、ユーザーの電子メール、電話番号のテーブルを読み取り、結果を配列として返すためにいくつかの非常に単純なクエリを実行する必要があります。これをPHPオブジェクトに直接配置できます。例えば:

<?php

/**
 * this implements a database connection object as a private class member
 */
class DBUser {

  private $_conn;

  /* constructor other functionality */

  /**
   * method to pass an SQL query to the database and return an array of results
   */
  public function readTelNos($iUserId) {
    return $this->_conn->read("SELECT `number` from `tel` WHERE `user_id` = " . (int) $iUserId);
  }

}
?>

これにより、問題がより小さく、より扱いやすい問題に分割され、実際に操作できる優れたPHPオブジェクトにすべてがまとめられます。

ユーザーオブジェクトには、次のようなもので簡単に取得できる電話番号と電子メールのリストがあり$oUser->getEmails();、オブジェクト内に連想配列として保存されている場合は、「ラベル」で取得することもできます。$oUser->getEmail('work');

于 2012-11-23T17:02:01.627 に答える
1

私が正しく理解している場合は、他のフィールドを電子メールに関連付ける必要もあります (例: タイプ)。

group_concat を使用すると、結果に電子メールの種類を追加できます。私の例では ";" タイプからメールを分離し、"," で結果を分離します。

SELECT u.name,  
    GROUP_CONCAT( distinct p.phone),  
    GROUP_CONCAT( distinct 'mail=',e.mail,';type=' ,type)  
    FROM people u
    LEFT OUTER JOIN phone p ON u.id=p.id
    LEFT OUTER JOIN mail e ON u.id=e.id
    GROUP BY u.id
于 2012-11-23T20:41:24.730 に答える
0

まずレコードを挿入するより一時テーブル名 temp_tb を作成します。次に、Row_Number() を使用してパーティションを作成し、リストされているすべてのレコードを複数回削除します。与えられた打撃のように。

    Insert into temp_tb SELECT People.Name, People.ID, Phones.Number, Emails.Email
    FROM People 
    LEFT OUTER JOIN Phones ON People.ID = Phones.ID
   LEFT OUTER JOIN Emails ON People.ID = Emails.ID 
   ORDER BY Name, ID, Number, Email;
   SELECT * from temp_tb 
    With A as
  (
 select People.Name, People.ID, Phones.Number, Emails.Email ROW_NUMBER() 
  OVER (Partition by ID ORDER BY Fee_temp.Name) As Number from temp_tb 
 )
 DELETE FROM A WHERE Number>1
 SELECT * FROM temp_tb 

お役に立てば幸いです。

于 2014-06-20T12:30:23.443 に答える