SQL Query抓住了两倍的结果

时间:2016-03-15 18:59:12

标签: mysql

我有一个SQL查询正在抓取电影的 db 。此SQL查询仅用于显示用户历史记录:

$movie = $db2->query("SELECT  m.id AS mid,m.photo AS pho,
       m.destination AS des,m.length AS len,
       m.length_content AS lenc,m.description AS desa,m.rating AS rat,
       m.files AS fil
    FROM  movies m
    INNER JOIN  history h ON h.movie_id = m.id
    WHERE  h.user_id = $id3
    ORDER BY  h.id
    LIMIT  $start, $per_page

“);

while($movie3 = mysqli_fetch_array($movie)) {
           $number++;
             $id2 = $movie3["mid"];
             $photo = $movie3["pho"];
             $destination = $movie3["des"];
             $length = $movie3["len"];
             $length_content = $movie3["lenc"];
             $description = $movie3["desa"];
             $rating = $movie3["rat"];
             $files = $movie3["fil"];

$friends_one = $db2->query("SELECT * FROM likes WHERE number_likes='$id2' LIMIT 2");

 while($movie4 = mysqli_fetch_array($friends_one)) {
...
}
}

我的结果是加倍的,它不是服务器或数据库信息的问题。这是问题的照片:

Visual Aid of SQL Mistake

下一张图片将显示结果假设的样子。此SQL查询遵循相同的db大纲和while循环作为历史记录,但由于db的结构,使用稍微不同的SQL查询。

Visual Aid of Correct Project

与第二张图片相关的代码:

