1

私のコードはこれです:

public function procAllianceAttRanking($limit="") {
  $q = "SELECT " . TB_PREFIX . "users.id userid, " . TB_PREFIX . "users.username username, " . TB_PREFIX . "users.alliance allyid, (

  SELECT SUM( " . TB_PREFIX . "vdata.pop ) 
  FROM " . TB_PREFIX . "vdata
  WHERE " . TB_PREFIX . "vdata.owner = userid
  )totalpop, (

  SELECT SUM( " . TB_PREFIX . "alidata.Aap ) 
  FROM " . TB_PREFIX . "alidata
  WHERE " . TB_PREFIX . "alidata.id = allyid
  )totalpoint, (

  SELECT COUNT( " . TB_PREFIX . "users.alliance ) 
  FROM " . TB_PREFIX . "users
  WHERE " . TB_PREFIX . "users.alliance = allyid
  )totalusers

  FROM " . TB_PREFIX . "users
  WHERE " . TB_PREFIX . "users.alliance > 0
  ORDER BY totalpoint DESC, allyid ASC $limit";
  return mysql_query($q);
}

出力コードは次のとおりです。

$sql = $ranking->procAllianceRanking();
$query = mysql_num_rows($sql);
if($query >= 1){ 
  while($row = mysql_fetch_array($sql)){
    if($row['allyid'] == $session->alliance) {
      echo "<tr class=\"hl\"><td class=\"ra fc\" >".$rank.".</td>";
    }else {
      echo "<tr class=\"hover\"><td class=\"ra \" >".$rank.".</td>";
    }
    echo "<td class=\"al \" ><a href=\"allianz.php?aid=".$row['allyid']."\">".$database->getAllianceName($row['allyid'])."</a></td>";

    echo "<td class=\"pla \" >".$row['totalusers']."</td>";
        echo "<td class=\"av \">".round($row['totalpop']/$row['totalusers'])."</td>";
      echo "<td class=\"po lc\">".$row['totalpop']."</td></tr>";
    $rank++;
  }
}

コードの出力は次のとおりです。

Greatest Alliance
   Alliance    player       Ø   points
 1. multii       3          4     11
 2. multii       3          2      6
 3. multii       3          2      6
 4. myallianc    2          5      5
 5. myallianc    2          1      2

しかし、これは正しくありません!!! . 各アライアンスの実際のトラビアンでは、統計では1行にすぎないため、コードの出力は間違っています。各アライアンスの正しい出力は次のようになります。

Greatest Alliance
   Alliance    player       Ø   points
 1. multii       3          8    23
 2. myallianc    2          6    7

すべてのアライアンスは 1 行のみである必要があります

4

1 に答える 1

1

Your query should be written this way:

SELECT 
  u.id userid, 
  u.username username, 
  u.alliance allyid, 
  SUM(v.pop )   AS totalpop, 
  SUM(a.Aap ) AS totalpoint,
  COUNT(ua.alliance ) AS totalusers
FROM users u
INNER JOIN vdata    v ON v.owner     = u.userid
INNER JOIN alidata  a ON a.id        = u.allyid
INNER JOIN users   ua ON ua.alliance = u.allyid
WHERE users.alliance > 0
GROUP BY u.id,
         u.username, 
         u.alliance 
ORDER BY u.totalpoint DESC, 
         u.allyid ASC ;

What I have done in this query:

I JOINed the tables users, vdata, alidata and users again instead of these correlated subqueries that you used in your question. Note that: I joined the table users one more times to get those users that has alliance = u.allyid but with a different alias. Then GROUP BY, with aggregate functions in the same query.

You might also need to use LEFT JOIN instead of INNER JOIN in case you want to include those unmtached data, i.e those users that has no entries in the others tables for example.


Update 1

To test the query against MySQL directly, and since you are using WAMP. Like in the following steps:

  • Ensure that the WAMP server is running:

enter image description here

  • From the task par open the phpMyAdmin:

enter image description here

  • Select your database that you're working with:

enter image description here

  • Navigate to SQL Tab:

enter image description here

  • Paste your query in the window:

enter image description here

  • Then press the button Go.

Update 1

Try this instead:

SELECT 
  u.id               AS userid, 
  u.username         AS username, 
  u.alliance         AS allyid, 
  SUM(v.pop)         AS totalpop, 
  SUM(a.Aap)         AS totalpoint,
  COUNT(ua.alliance) AS totalusers
FROM s1_users u
LEFT JOIN s1_vdata    v ON v.owner     = u.id
LEFT JOIN s1_alidata  a ON a.id        = u.alliance
LEFT JOIN s1_users   ua ON ua.alliance = u.alliance
WHERE u.alliance > 0 
GROUP BY u.id, 
         u.username, 
         u.alliance;

SQL Fiddle Demo

This will give you:

| USERID |    USERNAME | ALLYID | TOTALPOP | TOTALPOINT | TOTALUSERS |
----------------------------------------------------------------------
|      4 | Multihunter |      1 |       18 |          0 |          3 |
|      5 |     tester1 |      1 |       33 |          0 |          3 |
|      6 |     tester2 |      1 |       18 |          0 |          3 |

Note that: I couldn't find a column allyid in the s1_users table, so I joined the table s1_users with s1_alidata with the column alliance and s1_users with itself with the same field alliance. Not sure if this is right or not.


But there is a big problem in your tables' design. Your tables are normalized.

For instance, it seems that the fields Tribe, Access, Gold and Silver are related attributes for each user, so you can move them to a new table something like:

UsersFooProperties:

  • PropertyId,
  • UserId a foreign key to the users table,
  • Tribe,
  • Access,
  • Gold,
  • Silver,
  • Composite key(ProertyId, userid`).

The same for the fields B1, B2, B3 and B4, move them to a new table:

UsersBs:

  • UserId,
  • B1,
  • B2,
  • B3.

However, if these Bs are more than three and there are other properties for this B proeprty, you can create a new table Bs:

Bes:

  • BID,
  • other properties here ...

Then:

UsersBs:

  • UserId,
  • BID,
  • Composite key(Userid, BID).

Another big issue is with those 38 fields: friend1, ... , friend19, friend1wait, ..., friend19wait.

You have to have a separate table for those friends like this:

`UsersFriends:

  • UserId a foreign key to the users table,
  • FriendID,
  • WaitOrNot a flag 0 or 1.

There for you have only one column friend, in this column you can insert all the friends of these 38 columns like this:

UserId FriendId WaitOrNot
  1       1         0
  1       2         1
  1       3         0
  ...
  ...
  1       19        1

Also try to avoid storing mutiple values as a comma separated string value, like what you did in the column FQUEST. Make a new table for it like this:

UsersFQUEST:

  • UserID,
  • FQUESTId.

This was just an example of how you can redesign one of your table users these are just a sample of bad things you have in this table, you have other columns than these that I mentioned. You have also to do the same things for other tables.

For more information, see these:

于 2013-02-05T13:27:36.123 に答える