SQL Query is grabbing double the results - mysql
I have an SQL Query that is grabbing the db for movies. This SQL query is only for showing the users history:
$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)) {
...
}
}
I have results that are doubling, it is not a problem with the server or db information. This is a photo of the problem:
This next image is going to show what the results are suppose to look like. This SQL Query follows the same db outline and while loops as history but uses a slightly different SQL query due to the structure of the db.
Code Associated with second image:
$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)) {
...
}
}
I realize this is difficult to figure out. I'm new at programming and appreciate any help given...
EDIT: DDL For PhpmyAdmin
I'm not not quite sure if I did this right. Here are my results:
-- 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 */;
EDIT #trincot
This is the code I used:
$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 connects to a while loop. $id3 is the users id, which is found by a session. $start and $per_page are used for pagination purposes.
The duplicates
The DDL section shows you have duplicates in the history table, which in itself is not a problem, but it does explain the duplicate results you get in your query.
The solution is to filter away the duplicate history records, and keep only the most recent from them for the rest of the query. This filtering you can do in a sub query, like this:
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 ?, ?
(If SQL fiddle is willing to work, here is a fiddle).
The essence is in the GROUP BY movie_id which ensures you will not get duplicate movies. At the same time you take the greatest id from that group, which corresponds to the most recent one of that group, and this is important for the outer ORDER BY.
The question marks are place holders to be replaced when you prepare the statement (see below).
In the second version of the query, you don't select from history, but from likes. I assume you really want to select from history. If however, you want to only show movies that appear for this user in the likes table, you must either make sure the combination of movie and user is unique in that table, or apply the same principle as above, i.e. perform a sub query.
Prepared statements
You should use prepared statements to avoid SQL injection. Here is how you would do it:
$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();
The second query
It is really confusing to use the name number_likes for a column that apparently holds a movie id. I would recommend to change that name to movie_id. The fact that it concerns a like is already apparent from the table name.
Secondly, it is just as confusing to select from the table likes and then call the result $friends_one. As far as I can tell a record in the table likes indicates that a user likes a certain movie, and potentially records a review written by that user. It does not have any information about friends... A better name would be $movie_likers.
You limit the number of records to two, but have no control over which two will be taken. It would be better if you would add an ORDER BY clause.
Finally, you should either combine this query with the main query, or at least prepare it, so it is compiled once, and not in every iteration. Here is how that would look (with some change to variable names, see below):
$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);
Then combined with the other code, you get this code:
$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();
Choose telling variable names
As already hinted above, the names of the variables should better not be $id3, $id2, $movie4, ... etc. Try to use more telling names, like user_id, movie_id, etc. It helps to understand the code -- especially when you come back to it after a few months.
The first query joins the history table, but does not select from it. So you receive as many records per movie as there are history entries for the movie.
Related
How to implement IF condition in two relational tables?
I have two relational tables, and I would like to filter data using IF condition. The problem is that using LEFT JOIN I got records that cannot be grouped. The tables that I have are: calendar bookers The first table consists of lessons that can be booked by more people, and the second table contains data who booked each lesson. The IF condition that I would like to implement is: return '2' if lesson is booked by specific user, return '1' if lesson is booked, but by another user, and return '0' if lesson is not booked. What I would like to get according to above tables is given in the figure below. Expected result But, when I use LEFT JOIN to link those tables, I got record for every user that booked specific lesson. SELECT calendar.id, calendarId, lessonType, description, CASE WHEN bookedBy then IF(bookedBy = 8, '2', '1') ELSE '0' END AS bb, (select count(bookedBy) from bookers where calendar.id = bookers.lessonId) as nOfBookers FROM calendar LEFT JOIN bookers ON calendar.id = bookers.lessonId WHERE `calendarId`= 180 Without the LEFT JOIN (fiddle), counts are shown properly, but I cannot include IF condition, because the table bookers is not defined. I would appreciate any help. Thank you very much in advance. Here is the Fiddle. CREATE TABLE `calendar` ( `id` int(11) NOT NULL, `calendarId` varchar(50) NOT NULL, `lessonType` varchar(255) DEFAULT NULL, `description` varchar(255) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; INSERT INTO `calendar` (`id`, `calendarId`, `lessonType`, `description`) VALUES (1, '180', 'A', ''), (2, '180', 'A', ''), (3, '180', 'A', ''), (4, '180', 'B', ''), (5, '180', 'B', ''), (6, '180', 'B', ''), (7, '180', 'B', ''), (8, '180', 'B', ''), (9, '180', 'B', ''); CREATE TABLE `bookers` ( `id` int(11) NOT NULL, `lessonId` int(11) DEFAULT NULL, `bookedBy` int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- -- Dumping data for table `bookers` -- INSERT INTO `bookers` (`id`, `lessonId`, `bookedBy`) VALUES (4, 1, 8), (5, 2, 8), (6, 2, 28), (7, 2, 17), (8, 3, 11); -- -- Indexes for dumped tables -- ALTER TABLE `calendar` ADD PRIMARY KEY (`id`), ADD UNIQUE KEY `id` (`id`); -- -- Indexes for table `bookers` -- ALTER TABLE `bookers` ADD PRIMARY KEY (`id`); -- -- AUTO_INCREMENT for dumped tables -- -- -- AUTO_INCREMENT for table `bookers` -- ALTER TABLE `bookers` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=9; COMMIT; select version();
Try this: SELECT id, calendarid, lessontype, description, CASE WHEN FIND_IN_SET(8,vbb)>0 THEN 2 WHEN vbb IS NOT NULL THEN 1 ELSE 0 END AS bb, nOfBookers FROM (SELECT c.id, calendarId, lessonType, GROUP_CONCAT(bookedby) AS vbb, description, (SELECT COUNT(bookedby) FROM bookers WHERE c.id = bookers.lessonId) AS nOfBookers FROM calendar c LEFT JOIN bookers b ON c.id = b.lessonId WHERE `calendarId`= 180 GROUP BY c.id, calendarId, lessonType, description) A; In addition to your original LEFT JOIN attempt, I've added GROUP_CONCAT(bookedby) AS vbb which will return a comma separated bookedby value; which is 17,28,8. After that, I make the query as a sub-query and do CASE expression with FIND_IN_SET function on vbb to look for specific bookedby. Here's an update fiddle: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=0933e9fc3cb7445311c34c6705d11637
How to find count in many to many relationship in MySql, Cakephp 3.6
I need to calculate the count(vendors.id) for each category. ie: how many vendors are there for each category(not sub-category) I am using cakephp 3.6 framework and MySQL as database I tried with all possible way that i knew but not found any solution. Can anybody help me, is very important for my project [UPDATE] sql query i have used: SELECT cat.id,cat.name ,COUNT(`vendor_id`) AS vendor_count FROM `vendor_services` JOIN `categories` ON(`vendor_services`.`category_id` = `categories`.`id`) JOIN `categories` AS cat ON(categories.category_id = cat.id) WHERE 1 GROUP BY cat.id [UPDATE]Bellow is the sql to create corresponding tables -- phpMyAdmin SQL Dump -- version 4.7.0 -- https://www.phpmyadmin.net/ -- -- Host: 127.0.0.1 -- Generation Time: Dec 04, 2018 at 10:50 AM -- Server version: 10.1.24-MariaDB -- PHP Version: 7.1.6 SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET AUTOCOMMIT = 0; START TRANSACTION; SET time_zone = "+00:00"; -- -- Database: `demo123` -- -- -------------------------------------------------------- -- -- Table structure for table `categories` -- CREATE TABLE `categories` ( `id` int(11) NOT NULL, `category_id` tinyint(4) NOT NULL, `name` varchar(60) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Dumping data for table `categories` -- INSERT INTO `categories` (`id`, `category_id`, `name`) VALUES (1, 0, 'Books'), (2, 0, 'Electronics'), (3, 0, 'Garden'), (4, 1, 'Novel'), (5, 1, 'Science'), (6, 1, 'Story'), (7, 2, 'Mobile'), (8, 2, 'Tablet'), (9, 2, 'Headphone'), (10, 3, 'Pumps'), (11, 3, 'Pipes'); -- -------------------------------------------------------- -- -- Table structure for table `vendors` -- CREATE TABLE `vendors` ( `id` int(11) NOT NULL, `name` varchar(60) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Dumping data for table `vendors` -- INSERT INTO `vendors` (`id`, `name`) VALUES (1, 'VR Enterprizes'), (2, 'RR Vendors'), (3, 'JK Suppliers'); -- -------------------------------------------------------- -- -- Table structure for table `vendor_services` -- CREATE TABLE `vendor_services` ( `id` int(11) NOT NULL, `vendor_id` int(11) NOT NULL, `category_id` int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Dumping data for table `vendor_services` -- INSERT INTO `vendor_services` (`id`, `vendor_id`, `category_id`) VALUES (1, 1, 4), (2, 1, 5), (3, 1, 6), (4, 1, 11), (5, 2, 7), (6, 2, 8), (7, 2, 9), (8, 3, 10), (9, 3, 11); -- -- Indexes for dumped tables -- -- -- Indexes for table `categories` -- ALTER TABLE `categories` ADD PRIMARY KEY (`id`), ADD KEY `category_id` (`category_id`); -- -- Indexes for table `vendors` -- ALTER TABLE `vendors` ADD PRIMARY KEY (`id`); -- -- Indexes for table `vendor_services` -- ALTER TABLE `vendor_services` ADD PRIMARY KEY (`id`), ADD KEY `vendor_id` (`vendor_id`), ADD KEY `category_id` (`category_id`); -- -- AUTO_INCREMENT for dumped tables -- -- -- AUTO_INCREMENT for table `categories` -- ALTER TABLE `categories` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=12; -- -- AUTO_INCREMENT for table `vendors` -- ALTER TABLE `vendors` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; -- -- AUTO_INCREMENT for table `vendor_services` -- ALTER TABLE `vendor_services` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=10;COMMIT; CategoriesTable $this->hasMany(‘Subcategories’, [ 'className'=> ‘Categories’, 'foreignKey' => 'category_id', 'conditions' => ['category_id!= 0'] ]); $this->belongsTo('MainCategories', [ 'className'=> ‘Categories’, 'foreignKey' => 'category_id', ]);
Below is the query in oracle, please have a look, and modify it as per mysql, added below insertion, INSERT INTO VENDOR_SERVICES (ID, VENDOR_ID, CATEGORY_ID) VALUES(11, 3, 3); SELECT FRM.CATEGORY_ID, FRM.VENDOR_ID, FRM.VENDER_NAME,COUNT(VENDOR_ID) counts FROM ( SELECT distinct CT.CATEGORY_ID, VS.VENDOR_ID, VS.CATEGORY_ID VS_CATEGORY_ID,vn.ID, vn.NAME VENDER_NAME FROM CATEGORIES CT INNER JOIN VENDOR_SERVICES VS ON VS.CATEGORY_ID=CT.CATEGORY_ID INNER JOIN VENDORS VN ON VS.VENDOR_ID=VN.ID) frm group by CATEGORY_ID, VENDOR_ID, VENDER_NAME
customer_code 'in where clause is not unambiguous?
I am a beginner and i am looking for a solution for more than a hour, i don't have time to waste this weekend. So i want to have the date,destination and name where where klant_code = reis_code but i am getting the error which is displayed in my title. If i use select klant.naam, reis.bestemming from klant,reis where klant_code = reis_code it works, what i don't understand is that it's getting the error only when i want to add the date to the klant(client). What am i doing wrong here? Thanks for your time and help! This is my SQL code: CREATE TABLE `bestelling` ( `bestelling_code` int(11) NOT NULL, `klant_code` int(11) NOT NULL, `reis_code` int(11) NOT NULL, `datum` date NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Gegevens worden geëxporteerd voor tabel `bestelling` -- INSERT INTO `bestelling` (`bestelling_code`, `klant_code`, `reis_code`, `datum`) VALUES (1, 1, 1, '2017-12-12'), (2, 5, 3, '2018-01-01'), (3, 2, 5, '2018-03-05'), (4, 4, 2, '2018-08-08'), (5, 3, 4, '2018-12-10'); -- -------------------------------------------------------- -- -- Tabelstructuur voor tabel `klant` -- CREATE TABLE `klant` ( `klant_code` int(11) NOT NULL, `naam` varchar(20) NOT NULL, `adres` varchar(20) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Gegevens worden geëxporteerd voor tabel `klant` -- INSERT INTO `klant` (`klant_code`, `naam`, `adres`) VALUES (1, 'Gester', 'Amsterdam'), (2, 'Piet', 'Breda'), (3, 'Klaas', 'Rotterdam'), (4, 'Henk', 'Etten-leur'), (5, 'Sjaak', 'Tilburg'); -- -------------------------------------------------------- -- -- Tabelstructuur voor tabel `reis` -- CREATE TABLE `reis` ( `reis_code` int(12) NOT NULL, `bestemming` varchar(12) NOT NULL, `klasse` int(11) NOT NULL, `prijs_in_euro` int(11) NOT NULL, `geannuleerd` tinyint(1) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Gegevens worden geëxporteerd voor tabel `reis` -- INSERT INTO `reis` (`reis_code`, `bestemming`, `klasse`, `prijs_in_euro`, `geannuleerd`) VALUES (1, 'Spanje', 1, 500, 1), (2, 'Duitsland', 2, 300, 0), (3, 'Griekenland', 2, 700, 1), (4, 'Italie', 1, 640, 0), (5, 'Belgie', 2, 80, 1); COMMIT; /*!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 */;
There are some issue on your code. use an alias name for table. use JOIN instead of , comma (CROSS JOIN) it's an old style, JOIN can let us know each table relationship. SQL statement ensures which column of the data table is clearly marked You can try this. select k.naam, r.bestemming from klant k INNER JOIN reis r on k.klant_code = r.reis_code
Both tables have a column "klant_code". You have to clearly define it in the where clause, ie klant.klant_code or bestselling.klant_code. I think you're looking for a join "ON" rather than "WHERE" also.
You can try this with Inner Join with Alias. select k.naam, r.bestemming from klant k INNER JOIN reis r on k.klant_code = r.reis_code
MySQL join three tables, sum of item join to main table
I have three MySQL tables: For example A Table is menu ID, name B table is customer_order ID, order_date C table is order_item ID, menu_item_id, customer_order_id, order_quantity I try to output name, sum(order_quantity) in this month Currently i have two separate query which working ok, but the second query is inside of foreach loop, which seem not so good. First query which output all the menu items: $results = $wpdb->get_results( "SELECT * FROM menu WHERE post_id = $pid ORDER BY sort_order "); Second query will output total of each item sold on each month: $total = $wpdb->get_col( "SELECT SUM(oi.order_item_quantity) from order_item as oi INNER JOIN customer_order as ho ON ho.ID = oi.order_id WHERE oi.order_item_id = $subC->ID AND YEAR(ho.order_date) = $current_year AND MONTH(ho.order_date) = $current_month "); I try to merge the two queries into one query, which has taken me whole day but still not able to solve it, can anyone give me some help please. update thanks Rene. Select m.name, m.name as name, sum(oi.order_item_quantity) as sold_monthly from menu as m left join order_item as oi on oi.order_item_id = m.ID left join cusomter_order as co on co.ID = oi.order_id where m.post_id = 110 group by m.ID, m.name this will output name sold_monthly Sushi Lunch Special NULL Sushi Lunch 19 Sashimi Lunch 61 jason NULL egg roll NULL if i add YEAR(co.order_date) = 2016 AND MONTH(co.order_date) = 9 which i only get name sold_monthly Sushi Lunch 7 Sashimi Lunch 14 how can i keep sushi lunch special, jason, egg roll, the null item, when i add the YEAR(co.order_date) = 2016 AND MONTH(co.order_date) = 9. here i try (year(co.order_date) = 2016 and month(co.order_date) = 10) or sold_monthly is null which give me a query error update thanks Rene again it's working now (year(co.order_date) = 2016 and month(co.order_date) = 10) or co.order_date is null finally solve it, upper have little bug, when i change business_id which may not catch the result i want, so i am add a subquery to it. Select m.*, p.sold_monthly from menu as m left join ( SELECT SUM(oi.order_item_quantity) as sold_monthly, oi.order_item_id as ID, oi.order_item_name from order_item as oi LEFT JOIN cusomter_order as ho ON ho.ID = oi.order_id WHERE ho.business_id = $pid AND (year(ho.order_date) = $current_year and month(ho.order_date) = $current_month) OR ho.order_date is NULL GROUP by oi.order_item_id )p on p.ID = m.ID where m.post_id = $pid
So you're trying to get a list per post_id limited by the selected month. The following query will yield that for the following sample data. SELECT m.ID as ID, m.Name as Name, SUM(oi.order_quantity) as Quantity FROM menu as m LEFT JOIN order_item as oi ON oi.menu_item_id = m.ID LEFT JOIN customer_order as co ON co.ID = oi.customer_order_id WHERE m.post_id = 0 AND YEAR(co.order_date) = 2016 AND MONTH(co.order_date) = 9 OR co.order_date is NULL GROUP BY m.ID,m.Name,m.sort_order ORDER BY m.sort_order Sample Data SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET time_zone = "+00:00"; DROP TABLE IF EXISTS `customer_order`; CREATE TABLE `customer_order` ( `ID` int(11) NOT NULL, `order_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_german2_ci; TRUNCATE TABLE `customer_order`; INSERT INTO `customer_order` (`ID`, `order_date`) VALUES (1, '2016-09-06 00:00:00'), (2, '2016-09-13 00:00:00'), (3, '2016-08-09 00:00:00'), (4, '2016-09-19 00:00:00'); DROP TABLE IF EXISTS `menu`; CREATE TABLE `menu` ( `ID` int(11) NOT NULL, `sort_order` int(11) NOT NULL, `post_id` int(11) NOT NULL, `Name` varchar(20) COLLATE utf8_german2_ci NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_german2_ci; TRUNCATE TABLE `menu`; INSERT INTO `menu` (`ID`, `sort_order`, `post_id`, `Name`) VALUES (2, 0, 0, 'Test 1'), (4, 1, 0, 'Test 2'), (5, 2, 0, 'Test 3'); DROP TABLE IF EXISTS `order_item`; CREATE TABLE `order_item` ( `ID` int(11) NOT NULL, `menu_item_id` int(11) NOT NULL, `customer_order_id` int(11) NOT NULL, `order_quantity` int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_german2_ci; TRUNCATE TABLE `order_item`; INSERT INTO `order_item` (`ID`, `menu_item_id`, `customer_order_id`, `order_quantity`) VALUES (1, 2, 1, 1), (2, 2, 2, 3), (3, 4, 1, 1), (4, 4, 2, 4), (5, 2, 3, 3), (6, 4, 3, 1), (7, 2, 4, 4); ALTER TABLE `customer_order` ADD PRIMARY KEY (`ID`); ALTER TABLE `menu` ADD PRIMARY KEY (`ID`), ADD KEY `idx_pid` (`post_id`); ALTER TABLE `order_item` ADD PRIMARY KEY (`ID`), ADD KEY `idx_coid` (`customer_order_id`), ADD KEY `idx_miid` (`menu_item_id`); ALTER TABLE `customer_order` MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5; ALTER TABLE `menu` MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=6; ALTER TABLE `order_item` MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=8; ALTER TABLE `order_item` ADD CONSTRAINT `CostomerOrderConstrain` FOREIGN KEY (`customer_order_id`) REFERENCES `customer_order` (`ID`), ADD CONSTRAINT `MenuItemConstrain` FOREIGN KEY (`menu_item_id`) REFERENCES `menu` (`ID`); Good luck integrating the query, let me know if it worked. Update: Updated sample data to reproduce the actual problem. Updated the Solution Query.
sql to list services by the number of ratings the service owners have
I have 3 tables - user, service and ratings. The user's primary key is user_id and is a foreign key in the service table. Its also a foreign key in ratings table linked to rated_id (the user id of the person being rated) and rater_id (the user id of the person providing the rating) Each user has one service and can have mutltiple ratings. If the pushed field in the ratings table is 1, then its a valid rating and can be used. If its 0, its not valid yet and is waiting to be pushed. I need a query to show me a list of all services, sorted in decending ordered by the users with most ratings. Services belonging to Users with ratings but are not pushed are at the bottom along with services belonging to users with no ratings. Here is the sql to create the table and data: SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; /*!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 utf8 */; -- -- Database: `ratings` -- -- -------------------------------------------------------- -- -- Table structure for table `ratings` -- CREATE TABLE IF NOT EXISTS `ratings` ( `unique_id` int(11) NOT NULL AUTO_INCREMENT, `rater_id` int(11) NOT NULL, `rated_id` int(11) NOT NULL, `pushed` int(11) NOT NULL, PRIMARY KEY (`unique_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ; -- -- Dumping data for table `ratings` -- INSERT INTO `ratings` (`unique_id`, `rater_id`, `rated_id`, `pushed`) VALUES (1, 4, 1, 1), (2, 4, 1, 1), (3, 4, 2, 1), (4, 4, 3, 0); -- -------------------------------------------------------- -- -- Table structure for table `service` -- CREATE TABLE IF NOT EXISTS `service` ( `unique_id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `description` varchar(100) NOT NULL, PRIMARY KEY (`unique_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ; -- -- Dumping data for table `service` -- INSERT INTO `service` (`unique_id`, `user_id`, `description`) VALUES (1, 1, 'marks service'), (2, 2, 'shanes service'), (3, 3, 'peters service'); -- -------------------------------------------------------- -- -- Table structure for table `user` -- CREATE TABLE IF NOT EXISTS `user` ( `user_id` int(11) NOT NULL, `name` varchar(50) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Dumping data for table `user` -- INSERT INTO `user` (`user_id`, `name`) VALUES (1, 'mark'), (2, 'shane'), (3, 'peter'), (4, 'jobposter'); and here is a query i came up with SELECT s.*, count(r.rated_id), r.pushed FROM service s join user u on (u.user_id = s.user_id) join ratings r on (r.rated_id = u.user_id) group by r.rated_id order by r.rated_id the problem is its incomplete. users with no ratings wont show and if a user has multiple ratings but none are pushed, they will appear high up...
Try this query - SELECT s.*, r.rated_id, r.pushed_count FROM service s JOIN user u ON u.user_id = s.user_id LEFT JOIN ( SELECT rated_id, COUNT(IF(pushed = 1, 1, NULL)) pushed_count FROM ratings GROUP BY rated_id ) r ON r.rated_id = u.user_id ORDER BY r.pushed_count DESC
You might try this: SELECT u.name, s.DESCRIPTION, COUNT(r.rated_id) rated, r.pushed FROM USER u LEFT JOIN SERVICE s ON ( u.user_id = s.user_id ) LEFT JOIN ratings r ON ( r.rated_id = u.user_id ) GROUP BY u.name, r.rated_id, r.pushed ORDER BY r.pushed DESC, 3 DESC, u.name I am not hundred percent sure about left joining user with services. Remove left if you require users to have services in order to participate in ratings.