$movie = $db2->query("SELECT  *
    FROM  movies m
    INNER JOIN  likes h ON h.number_likes = m.id
    WHERE  h.user = $id3
    ORDER BY  h.id
    LIMIT  $start, $per_page");

while($movie3 = mysqli_fetch_array($movie)) {
           $number++;
           $id2 = $movie3["id"];
           $photo = $movie3["photo"];
           $rating = $movie3["rating"];
           $destination = $movie3["destination"];
            $length = $movie3["length"];
            $length_content = $movie3["length_content"];
            $files = $movie3["files"];
           $description = $movie3["description"];

 $friends_one = $db2->query("SELECT * FROM likes WHERE number_likes='$id2' LIMIT 2");

           while($movie4 = mysqli_fetch_array($friends_one)) {
...
}
}

我意识到这很难搞清楚。我是编程新手并且感谢任何帮助...

编辑:DDL for PhpmyAdmin

我不太确定我是否做得对。以下是我的结果:

-- phpMyAdmin SQL Dump
-- version 4.4.14
-- http://www.phpmyadmin.net
--
-- Host: 127.0.0.1
-- Generation Time: Mar 15, 2016 at 12:30 PM
-- Server version: 5.6.26
-- PHP Version: 5.6.12

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;

--
-- Database: `crave crap`
--

-- --------------------------------------------------------

--
-- Table structure for table `episodes`
--

CREATE TABLE IF NOT EXISTS `episodes` (
  `id` int(11) NOT NULL,
  `show_id` int(11) NOT NULL,
  `title` text NOT NULL,
  `destination` text NOT NULL,
  `description` text NOT NULL,
  `length` text NOT NULL,
  `likes` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- --------------------------------------------------------

--
-- Table structure for table `friends`
--

CREATE TABLE IF NOT EXISTS `friends` (
  `id` int(11) NOT NULL,
  `user` int(11) NOT NULL,
  `grab` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=latin1;

--
-- Dumping data for table `friends`
--

INSERT INTO `friends` (`id`, `user`, `grab`) VALUES
(13, 52, 51),
(14, 53, 51),
(15, 54, 51),
(16, 55, 51);

-- --------------------------------------------------------

--
-- Table structure for table `history`
--

CREATE TABLE IF NOT EXISTS `history` (
  `id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `movie_id` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=90 DEFAULT CHARSET=latin1;

--
-- Dumping data for table `history`
--

INSERT INTO `history` (`id`, `user_id`, `movie_id`) VALUES
(80, 51, 7),
(81, 51, 8),
(82, 51, 9),
(83, 51, 11),
(84, 51, 11),
(85, 51, 11),
(86, 51, 11),
(87, 51, 11),
(88, 51, 11),
(89, 51, 11);

-- --------------------------------------------------------

--
-- Table structure for table `likes`
--

CREATE TABLE IF NOT EXISTS `likes` (
  `id` int(11) NOT NULL,
  `user` int(11) NOT NULL,
  `number_likes` int(11) NOT NULL,
  `review` text NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=150 DEFAULT CHARSET=latin1;

--
-- Dumping data for table `likes`
--

INSERT INTO `likes` (`id`, `user`, `number_likes`, `review`) VALUES
(130, 51, 9, 'gtgtgt'),
(131, 51, 8, 'gbgtrgrt'),
(132, 52, 8, 'tgrrgrgt'),
(135, 53, 8, 'tgrgtrgtr'),
(136, 53, 9, 'gtbrgtrgtrgtr'),
(137, 52, 11, 'tgrgtrgtr'),
(138, 53, 11, 'tgrgtrgtr'),
(139, 54, 11, 'tgrtgrbgtr'),
(140, 52, 12, 'tgrtgrgtr'),
(141, 53, 12, 'gtrgtrgtr'),
(143, 52, 9, 'ttrgth'),
(146, 51, 7, 'gtgtrtg'),
(147, 52, 7, 'tgtrgtrtr'),
(149, 51, 11, 'No Review Found');

-- --------------------------------------------------------

--
-- Table structure for table `movies`
--

CREATE TABLE IF NOT EXISTS `movies` (
  `id` int(11) NOT NULL,
  `title` text NOT NULL,
  `photo` text NOT NULL,
  `destination` text NOT NULL,
  `description` text NOT NULL,
  `rating` text NOT NULL,
  `length` text NOT NULL,
  `length_content` text NOT NULL,
  `likes` int(11) NOT NULL,
  `files` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=latin1;

--
-- Dumping data for table `movies`
--

INSERT INTO `movies` (`id`, `title`, `photo`, `destination`, `description`, `rating`, `length`, `length_content`, `likes`, `files`) VALUES
(7, 'Star Inside Out', 'covers/pirate.jpg', 'movies/56c7ede7d3ed3658.44679765.mp4', 'Professional, Clean, Ready to Go', 'G', '1h 20m', '1', 6, 3),
(8, 'Star Wars', 'covers/star wars.jpg', 'movies/56c7ede7d3ed3108.44679765.mp4', 'Thirty years after the defeat of the Galactic Empire, the galaxy faces a new threat from the evil Kylo Ren (Adam Driver) and the First Order. When a defector named Finn crash-lands on a desert planet, he meets Rey (Daisy Ridley), a tough scavenger whose droid contains a top-secret map. Together, the young duo joins forces with Han Solo (Harrison Ford) to make sure the Resistance receives the intelligence concerning the whereabouts of Luke Skywalker (Mark Hamill), the last of the Jedi Knights.', 'PG', '2h 16m', '1', 100, 100),
(9, 'Hello', 'covers/56e068530dc9f9.52895782.jpg', 'movies/56e06853166618.33290858.mp4', 'Hello', 'PG-13', '58m', '0', 27, 12),
(11, 'The lost boy', 'covers/56e4341b6bb3f5.36887672.jpg', 'movies/56e4341b6bd319.33767547.mp4', 'A boy gets lost in the forest, separating him from his family, he must learn how to survive long enough to get out alive.', 'PG-13', '1h 47m', '1', 29, 58),
(12, 'The lost boy', 'covers/56e4341b6bb3f5.36887672.jpg', 'movies/56e4341b6bd319.33767547.mp4', 'A boy gets lost in the forest, separating him from his family, he must learn how to survive long enough to get out alive.', 'PG-13', '1h 47m', '1', 30, 60),
(14, 'The lost boy', 'covers/56e4341b6bb3f5.36887672.jpg', 'movies/56e4341b6bd319.33767547.mp4', 'A boy gets lost in the forest, separating him from his family, he must learn how to survive long enough to get out alive.', 'PG-13', '1h 47m', '1', 33, 60),
(15, 'The lost boy', 'covers/56e4341b6bb3f5.36887672.jpg', 'movies/56e4341b6bd319.33767547.mp4', 'A boy gets lost in the forest, separating him from his family, he must learn how to survive long enough to get out alive.', 'PG-13', '1h 47m', '1', 30, 60),
(16, 'The lost boy', 'covers/56e4341b6bb3f5.36887672.jpg', 'movies/56e4341b6bd319.33767547.mp4', 'A boy gets lost in the forest, separating him from his family, he must learn how to survive long enough to get out alive.', 'PG-13', '1h 47m', '1', 34, 60),
(17, 'The lost boy', 'covers/56e4341b6bb3f5.36887672.jpg', 'movies/56e4341b6bd319.33767547.mp4', 'A boy gets lost in the forest, separating him from his family, he must learn how to survive long enough to get out alive.', 'PG-13', '1h 47m', '1', 32, 60),
(18, 'The lost boy', 'covers/56e4341b6bb3f5.36887672.jpg', 'movies/56e4341b6bd319.33767547.mp4', 'A boy gets lost in the forest, separating him from his family, he must learn how to survive long enough to get out alive.', 'PG-13', '1h 47m', '1', 32, 60);

-- --------------------------------------------------------

--
-- Table structure for table `shows`
--

CREATE TABLE IF NOT EXISTS `shows` (
  `id` int(11) NOT NULL,
  `title` text NOT NULL,
  `photo` text NOT NULL,
  `description` text NOT NULL,
  `likes` int(11) NOT NULL,
  `seasons` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;

--
-- Dumping data for table `shows`
--

INSERT INTO `shows` (`id`, `title`, `photo`, `description`, `likes`, `seasons`) VALUES
(1, 'Age of Ultron', 'covers/56c6961452b097.49801377.jpg', 'Hello', 5, 2);

-- --------------------------------------------------------

--
-- Table structure for table `show_likes`
--

CREATE TABLE IF NOT EXISTS `show_likes` (
  `id` int(11) NOT NULL,
  `user` int(11) NOT NULL,
  `number_likes` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- --------------------------------------------------------

--
-- Table structure for table `users`
--

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) NOT NULL,
  `username` text NOT NULL,
  `password` text NOT NULL,
  `dropbox_token` text NOT NULL,
  `active` int(11) NOT NULL,
  `premium` int(11) NOT NULL,
  `avatar` text NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=63 DEFAULT CHARSET=latin1;

--
-- Dumping data for table `users`
--

INSERT INTO `users` (`id`, `username`, `password`, `dropbox_token`, `active`, `premium`, `avatar`) VALUES
(51, 'MatthewMalan', '76a7289eb67f6468356cba907809f2fd', 'kLQQAh1zJSAAAAAAAAABjaQvSFyq0RxKylBPtSL3-PM7uKRDaATZunClQ1Zsv24F', 0, 1, 'avatars/matthew.jpg'),
(52, 'Sam Coles', '91d9dfc1fef07bbcf46fe06f659e8cb3', 'kLQQAh1zJSAAAAAAAAAB48QKdqo-X0nN99I_3bxbFMKRtSdwbsrBz00yO_0P0XAB', 0, 1, 'avatars/sam.jpg'),
(53, 'Traek Malan', '91d9dfc1fef07bbcf46fe06f659e8cb3', 'kLQQAh1zJSAAAAAAAAAB48QKdqo-X0nN99I_3bxbFMKRtSdwbsrBz00yO_0P0XAB', 0, 1, 'avatars/traek.jpg'),
(54, 'Jesse Gaines', '91d9dfc1fef07bbcf46fe06f659e8cb3', 'kLQQAh1zJSAAAAAAAAAB48QKdqo-X0nN99I_3bxbFMKRtSdwbsrBz00yO_0P0XAB', 0, 1, 'avatars/jessie.jpg'),
(55, 'Rich Radford', '91d9dfc1fef07bbcf46fe06f659e8cb3', 'kLQQAh1zJSAAAAAAAAAB48QKdqo-X0nN99I_3bxbFMKRtSdwbsrBz00yO_0P0XAB', 0, 1, 'avatars/rich.jpg'),
(58, 'Donald Trump', '91d9dfc1fef07bbcf46fe06f659e8cb3', 'kLQQAh1zJSAAAAAAAAAB48QKdqo-X0nN99I_3bxbFMKRtSdwbsrBz00yO_0P0XAB', 0, 1, 'avatars/donald.jpg'),
(59, 'Marco Rubio', '91d9dfc1fef07bbcf46fe06f659e8cb3', 'kLQQAh1zJSAAAAAAAAAB48QKdqo-X0nN99I_3bxbFMKRtSdwbsrBz00yO_0P0XAB', 0, 1, 'avatars/marco.jpg'),
(62, 'Joseph Malan', '91d9dfc1fef07bbcf46fe06f659e8cb3', 'kLQQAh1zJSAAAAAAAAAB5mCiOhnPi2nNKr7bhFLnOC8LVRMiLvdI30CNgSJNOygm', 0, 1, 'default');

--
-- Indexes for dumped tables
--

--
-- Indexes for table `episodes`
--
ALTER TABLE `episodes`
  ADD PRIMARY KEY (`id`);

--
-- Indexes for table `friends`
--
ALTER TABLE `friends`
  ADD PRIMARY KEY (`id`);

--
-- Indexes for table `history`
--
ALTER TABLE `history`
  ADD PRIMARY KEY (`id`);

--
-- Indexes for table `likes`
--
ALTER TABLE `likes`
  ADD PRIMARY KEY (`id`);

--
-- Indexes for table `movies`
--
ALTER TABLE `movies`
  ADD PRIMARY KEY (`id`);

--
-- Indexes for table `shows`
--
ALTER TABLE `shows`
  ADD PRIMARY KEY (`id`);

--
-- Indexes for table `show_likes`
--
ALTER TABLE `show_likes`
  ADD PRIMARY KEY (`id`);

--
-- Indexes for table `users`
--
ALTER TABLE `users`
  ADD PRIMARY KEY (`id`);

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `episodes`
--
ALTER TABLE `episodes`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `friends`
--
ALTER TABLE `friends`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=17;
--
-- AUTO_INCREMENT for table `history`
--
ALTER TABLE `history`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=90;
--
-- AUTO_INCREMENT for table `likes`
--
ALTER TABLE `likes`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=150;
--
-- AUTO_INCREMENT for table `movies`
--
ALTER TABLE `movies`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=19;
--
-- AUTO_INCREMENT for table `shows`
--
ALTER TABLE `shows`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=2;
--
-- AUTO_INCREMENT for table `show_likes`
--
ALTER TABLE `show_likes`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `users`
--
ALTER TABLE `users`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=63;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

编辑@trincot

这是我使用的代码:

$movie = $db2->query("SELECT  m.id AS mid, m.photo AS pho,
        m.destination AS des, m.length AS len,
        m.length_content AS lenc, m.description AS desa, m.rating AS rat,
        m.files AS fil
    FROM  movies m
    INNER JOIN  
      ( SELECT  movie_id, MAX(id) AS id,
            FROM  history
            WHERE  h.user_id = $id3
            GROUP BY  movie_id 
      ) h ON h.movie_id = m.id
    ORDER BY  h.id
    LIMIT  $start, $per_page");

$movie连接到while循环。 $id3是用户ID,由会话找到。 $start$per_page用于分页目的。

2 个答案:

答案 0 :(得分:0)

第一个查询加入history表,但不从中选择。因此,每部电影都会收到与电影的历史条目一样多的记录。

答案 1 :(得分:0)

重复

DDL部分显示history表中有重复项,这本身不是问题,但它确实解释了您在查询中获得的重复结果。

解决方案是过滤掉重复的历史记录,并在查询的其余部分中仅保留最新的历史记录。您可以在子查询中进行此过滤,如下所示:

SELECT      m.id AS mid,
            m.photo AS pho, 
            m.destination AS des,
            m.length AS len,
            m.length_content AS lenc,
            m.description AS desa,
            m.rating AS rat,
            m.files AS fil 
FROM        movies m 
INNER JOIN  (
                SELECT   movie_id,
                         MAX(id) AS id 
                FROM     history 
                WHERE    user_id = ?
                GROUP BY movie_id
            ) h ON h.movie_id = m.id
ORDER BY    h.id 
LIMIT       ?, ? 

(如果SQL小提琴愿意工作,这里是fiddle)。

本质是GROUP BY movie_id,确保您不会获得重复的电影。同时,您从该组中获取最大的 id ,该组对应于该组中最新的一个,这对于外部ORDER BY非常重要。

问题标记是在准备声明时要替换的占位符(见下文)。

在查询的第二个版本中,您不是从history选择,而是从likes选择。我假设你真的想从history中选择。但是,如果您只想在likes表格中显示为此用户显示的电影,则必须确保电影和用户的组合在该表格中是唯一的,或者应用与上述相同的原则,即执行一个子查询。

准备好的陈述

您应该使用预准备语句来避免SQL injection。您将如何做到这一点:

$sql = ' ... '; // insert above query here
$stmt_movies = $db2->prepare($sql);
$stmt_movies->bind_param("iii", $user_id, $start, $per_page);
$stmt_movies->execute() or die($stmt_movies->error);
$stmt_movies->store_result();
$stmt_movies->bind_result($movie_id, $photo, $destination, $length,
                   $length_content, $description; $rating, $files);
while ($stmt_movies->fetch()) {
    //...
}
$stmt_movies->free_result();

第二个查询

将名称​​ number_likes 用于显然拥有电影ID的列实在令人困惑。我建议将该名称更改为 movie_id 。从表名中可以明显看出它与之相关的事实。

其次,从喜欢表中选择然后调用结果 $ friends_one 同样令人困惑。据我所知,表中的记录 likes 表示用户喜欢某部电影,并可能记录该用户编写的评论。它没有关于朋友的任何信息......一个更好的名字将是 $ movie_likers

您将记录数限制为两个,但无法控制将采用哪两个。如果要添加ORDER BY子句会更好。

最后,您应该将此查询与主查询相结合,或至少准备它,因此它只编译一次,而不是每次迭代。这是看起来的样子(对变量名称进行一些更改,见下文):

$sql = "SELECT review FROM likes WHERE number_likes = ? ORDER BY id DESC LIMIT 2";
$stmt_likes = $db2->prepare($sql);
$stmt_likes->bind_param("i", $move_id);

然后结合其他代码,您将获得以下代码:

$sql = ' ... '; // insert above query here
$stmt_movies = $db2->prepare($sql);
$stmt_movies->bind_param("iii", $movie_id, $start, $per_page);
$stmt_movies->execute() or die($stmt_movies->error);
$stmt_movies->store_result();
$stmt_movies->bind_result($movie_id, $photo, $destination, $length,
                   $length_content, $description; $rating, $files);

$sql = "SELECT review FROM likes WHERE number_likes = ? ORDER BY id DESC LIMIT 2";
$stmt_likes = $db2->prepare($sql);

while ($stmt_movies->fetch()) {
    $stmt_likes->bind_param("i", $movie_id);
    $stmt_likes->execute() or die($stmt_likes->error);
    $stmt_likes->store_result();
    $stmt_likes->bind_result($review);
    while ($stmt_likes->fetch()) {
        //... 
    }
    $stmt_likes->free_result();
    //...
}
$stmt_movies->free_result();

选择告诉变量名称

如上所述,变量的名称最好不要是 $ id3 $ id2 $ movie4 ,...尝试使用更多有说服力的名称,例如 user_id movie_id 等。这有助于理解代码 - 尤其是当您在几个月后再回到它时。