customer_code 'in where clause is not unambiguous? - mysql

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

Related

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

How to use the result of a subquery

I have three SQL tables as below:
(The "orders" table below is not complete)
How to resolve the following question using just one sql query:
Select the customers who ordered in 2014 all the products (at least) that the customers named 'Smith' ordered in 2013.
Is this possible?
I have thought about this:
Firstly, find the all the products that the client named "Smith" ordered in 2013.
Secondly, find the list of customers who at least have ordered all the above products in 2014.
Which brings me to a SQL query like this:
SELECT cname,
FROM customers
NATURAL JOIN orders
WHERE YEAR(odate) = '2014'
AND "do_something_here"
(SELECT DISTINCT pid
FROM orders
NATURAL JOIN customers
WHERE LOWER(cname)='smith'
AND YEAR(odate)='2013') as results;
in which all the subquery results (the list of products that "Smith" ordered in 2013) should be used to find the clients needed.
But I don't know if this is the good approach.
Sorry for my English because I am not a native speaker.
If you want to test it out on phpMyAdmin, here's the SQL:
-- phpMyAdmin SQL Dump
-- version 4.7.5
-- https://www.phpmyadmin.net/
--
-- Host: localhost
-- Generation Time: Mar 21, 2018 at 02:49 PM
-- Server version: 5.7.20
-- PHP Version: 7.1.7
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
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: `tp1`
--
-- --------------------------------------------------------
--
-- Table structure for table `customers`
--
CREATE TABLE `customers` (
`cid` int(11) NOT NULL,
`cname` varchar(30) NOT NULL,
`residence` varchar(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Dumping data for table `customers`
--
INSERT INTO `customers` (`cid`, `cname`, `residence`) VALUES
(0, 'didnotorder', 'Great Britain'),
(1, 'Jones', 'USA'),
(2, 'Blake', NULL),
(3, 'Dupond', 'France'),
(4, 'Smith', 'Great Britain'),
(5, 'Gupta', 'India'),
(6, 'Smith', 'France');
-- --------------------------------------------------------
--
-- Table structure for table `orders`
--
CREATE TABLE `orders` (
`pid` int(11) NOT NULL,
`cid` int(11) NOT NULL,
`odate` date NOT NULL,
`quantity` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Dumping data for table `orders`
--
INSERT INTO `orders` (`pid`, `cid`, `odate`, `quantity`) VALUES
(1, 1, '2014-12-12', 2),
(1, 4, '2014-11-12', 6),
(2, 1, '2014-06-02', 6),
(2, 1, '2014-08-20', 6),
(2, 1, '2014-12-12', 2),
(2, 2, '2010-11-12', 1),
(2, 2, '2014-07-21', 3),
(2, 3, '2014-10-01', 1),
(2, 3, '2014-11-12', 1),
(2, 4, '2014-01-07', 1),
(2, 4, '2014-02-22', 1),
(2, 4, '2014-03-19', 1),
(2, 4, '2014-04-07', 1),
(2, 4, '2014-05-22', 1),
(2, 4, '2014-09-12', 4),
(2, 6, '2014-10-01', 1),
(3, 1, '2014-12-12', 1),
(3, 2, '2013-01-01', 1),
(3, 4, '2015-10-12', 1),
(3, 4, '2015-11-12', 1),
(4, 1, '2014-12-12', 3),
(4, 2, '2014-06-11', 2),
(4, 5, '2014-10-12', 1),
(4, 5, '2014-11-13', 5),
(5, 2, '2015-07-21', 3),
(6, 2, '2015-07-21', 7),
(6, 3, '2014-12-25', 1);
-- --------------------------------------------------------
--
-- Table structure for table `products`
--
CREATE TABLE `products` (
`pid` int(11) NOT NULL,
`pname` varchar(30) NOT NULL,
`price` decimal(7,2) NOT NULL,
`origin` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Dumping data for table `products`
--
INSERT INTO `products` (`pid`, `pname`, `price`, `origin`) VALUES
(0, 'wasnotordered', '11.00', NULL),
(1, 'chocolate', '5.00', 'Belgium'),
(2, 'sugar', '0.75', 'India'),
(3, 'milk', '0.60', 'France'),
(4, 'tea', '10.00', 'India'),
(5, 'chocolate', '7.50', 'Switzerland'),
(6, 'milk', '1.50', 'France');
--
-- Indexes for dumped tables
--
--
-- Indexes for table `customers`
--
ALTER TABLE `customers`
ADD PRIMARY KEY (`cid`);
--
-- Indexes for table `orders`
--
ALTER TABLE `orders`
ADD PRIMARY KEY (`pid`,`cid`,`odate`),
ADD KEY `orders_fk_cid` (`cid`);
--
-- Indexes for table `products`
--
ALTER TABLE `products`
ADD PRIMARY KEY (`pid`);
--
-- Constraints for dumped tables
--
--
-- Constraints for table `orders`
--
ALTER TABLE `orders`
ADD CONSTRAINT `orders_fk_cid` FOREIGN KEY (`cid`) REFERENCES `customers` (`cid`),
ADD CONSTRAINT `orders_fk_pid` FOREIGN KEY (`pid`) REFERENCES `products` (`pid`);
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 */;
You can try something like the following. Basically force join the customers with all the products from smith of 2013, then LEFT JOIN with the products each customer bought of 2014. If both counts are equal means that all products from smith of 2013 were bought at least once in 2014, for each customer.
SELECT
C.cid
FROM
Customers C
CROSS JOIN (
SELECT DISTINCT
P.pid
FROM
Customers C
INNER JOIN Orders O ON C.cid = O.cid
INNER JOIN Products P ON O.pid = P.pid
WHERE
C.cname = 'Smith' AND
YEAR(O.odate) = 2013) X
LEFT JOIN (
SELECT DISTINCT
C.cid,
P.pid
FROM
Customers C
INNER JOIN Orders O ON C.cid = O.cid
INNER JOIN Products P ON O.pid = P.pid
WHERE
YEAR(O.odate) = 2014) R ON C.cid = R.cid AND X.pid = R.pid
GROUP BY
C.cid
HAVING
COUNT(X.pid) = COUNT(R.pid)
If you want to see the customers even if there are no products from smith of 2013, you can switch the CROSS JOIN for a FULL JOIN (...) X ON 1 = 1.
You can solve this by finding all the products that each cid has in common with the Smith customers. Then, just check that the count covers all the products:
select o2014.cid, count(distinct o2013.pid) as num_products,
group_concat(distinct o2013.pid) as products
from orders o2013 join
orders o2014
on o2013.pid = o2014.pid and
year(o2013.odate) = 2013 and year(o2014.odate) = 2014
where o2013.cid = (select c.cid from customers c where c.cname = 'Smith')
group by o2014.cid
having num_products = (select count(distinct o2013.products)
from orders o2013
where o2013.cid = (select c.cid from customers c where c.cname = 'Smith')
);

sum of values based on condition

Iam new to mysql
I have two tables,
CREATE TABLE `tab1` (
`tid1` int(2) NOT NULL auto_increment,
`payer` varchar(100) default NULL,
`receiver` varchar(100) default NULL,
`payAmt` decimal(20,2) default '0.00',
`recAmt` decimal(20,2) default '0.00',
PRIMARY KEY (`tid1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
--
-- Dumping data for table tab1
INSERT INTO `tab1` (`tid1`, `payer`, `receiver`, `payAmt`, `recAmt`) VALUES
(1, 'aaa', 'bbb', 100.00, -100.00),
(2, 'aaa', 'ccc', 200.00, -200.00),
(3, 'bbb', 'aaa', 150.00, -150.00),
(4, 'ccc', 'aaa', 175.00, -175.00);
--
-- Table structure for table tab2
CREATE TABLE `tab2` (
`tid2` int(2) NOT NULL auto_increment,
`payer` varchar(100) default NULL,
`receiver` varchar(100) default NULL,
`payAmt` decimal(20,2) default '0.00',
`recAmt` decimal(20,2) default '0.00',
PRIMARY KEY (`tid2`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
--
-- Dumping data for table tab2
INSERT INTO `tab2` (`tid2`, `payer`, `receiver`, `payAmt`, `recAmt`) VALUES
(1, 'ddd', 'aaa', 223.00, -223.00),
(2, 'aaa', 'bbb', 429.00, -429.00),
(3, 'ccc', 'aaa', 102.00, -102.00);
I want the result as shown below
name payAmtTotal recAmtTotal payAmtTotal-recAmtTotal
aaa 729 650 79
bbb 150 529 -379
ccc 277 -277 554
ddd 223 0 223
Not sure why there is more then 1 table with this information, first thing that comes up is trying to turn this into 1 table.
Anyway, not sure if this is the best and cleanest way bu if the tables aren't to large and you have to option of creating temporary tables then here's one way of getting the desired results.
CREATE TEMPORARY TABLE IF NOT EXISTS temp1 AS (SELECT * FROM `tab1`);
INSERT INTO temp1 SELECT * FROM `tab2`;
CREATE TEMPORARY TABLE IF NOT EXISTS temp2 AS (SELECT * FROM `temp1`);
CREATE TEMPORARY TABLE IF NOT EXISTS temp3 AS (SELECT * FROM `temp1`);
SELECT
`payer` AS `name`,
(SELECT SUM(payAmt) AS `p` FROM temp2 AS t WHERE t.payer = temp1.payer) AS `payAmtTotal` ,
(SELECT SUM(payAmt) AS `r` FROM temp3 AS t WHERE t.receiver = temp1.payer) AS `recAmtTotal`
FROM
temp1
GROUP BY `name`;
Basically you create a singe (temporary) table and fill this table with the data from the two existing tables.
Since MySQL won't let you use the same temporary table more then once in a single query you need to create a few more :-) they can be copies of the first one though.
After that the selection query on itself isn't that complicated.

MySQL three way join?

I need to amend the following SQL so that it retrieves TTFF data for items that have category "beer" set in a table called planogram
select p.product_name, count(t.product_id), avg(t.TTFF), std(t.TTFF)
from product p left join
TTFFdata t
on p.product_id = t.product_id
where planogram_id = 1 group by p.product_name
However the products don't have category data, so I need to somehow get if from the categories in the planogram table. Something like this, but with the appropriate joining to make it work:
select p.product_name, count(t.product_id), avg(t.TTFF), std(t.TTFF)
from product p left join
TTFFdata t
on p.product_id = t.product_id
where planogram.category = "beer" group by p.product_name
Two things to consider:
I'm not very experiencd with SQL.
I think the database I've been given is badly structured (no category ids on the products?!), but I probably have to work with it as it is.
Any help much appreciated.
The full sql I'm working with is below:
-- phpMyAdmin SQL Dump
-- version 4.6.5.2
-- https://www.phpmyadmin.net/
--
-- Host: localhost
-- Generation Time: Mar 08, 2017 at 07:50 PM
-- Server version: 10.1.21-MariaDB
-- PHP Version: 5.6.30
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: `chart`
--
-- --------------------------------------------------------
--
-- Table structure for table `planogram`
--
CREATE TABLE `planogram` (
`planogram_id` int(11) NOT NULL,
`planogram_name` varchar(200) NOT NULL,
`project_name` varchar(200) NOT NULL,
`category` varchar(45) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Dumping data for table `planogram`
--
INSERT INTO `planogram` (`planogram_id`, `planogram_name`, `project_name`, `category`) VALUES
(1, 'planogramA', '', 'beer'),
(2, 'planogramB', '', 'coffee'),
(3, 'planogramC', '', 'coffee'),
(4, 'planogramD', '', 'fruit'),
(5, 'planogramE', '', 'beer');
-- --------------------------------------------------------
--
-- Table structure for table `product`
--
CREATE TABLE `product` (
`product_id` int(11) NOT NULL,
`product_name` varchar(200) NOT NULL,
`detail` varchar(200) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Dumping data for table `product`
--
INSERT INTO `product` (`product_id`, `product_name`, `detail`) VALUES
(1, 'beer1', ''),
(2, 'beer2', ''),
(3, 'coffee1', ''),
(4, 'coffee2', ''),
(5, 'coffee3', ''),
(6, 'coffee4', ''),
(7, 'coffee5', ''),
(8, 'coffee6', ''),
(9, 'beer3', ''),
(10, 'beer4', ''),
(13, 'fruit1', ''),
(14, 'fruit2', '');
-- --------------------------------------------------------
--
-- Table structure for table `TTFFdata`
--
CREATE TABLE `TTFFdata` (
`record_id` int(11) NOT NULL,
`participant_id` varchar(45) NOT NULL,
`TTFF` decimal(10,2) NOT NULL,
`product_id` int(11) NOT NULL,
`planogram_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Dumping data for table `TTFFdata`
--
INSERT INTO `TTFFdata` (`record_id`, `participant_id`, `TTFF`, `product_id`, `planogram_id`) VALUES
(1, 'a1', '6.21', 1, 1),
(2, 'a2', '5.70', 1, 1),
(3, 'a3', '6.00', 1, 1),
(4, 'b1', '3.40', 2, 1),
(5, 'b2', '4.30', 2, 1),
(6, 'b3', '6.00', 2, 1),
(7, 'c1', '7.00', 3, 2),
(8, 'c2', '8.00', 3, 2),
(9, 'c3', '5.00', 3, 2),
(10, 'd1', '8.90', 4, 2),
(11, 'd2', '3.00', 4, 2),
(12, 'd3', '4.50', 4, 2),
(15, 'e1', '8.00', 5, 2),
(16, 'e2', '9.00', 5, 2),
(17, 'f1', '5.50', 6, 3),
(18, 'f2', '5.00', 6, 3),
(19, 'g1', '5.20', 7, 3),
(20, 'g2', '3.60', 7, 3),
(21, 'h1', '5.00', 8, 3),
(22, 'h2', '5.10', 8, 3),
(23, 'i1', '6.00', 13, 4),
(24, 'i2', '7.00', 13, 4),
(25, 'j1', '4.00', 14, 4),
(26, 'j2', '6.00', 14, 4),
(27, 'k1', '6.70', 9, 5),
(28, 'k2', '6.10', 9, 5),
(29, 'l1', '3.00', 10, 5),
(30, 'l2', '5.00', 10, 5);
--
-- Indexes for dumped tables
--
--
-- Indexes for table `planogram`
--
ALTER TABLE `planogram`
ADD PRIMARY KEY (`planogram_id`);
--
-- Indexes for table `product`
--
ALTER TABLE `product`
ADD PRIMARY KEY (`product_id`);
--
-- Indexes for table `TTFFdata`
--
ALTER TABLE `TTFFdata`
ADD PRIMARY KEY (`record_id`),
ADD KEY `product_id` (`product_id`),
ADD KEY `planogram_id` (`planogram_id`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `planogram`
--
ALTER TABLE `planogram`
MODIFY `planogram_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=6;
--
-- AUTO_INCREMENT for table `product`
--
ALTER TABLE `product`
MODIFY `product_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=17;
--
-- AUTO_INCREMENT for table `TTFFdata`
--
ALTER TABLE `TTFFdata`
MODIFY `record_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=31;
/*!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 */;
You need to include all 3 tables in the join and make sure that you group by on all relevant fields to get the correct output. Based on the sample data, each product is associated with only one planogram, so my answer is based on the assumption that this is true for your entire data:
select p.product_name, count(t.product_id), avg(t.TTFF), std(t.TTFF)
from product p
left join TTFFdata t on p.product_id = t.product_id
left join planogram pl on t.planogram_id=pl.planogram_id
where planogram.category = "beer"
group by p.product_name

SQL Query is grabbing double the results

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.