I want to build simple database system about bike (or bicycle) rental store.
Here are the tables, and columns in parantheses:
Model (MNr, Modelname, dayprice)
Bike (MNr, CopyNr, Frame, Color)
Customer (CNr, Name, Surename, MobileNr)
Rental (CNr, MNr, CopyNr, DateOut, DateIn)
(MNr stands for model number, CNr stands for customer number).
Models are bike models, Bike table shows data on each particular bike.
There can be several bikes of each model, to distinguish between them
"CopyNr" column is used, where each bike in a given model is numbered 1, 2, 3, etc.
Rental: A rental relationship always applies to only one bike and one customer.
So I put the following primary and foreign keys:
Model (MNr (PK), Modelname, dayprice)
Bike (MNr (FK), CopyNr (PK), Frame, Color)
Customer (CNr (PK), Firstame, Surname, MobileNr)
Rent (CNr (FK), MNr (FK), CopyNr (FK), DateOut, DateIn)
The "CopyNr" at "Rental" is referring to the "CopyNr" of "Bikes". So I used "CopyNr" as
primary key column.
But that column can contain duplicate values, like there can be copy nr 2 of model A and copy nr 2 of
model B.
And primary key columns don't allow duplicate values.
I wrote the following in the SQL file, and when but it on PHPMyAdmin.
Here's the code from SQL code:
[It had Norwegian names, I changed it to English, thus color names are Norwegian]
-- phpMyAdmin SQL Dump
-- version 4.8.4
-- https://www.phpmyadmin.net/
--
-- Host: 127.0.0.1:3306
-- Generation Time: Feb 04, 2020 at 07:15 PM
-- Server version: 10.2.26-MariaDB-log
-- PHP Version: 7.1.30
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+01: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 */;
--
--
--
-- --------------------------------------------------------
--
-- Table structure for table `Customer`
--
CREATE TABLE `Customer` (
`CNr` int(2) NOT NULL,
`Firstname` varchar(20),
`Surname` varchar(20),
`MobileNr` varchar(8),
PRIMARY KEY (CNr)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `Customer` (`CNr`, `Firstname`, `Surname`, `MobileNr`) VALUES
(1, 'Olav', 'Petterses', '88888888'),
(2, 'Petter', 'Olavsson', '44444444');
-- --------------------------------------------------------
--
-- Table structure for table `Model`
--
CREATE TABLE `Model` (
`MNr` int(5) NOT NULL,
`Modelname` varchar(20),
`Dayprice` double DEFAULT NULL,
PRIMARY KEY (MNr)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `Model` (`MNr`, `Modelname`, `Dayprice`) VALUES
(2, 'FirstPrice', 10),
(15, 'DBS', 50),
(16, 'DBS', 60);
-- --------------------------------------------------------
--
-- Table structure for table `Bike`
--
CREATE TABLE `Bike` (
`MNr` int(5),
`CopyNr` int(2) NOT NULL,
`Frame` int(3),
`Color` varchar(10),
PRIMARY KEY (`CopyNr`, `MNr`),
CONSTRAINT `Bike_ibfk_1` FOREIGN KEY (`MNr`) REFERENCES `Model` (`MNr`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `Bike` (`MNr`, `CopyNr`, `Frame`, `Color`) VALUES
(2, 1, 55, 'rød'),
(15, 1, 65, 'rød'),
(16, 1, 55, 'grønn'),
(2, 2, 55, 'rød'),
(15, 2, 65, 'grønn');
-- --------------------------------------------------------
--
-- Table structure for table `Rent`
--
CREATE TABLE `Rent` (
`CNr` int(2),
`MNr` int(5),
`CopyNr` int(2),
`DatoUt` date,
`DateInn` date,
CHECK (`DatoUt` < `DateInn`),
CONSTRAINT `Rent_ibfk_1` FOREIGN KEY (`MNr`) REFERENCES `Model` (`MNr`),
CONSTRAINT `Rent_ibfk_2` FOREIGN KEY (`CopyNr`) REFERENCES `Bike` (`CopyNr`),
CONSTRAINT `Rent_ibfk_3` FOREIGN KEY (`CNr`) REFERENCES `Customer` (`CNr`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `Rent` (`CNr`, `MNr`, `CopyNr`, `DatoUt`, `DateInn`) VALUES
(1, 15, 1, '2020-01-01', '2020-01-30'),
(2, 15, 2, '2020-02-15', '2020-02-29');
/*!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 */;
When I put it on SQL on PHPAdmin and click "GO", I got error because of CHECK ( DatoIn > DateUt) code.
And I remove that part, then I get "Rent" table empty of values.
What's wrong am I doing?
Why is the "Rent" table empty of values when I put this on SQL on PHPMyAdmin?
Should I restructure the table relations?
And why "CHECK" doesn't work?
The error message I get where I use CHECK:
I believe you're seeing the syntax warning due to a bug in the parser used by phpMyAdmin which improperly marks this syntax as incorrect. I think that bug specifically is already reported as https://github.com/phpmyadmin/sql-parser/issues/167.
As nick indicates, you can still use the query despite the syntax warning.
I think that the date out should've be less than the date in
CHECK (DatoUt < DateInn),
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.
I'm thinking of doing something like...
Table Pants (20 entrees)
| ID | Item | Description | Price
Table Shirts (20 entrees)
| ID | Item | Description | Price
Table Socks (5 entrees)
| ID | Item | Description | Price
Then I run a php foreach ID in $table, to populate the list on a page.
So would this be an efficient way of doing this since some of my tables might not have many entrees? Or should I have all the entrees in one table and add an extra field for the different categories and find another way of populating my page via the new field? Or maybe a greater idea?
Thanks for your time.
your model is not flexible and not efficient. Your second solution is the good one create a table named items and add an extra field named categories which should be a foreign key.
you can check this http://sqlfiddle.com/#!2/74c91/1, here is all you need
here is the code needed for the database creation :
/*!40101 SET #OLD_CHARACTER_SET_CLIENT=##CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET FOREIGN_KEY_CHECKS=0 */;
-- Dumping structure for table database.categories
CREATE TABLE IF NOT EXISTS `categories` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`created` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- Dumping data for table database.categories: ~0 rows (approximately)
/*!40000 ALTER TABLE `categories` DISABLE KEYS */;
INSERT INTO `categories` (`id`, `name`, `created`) VALUES
(1, 'Pants ', '2012-12-15 11:37:27'),
(2, 'Shirts ', '2012-12-15 11:37:36'),
(3, 'Socks ', '2012-12-15 10:38:47');
/*!40000 ALTER TABLE `categories` ENABLE KEYS */;
-- Dumping structure for table database.clothes
CREATE TABLE IF NOT EXISTS `clothes` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`item` varchar(255) NOT NULL,
`description` text,
`category_id` int(10) NOT NULL,
`created` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `category_id` (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- Dumping data for table database.clothes: ~0 rows (approximately)
/*!40000 ALTER TABLE `clothes` DISABLE KEYS */;
INSERT INTO `clothes` (`id`, `item`, `description`, `category_id`, `created`) VALUES
(1, 'red socks', 'Red Socks Rocks', 3, '2012-12-15 10:39:06'),
(2, 'blue socks', 'nice socks too', 3, '2012-12-15 10:39:18'),
(3, 'grey pants', 'pretty cool', 1, '2012-12-15 10:40:34'),
(4, 'Blue Shirt', 'Nice blue shirt', 2, '2012-12-15 10:40:10');
/*!40000 ALTER TABLE `clothes` ENABLE KEYS */;
/*!40014 SET FOREIGN_KEY_CHECKS=1 */;
/*!40101 SET CHARACTER_SET_CLIENT=#OLD_CHARACTER_SET_CLIENT */;
And here is the code to retrieve your data:
SELECT
clothes.id AS clotheId,
clothes.item AS clotheItem,
clothes.description AS clotheDescription,
categories.id AS categoryId,
categories.name AS categoryName
FROM clothes
LEFT JOIN categories
ON clothes.category_id=categories.id;
I'd go with the latter.
ID | Item | Description | Price | Type
Then use a query like:
SELECT * FROM items WHERE type='$type'
I would not store this data in separate tables. Create one table, then include an indicator as to the type of item it is.
Similar to this:
create table ClothingItems
(
id,
typeid,
item,
description,
price
);
create table clothingType
(
typeid,
name
);
Then to query you can use:
select *
from clothingitems i
left join clothingType t
on t.typeid = t.typeid
where t.name = 'socks'
Well, it might not have so many entrees for the moment. But maybe in the future? Don't put yourself in a corner :).
Ask yourself the question; -Can an article belong to more than one category?
If NO, you should create at least 2 tables (one-to-many relation):
categories
id|title|description|...
articles
id|category_id|title|price|...
If YES, you should create at least 3 tables (many-to-many relation):
categories
id|title|description|...
articles
id|category_id|title|price|...
articles_categories
article_id|category_id
Best of luck :)
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.