3

我有一种情况,我有几个表,我通过 INNER JOIN 从中提取。存在一对多的关系,主表中每个公园都有一条线,但照片表可能有一些公园的多条线。我的代码的工作原理是为每个公园显示一张照片,但我只能显示一张。我怀疑问题出在 foreach 循环中,但我有点难过。这是代码:

try
{
    $sql = 'SELECT parks.id, parks.state, parks.name, parks.description, parks.site, parks.sname, parks.street, parks.city, parks.zip, parks.phone, comments.comment, comments.commentname, events.event, events.date, events.description2, photos.parkid, photos.type, photos.filename, photos.big FROM parks
            INNER JOIN comments INNER JOIN photos INNER JOIN events ON parks.parkid = comments.parkid and parks.parkid = photos.parkid and parks.parkid = events.parkid
            GROUP BY parks.id
            ORDER BY parks.name asc';
    $result = $pdo->query($sql);
}

catch (PDOException $e)
{
    $error = 'Error fetching data: ' . $e->getMessage();
    include 'output.html.php';
    exit();
}

//This is pulling the information from the database for display. On the foreach it will display each
//line until there are no more lines to display.    
foreach ($result as $row)
{
    $datas[] = array ('id' =>$row['id'],
                'parkid' =>$row['parkid'],
                'state' =>$row['state'], 
                'name' =>$row['name'], 
                'description' =>$row['description'], 
                'site' =>$row['site'], 
                'sname' =>$row['sname'],
                'street' =>$row['street'], 
                'city' =>$row['city'], 
                'phone' =>$row['phone'],
                'zip' =>$row['zip'],
                'commentname' =>$row['commentname'],
                'comment' =>$row['comment'],
                'event' =>$row['event'],
                'date' =>$row['date'],
                'description2' =>$row['description2'],
                'type' =>$row['type'],
                'filename' =>$row['filename'],
                'big' =>$row['big']);
}    
include 'writing.html.php';

<?php    
foreach ($datas as $name)
{
    if ($name['state'] === 'PA') 
    {
?>  
        <a href="#header" title="return to the top of the page">Back to top</a>
        <input type="hidden" name="id" value="' . $name['id'] . '" />
        <h1 id="name"> <?php echo ($name['name']) ?> </h1>
        <p id="descriptionlist">
            <?php echo ($name['description']) ?>
            <br />
            <ul id="link">
                <li class="l1">
                    <a href=<?php echo $name['site'] ?> target="_blank"> <?php echo $name['sname'] ?> </a>
                </li>
            </ul>
        </p>

        <h2>Location</h2>
        <div class = "loc"> 
            <p class="loct">
                <a class = "fancyImg" href="maps/<?php echo $name['id'] ?>state.gif"> <img src= "maps/<?php echo $name['id'] ?>state.gif"> </a>
                <br />
                <php echo ($name['street']) . ?>
                <br />
                <?php echo ($name['city']) .  
                    ($name['state']) .
                    ($name['zip']) ?>
                <br>
                <?php echo ($name['phone']) ?> 
                <br> <br>
            </p>
        </div>

        <h2>Trail Map</h2>
        <div class = "map">
            <p class = "mapt"> 
                Click to Enlarge
                <a class ="fancyImg" href= "/maps/<?php echo $name['id'] ?>maplink.gif">
                    <img src= "/maps/<?php echo $name['id'] ?>.gif"></a> <br> <br> 
            </p>
        </div>

        <h2>Photos</h2>
        <div class = "pho">
            <p class = "phot">
                <a class = "fancyImg" href= "/assets/indiv/<?php echo $name['big'] ?>.gif"> 
                    <img src= "<?php echo $name['filename'] ?>.gif"></a>**
                Submit <i>your</i> photos of <?php echo ($name['name']) ?> through our <ul id = "link"><li><a href="https://www.facebook.com/Ride4Wheel">Facebook Page!</li></ul></a></h3><p> Or go to our Contact Us page for information on how to e-mail us your favorite pictures! 
            </p>
        </div>

手头的问题在此处末尾的 pho div 中。我希望 $name['big'] 能给我这个循环的所有项目,但它只给了我第一个。我在这里缺少一些基本的东西。

链接是http://www.ride4wheel.com/new_ma.php

4

4 回答 4

2

除了您的查询具有一对多关系这一事实之外,关系数据库结果将始终作为行返回,我认为在您的情况下,您将不得不使用您的唯一 ID 再次循环并为“大”字段寻找不同的值。

我也不认为你需要foreach循环来使你的结果像关联数组,你可能需要使用它来代替:PDOStatement::fetchAll

于 2012-12-01T00:28:06.900 回答
2

问题出在您的查询中。您INNER JOIN的照片将为所有照片创建一行,并且为每个分配的照片重复公园。再次区分公园,GROUP BY但强制 MySQL 选择分配的照片之一。

如果公园没有图片,它根本不会在列表中(INNNER JOIN= 给我所有在两个表中都有关系的东西)

您可以删除GROUP BY并替换INNER JOINsby LEFT JOINs(给我所有公园并附上图像和评论,如果有的话),这需要在输出循环中检查(我当前的公园是什么,我是否已经显示了这个公园,显示当前图片,显示当前评论)

更干净但更慢的解决方案是删除用于获取图像和评论的连接和字段,这样你就只能得到公园;然后在 parks 循环中获取评论并在两个额外的查询中获取当前公园的图像。

编辑1:

就像评论中所说的那样,这不是一个很好的选择,因为您将触发两个额外的查询并为您添加的每个公园再运行两个循环。我希望您了解多对多关系的基本问题 - 数据库结果只能是二维表

编辑2:

我已将您的代码修复为我建议的内容,请注意

<?php
try
{
    $sql = 'SELECT 
                parks.id, 
                parks.state, 
                parks.name, 
                parks.description, 
                parks.site, 
                parks.sname, 
                parks.street, 
                parks.city, 
                parks.zip, 
                parks.phone, 
                comments.comment, 
                comments.commentname, 
                events.event, 
                events.date, 
                events.description2,                
                photos.type, 
                photos.filename, 
                photos.big 
            FROM 
                parks
                    LEFT JOIN comments ON comments.parkid = parks.id
                    LEFT JOIN photos ON photos.parkid = parks.id
                    LEFT JOIN events ON events.parkid = parks.id
            ORDER BY 
                parks.name ASC';
    $result = $pdo->query($sql);
}
catch (PDOException $e)
{
    $error = 'Error fetching data: ' . $e->getMessage();
    include 'output.html.php';
    exit();
}

//This is pulling the information from the database for display. On the foreach it will display each
//line until there are no more lines to display.    
$datas = array();

foreach ( $result as $row )
{
        // we didn't add this park yet
        if ( !array_key_exists( $row['id'], $datas )
        {
            $datas[$row['id']] = array (
                'id' => $row['id'],                
                'state' => $row['state'], 
                'name' => $row['name'], 
                'description' => $row['description'], 
                'site' => $row['site'], 
                'sname' => $row['sname'],
                'street' => $row['street'], 
                'city' => $row['city'], 
                'phone' => $row['phone'],
                'zip' => $row['zip'],
                'comments' => array(),
                'photos' => array(),
                'events' => array()
            );
        }

        // if there is no comment for this park, this will be null
        if ( $row['comment'] )
        {
            $datas[$row['id']]['comments'][] = array (
                'comment' => $row['comment'],
                'commentname' => $row['commentname']
            );
        }

        // same for photos
        if ( $row['filename'] )
        {
            $datas[$row['id']]['photos'][] = array (                
                'type' => $row['type']
                'filename' => $row['filename']
                'big' => $row['big']
            );
        }

        // same for events
        if ( $row['event'] )
        {
            $datas[$row['id']]['events'][] = array (
                'event' => $row['event'],
                'date' => $row['date'],
                'description2' => $row['description2']
            );
        }
}

include 'writing.html.php';

和写作.html.php

<?php    
foreach ($datas as $park)
{
    // do you only want to display PA? 
    // then add " WHERE state = 'PA' " to your query
    if ($park['state'] === 'PA') 
    {
?>  
        <a href="#header" title="return to the top of the page">Back to top</a>
        <input type="hidden" name="id" value="' . $park['id'] . '" />
        <h1 id="name"> <?php echo ($park['name']) ?> </h1>
        <p id="descriptionlist">
            <?php echo ($park['description']) ?>
            <br />
            <ul id="link">
                <li class="l1">
                    <a href=<?php echo $park['site'] ?> target="_blank"> <?php echo $park['sname'] ?> </a>
                </li>
            </ul>
        </p>

        <h2>Location</h2>
        <div class = "loc"> 
            <p class="loct">
                <a class = "fancyImg" href="maps/<?php echo $park['id'] ?>state.gif"> <img src= "maps/<?php echo $park['id'] ?>state.gif"> </a>
                <br />
                <php echo ($park['street']) . ?>
                <br />
                <?php echo ($park['city']) .  
                    ($park['state']) .
                    ($park['zip']) ?>
                <br>
                <?php echo ($park['phone']) ?> 
                <br> <br>
            </p>
        </div>

        <h2>Trail Map</h2>
        <div class = "map">
            <p class = "mapt"> 
                Click to Enlarge
                <a class ="fancyImg" href= "/maps/<?php echo $park['id'] ?>maplink.gif">
                    <img src= "/maps/<?php echo $park['id'] ?>.gif"></a> <br> <br> 
            </p>
        </div>
        <?php if ( !empty( $park['photos'] ) ): ?>
        <h2>Photos</h2>
            <?php foreach( $park['photos'] as $photo ): ?>
                <div class = "pho">
                    <p class = "phot">
                        <a class = "fancyImg" href= "/assets/indiv/<?php echo $photo['big'] ?>.gif"> 
                            <img src= "<?php echo $photo['filename'] ?>.gif"></a>**
                        Submit <i>your</i> photos of <?php echo ($photo['name']) ?> through our <ul id = "link"><li><a href="https://www.facebook.com/Ride4Wheel">Facebook Page!</li></ul></a></h3><p> Or go to our Contact Us page for information on how to e-mail us your favorite pictures! 
                    </p>
                </div>
            <?php endforeach; ?>
        <?php endif; ?>

        <?php if ( !empty( $park['comments'] ) ): ?>
            <h2>Comments</h2>
            <?php foreach( $park['comments'] as $comment ): ?>
                <?php echo $comment['comment']; ?>
            <?php endforeach; ?>
        <?php endif; ?>

        <?php if ( !empty( $park['events'] ) ): ?>
            <h2>Events</h2>
            <?php foreach( $park['events'] as $event ): ?>
                <?php echo $event['event']; ?>
            <?php endforeach; ?>
        <?php endif; ?>
<?php 
    }
}

编辑 3:

您需要了解的是,您只能从数据库中返回一个二维结果表。那么,如果您的公园不重复,您将如何为一个公园返回 10 张照片?是的,这(完全)不可能。这就是为什么您必须过滤重复的行,并且只有在您获得公园后才拍摄照片、评论和活动。

在上面的代码中,我使用唯一的公园 ID 作为数组索引,这样我就可以确定这个公园是否已经在数据数组中,然后添加照片、事件和评论。

如果您这样做print_r( $results )并将其与此进行比较,print_r( $datas )您将了解整个事情

于 2012-12-01T00:33:40.767 回答
1

除非每个公园都至少有一条评论和一张照片,否则您的查询不会返回所有公园的行。这就是INNER JOIN工作原理,它只取所有根据您指定的连接条件匹配的行的交集。

如果您想显示所有公园,无论它们是否有评论和/或照片,我建议您LEFT JOIN改用:

SELECT
    parks.id,
    parks.state,
    parks.name,
    parks.description,
    parks.site,
    parks.sname,
    parks.street,
    parks.city,
    parks.zip,
    parks.phone,
    comments.comment,
    comments.commentname,
    events.event,
    events.date,
    events.description2,
    photos.parkid,
    photos.type,
    photos.filename,
    photos.big
FROM
    parks
    LEFT JOIN comments ON (parks.parkid = comments.parkid)
    LEFT JOIN photos ON (parks.parkid = photos.parkid)
    LEFT JOIN events ON (parks.parkid = events.parkid)
ORDER BY
    parks.name asc

编辑

我删除了该GROUP BY子句,因为我很确定这不是您想要的;您可能希望查看与公园相关的每张照片或评论,而不是将它们都任意缩减为每个公园的一行。

编辑

使用此查询应该可以解决您在原始查询未返回您期望的评论和照片行时可能遇到的任何问题。您曾说过,这种关系是 1 公园与许多评论和许多照片。此查询应返回与每个公园关联的每条评论和照片,但每个公园将返回多行。您需要调整代码来弥补这一点,可能通过创建一个公园数据数组,其中数组中的每个元素对应于一个公园。每个元素还应包含一组评论和照片,每个公园可能有多个评论和照片。

结果集的每次迭代都应准备好在公园数据数组中创建一个新元素,或者识别当前结果集行对应于您已经开始构建其数据的公园。此外,如果当前迭代中有任何评论或照片,则应将它们添加到当前(新的或现有的)公园的评论和/或照片数组中。foreach这是如何执行此操作 的示例循环:

$parks = array();

foreach ($result as $row) {
    // Create a new element in $parks because it's not in the $parks array yet
    if (! array_key_exists($row['id'], $parks)) {
        $park = array();
        $park['id'] = $row['id'];
        $park['state'] = $row['state'];
        $park['name'] = $row['name'];
        $park['description'] = $row['description'];
        $park['site'] = $row['site'];
        $park['sname'] = $row['sname'];
        $park['street'] = $row['street'];
        $park['city'] = $row['city'];
        $park['zip'] = $row['zip'];
        $park['phone'] = $row['phone'];

        $park['comments'] = array();
        $park['photos'] = array();

        $parks[$row['id']] = $park;
    } else {
        // Otherwise, this is a park we've already seen
        $park = $parks[$row['id']];
    }

    // If there are comments in this result set row, add them
    if ($row['comment'] || $row['commentname']) {
        $park['comments'][] = array(
            'comment' => $row['comment'],
            'commentname' => $row['commentname']
        );
    }

    // If there are photos in this result set row, add them
    if ($row['type'] || $row['filename'] || $row['big']) {
        $park['photos'][] = array(
            'type' => $row['type'], 
            'filename' => $row['filename'], 
            'big' => $row['big']
        );
    }
}

这段代码不是很漂亮,也不是很好,它当然可以改进。我只是匆匆把它放在一起,给你一个如何建造这样一个结构的例子。

关系数据并不总是清晰地映射到分层对象图,这是对象关系阻抗不匹配

于 2012-12-01T00:36:07.620 回答
0

要获取一个数组中的所有行而不是第一个 foreach 循环,请尝试使用<?$datas = $pdo->fetchAll();?>

于 2012-12-01T00:33:47.793 回答