简体   繁体   中英

MySQL UNION and PHP, not friends?

Whatever I do, I cannot get this code to echo $done .

Here is an excerpt from my code that I just cannot get to work for the life of me. I have tried it five different ways, but nothing is working. My only conclusion is that it doesn't work because of UNION.

Is there a way around this? Or is this even the problem?

$query01 = "SELECT COUNT(DISTINCT report) AS ip 
                FROM reports 
                    WHERE country =  '".$country."' 
                    AND YEAR(date) = '2011' 
                    AND MONTH(date) = '".$i."' AND 
                    status ='IP' 
        UNION
            SELECT COUNT(DISTINCT report) AS done 
                FROM reports 
                    WHERE country =  '".$country."' 
                    AND YEAR(date) = '2011' 
                    AND MONTH(date) = '".$i."' 
                    AND status ='DONE'";

$result01 = mysql_query($query01);

while ($row01 = mysql_fetch_array($result01)) {
    $ip = $row01['ip'];
    $done = $row01['done'];
    $all = $ip + $done;

    if($all>0){
        echo "<td>".$ip.":".$done."</td>";
    }

    else{
        echo "<td>-</td>";
    }

}

I guess you are trying to get the ip and done as two columns of each row in which case UNION is not the right choice for the query you have.

Try this:

    $query01 = "SELECT a.ip, b.done 
  FROM 
    (
    SELECT COUNT(DISTINCT report) AS ip 
                    FROM reports 
                        WHERE country =  '".$country."' 
                        AND YEAR(date) = '2011' 
                        AND MONTH(date) = '".$i."' AND 
                        status ='IP' 
        ) a,
        (
                SELECT COUNT(DISTINCT report) AS done 
                    FROM reports 
                        WHERE country =  '".$country."' 
                        AND YEAR(date) = '2011' 
                        AND MONTH(date) = '".$i."' 
                        AND status ='DONE'
        ) b";

    $result01 = mysql_query($query01);

    while ($row01 = mysql_fetch_array($result01)) {
        $ip = $row01['ip'];
        $done = $row01['done'];
        $all = $ip + $done;

        if($all>0){
            echo "<td>".$ip.":".$done."</td>";
        }

        else{
            echo "<td>-</td>";
        }

    }

Things you need to understand about UNION:

  • UNION appends rows together, it doesn't put them side-by-side as columns.
  • The column names are determined by the first query in the UNION, and can't change. So your column will be named ip , and the name done you define in your second query is ignored.

I'd recommend using GROUP BY for this query instead of UNION. Then process the results by row. Here's an example (untested):

$query01 = "SELECT status, COUNT(DISTINCT report) AS c
            FROM reports 
            WHERE country = '{$country}' 
              AND date between '2011-{$i}-01' AND '2011-{$i}-32' 
              AND status IN ('IP','DONE')
            GROUP BY status";

$result01 = mysql_query($query01);

$status_count = array("IP"=>0, "DONE"=>0);
while ($row01 = mysql_fetch_array($result01)) {
    $status_count[ $row01["status"] ] = $row01["c"];
}

if (array_sum($status_count) > 0) {
    echo "<td>{$status_count["IP"]}:{$status_count["DONE"]}</td>";
}

else {
    echo "<td>-</td>";
}

Your UNION is unioning two queries that have different columns: one of them has a single column named ip , the other has one named done . It's possible that MySQL is returning a result set with the column named ip because that is the first name it encounters for this column. The values of the done column are concatenated to the values of the ip column, but the column already has the name ip . There is no column named done . Maybe try:

$query01 = "SELECT COUNT(DISTINCT report) AS report_count, 'ip' as indicator 
                FROM reports 
                    WHERE country =  '".$country."' 
                    AND YEAR(date) = '2011' 
                    AND MONTH(date) = '".$i."' AND 
                    status ='IP' 
        UNION
            SELECT COUNT(DISTINCT report) AS report_count, 'done' as indicator 
                FROM reports 
                    WHERE country =  '".$country."' 
                    AND YEAR(date) = '2011' 
                    AND MONTH(date) = '".$i."' 
                    AND status ='DONE'";

Now both of the queries have the same columns, you can choose to print the row where indicator = 'done' .

When you do a union query, the number of columns in each component have to match (yours do), and the aliases in the FIRST query issued will be how the column names will be returned to the client (your script). In your case, you'll only ever have an ip column - there will never be a done column.

if you need to distinguish where each row in the results came from (which component query issued that), you can create a virtual column to indicate source:

SELECT 'ip' as src, COUNT(...) as cnt
UNION
SELECT 'done' as src, COUNT...) as cnt

so now you'll have two columns being returned, and can access them as $row['src'] and $row['cnt'] .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM