防止鬼入口多对多

时间:2011-10-28 18:45:41

标签: php mysql sql

我的表格标记包含字段tag_idname。我有一个联结表 tag_map ,其中包含字段tag_idvid_id,用于将表标记连接到表视频(通过vid_id )。

当我为vid_id插入新标记时,我删除了vid_id的tag_map中的所有条目,如果tag_map中只有一个条目我还想删除该条目表tags中的标记用于防止ghost条目(标记没有相应tag_map条目的条目)。

问题是,我似乎无法准确地获得这个数。例如,如果我在tag_map中有3个条目,每个条目在tags中都有1个相应的标记,则每个标记的计数为1,0,0。我是否为此目的使用了错误的查询?

//find all tags for given vid_id
$sql = 'SELECT tag_map.*, tags2.name AS tag_name
FROM tag_map
INNER JOIN tags2 ON tags2.tag_id = tag_map.tag_id
INNER JOIN video ON video.vid_id = tag_map.vid_id
WHERE tag_map.vid_id=?';
$stmt_tags = $conn->prepare($sql);
$result=$stmt_tags->execute(array($vid_id));

while ($row = $stmt_tags->fetch(PDO::FETCH_ASSOC)) {
$tag_name=$row['tag_name'];

//for each tag check how many rows exist in tag_map COUNT IS NOT ACCURATE
    $sql = 'SELECT *, COUNT(tags2.name) as cnt
FROM tag_map
JOIN tags2 ON tags2.tag_id = tag_map.tag_id
JOIN video ON video.vid_id = tag_map.vid_id
WHERE tags2.name=?';
$stmt_tags2 = $conn->prepare($sql);
$result=$stmt_tags2->execute(array($tag_name));

while ($row2 = $stmt_tags2->fetch(PDO::FETCH_ASSOC)) {
    echo $cnt=$row2['cnt'];
}

if ($cnt==1){
  $sql = "DELETE FROM tag_map WHERE vid_id = ?";
$stmt14 = $conn->prepare($sql);
$result=$stmt14->execute(array($vid_id));
  $sql = "DELETE FROM tags2 WHERE tags2.name = ?";
$stmt14 = $conn->prepare($sql);
$result=$stmt14->execute(array($tag_name));
}
else {
      $sql = "DELETE FROM tag_map WHERE vid_id = ?";
$stmt14 = $conn->prepare($sql);
$result=$stmt14->execute(array($vid_id));
}
}

编辑插入多对多

foreach($variable as $tag) {

    $sql = 'SELECT *, COUNT(tags2.name) as cnt
FROM tag_map
JOIN tags2 ON tags2.tag_id = tag_map.tag_id
JOIN video ON video.vid_id = tag_map.vid_id
WHERE tags2.name=?';
$stmt_tags2 = $conn->prepare($sql);
$result=$stmt_tags2->execute(array($tag));
while ($row = $stmt_tags2->fetch(PDO::FETCH_ASSOC)) {
    $cnt=$row['cnt'];
    $exist_tag_id=$row['tag_id'];
}

$id=md5(uniqid());
$tag_id=md5(uniqid());

if ($cnt==0){
    $sql="INSERT into tag_map (id,vid_id,tag_id) VALUES (?,?,?)";
$stmt16 = $conn->prepare($sql);
$result=$stmt16->execute(array($id,$vid_id,$tag_id));
    $sql="INSERT into tags2 (tag_id,name) VALUES (?,?)";
$stmt16 = $conn->prepare($sql);
$result=$stmt16->execute(array($tag_id,trim($tag)));
}
else {
$sql="INSERT into tag_map (id,vid_id,tag_id) VALUES (?,?,?)";
$stmt16 = $conn->prepare($sql);
$result=$stmt16->execute(array($id,$vid_id,$exist_tag_id));
}

}

3 个答案:

答案 0 :(得分:1)

你甚至不需要担心计数。从tag_map中删除然后:

DELETE t 
    FROM tags2 t
        LEFT JOIN tag_map tm
            ON t.tag_id = tm.tag_id
    WHERE tm.tag_id IS NULL;

答案 1 :(得分:1)

难道你不能这样做吗?或者我错过了什么?

删除某个视频中的所有代码,然后删除tag_map表中没有相应值的代码。

DELETE FROM tag_map WHERE vid_id = <video_id>;
DELETE FROM tags t 
WHERE NOT EXISTS (SELECT 1 FROM tag_map tm WHERE tm.tag_id = t.tag_id);

答案 2 :(得分:1)

在您的两个查询中,由于您只在vid_id上运行,因此不需要加入视频。只需专注于tags2和tag_map表。使用额外连接时,如果您没有该标记的视频条目,则可能会出现错误0。

此外,如果您想获取特定tag_id的计数,请执行以下操作:

SELECT COUNT(tm.tag_id) FROM tags2 t 
  LEFT OUTER JOIN tag_map ON tm.tag_id = t.tag_id
  WHERE t.name = ?

执行外部联接,这样在tag_map中没有条目的条目时,您实际上会得到0的计数。

但是,我更喜欢实际的DELETE,就像上面检查存在的那样。