MySQL three way join? - mysql

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

Related

MySql problem to extract data from two 1to1 tables relationships

I'm trying to doing this exercise
Extract from the database all the records relating to the "Mathematics" lessons ('docenti.materia' column) of the teacher ('docenti' table) Andrea Bianchi with the participant ('partecipanti' table) Mario Rossi
db sql file
-- phpMyAdmin SQL Dump
-- version 5.2.0
-- https://www.phpmyadmin.net/
--
-- Host: localhost:3306
-- Generation Time: Dec 17, 2022 at 04:13 PM
-- Server version: 8.0.30
-- PHP Version: 8.1.10
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
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: `school`
--
-- --------------------------------------------------------
--
-- Table structure for table `docenti`
--
CREATE TABLE `docenti` (
`id` bigint UNSIGNED NOT NULL,
`id_persona_fisica` bigint UNSIGNED NOT NULL,
`materia` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
--
-- Dumping data for table `docenti`
--
INSERT INTO `docenti` (`id`, `id_persona_fisica`, `materia`) VALUES
(9, 2, 'Matematica'),
(10, 6, 'Storia'),
(11, 3, 'Filosofia');
-- --------------------------------------------------------
--
-- Table structure for table `lezioni`
--
CREATE TABLE `lezioni` (
`id` bigint UNSIGNED NOT NULL,
`id_docente` bigint UNSIGNED NOT NULL,
`giorno` date NOT NULL,
`ora_inizio` time NOT NULL DEFAULT '15:00:00'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
--
-- Dumping data for table `lezioni`
--
INSERT INTO `lezioni` (`id`, `id_docente`, `giorno`, `ora_inizio`) VALUES
(47, 11, '2022-04-26', '15:00:00'),
(48, 11, '2022-04-19', '15:00:00'),
(49, 11, '2022-12-27', '15:00:00'),
(50, 11, '2022-12-20', '15:00:00'),
(51, 9, '2022-03-30', '15:00:00'),
(52, 9, '2022-04-27', '15:00:00'),
(53, 9, '2022-04-20', '15:00:00'),
(54, 9, '2022-04-13', '15:00:00'),
(55, 9, '2022-12-23', '15:00:00'),
(56, 9, '2022-12-30', '15:00:00'),
(57, 9, '2022-11-25', '15:00:00'),
(58, 9, '2022-11-18', '15:00:00'),
(59, 9, '2022-12-09', '15:00:00'),
(60, 9, '2022-12-04', '15:00:00'),
(61, 10, '2022-12-26', '15:00:00'),
(62, 10, '2022-12-19', '15:00:00'),
(63, 10, '2022-12-12', '15:00:00'),
(64, 10, '2022-11-28', '15:00:00'),
(65, 10, '2022-11-21', '15:00:00'),
(66, 10, '2022-11-14', '15:00:00'),
(67, 10, '2022-04-25', '15:00:00'),
(68, 10, '2022-04-15', '15:00:00'),
(69, 10, '2022-04-11', '15:00:00');
-- --------------------------------------------------------
--
-- Table structure for table `partecipanti`
--
CREATE TABLE `partecipanti` (
`id` bigint UNSIGNED NOT NULL,
`id_persona_fisica` bigint UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
--
-- Dumping data for table `partecipanti`
--
INSERT INTO `partecipanti` (`id`, `id_persona_fisica`) VALUES
(4, 1),
(2, 4),
(5, 5),
(1, 7),
(3, 8);
-- --------------------------------------------------------
--
-- Table structure for table `persona_fisica`
--
CREATE TABLE `persona_fisica` (
`id` bigint UNSIGNED NOT NULL,
`nome` varchar(255) NOT NULL,
`cognome` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
--
-- Dumping data for table `persona_fisica`
--
INSERT INTO `persona_fisica` (`id`, `nome`, `cognome`) VALUES
(1, 'Mario', 'Rossi'),
(2, 'Andrea', 'Bianchi'),
(3, 'Ernesto', 'Pignoccheri'),
(4, 'Rosa', 'Mastro'),
(5, 'Franco', 'Tilder'),
(6, 'Sara', 'Santelli'),
(7, 'Serena', 'Baropoli'),
(8, 'Franco', 'Baglivi');
-- --------------------------------------------------------
--
-- Table structure for table `presenze`
--
CREATE TABLE `presenze` (
`id` bigint UNSIGNED NOT NULL,
`id_lezione` bigint UNSIGNED NOT NULL,
`id_partecipante` bigint UNSIGNED NOT NULL,
`ora_ingresso` time NOT NULL,
`ora_uscita` time NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
--
-- Dumping data for table `presenze`
--
INSERT INTO `presenze` (`id`, `id_lezione`, `id_partecipante`, `ora_ingresso`, `ora_uscita`) VALUES
(1, 47, 1, '08:00:00', '10:00:00'),
(2, 48, 1, '08:00:00', '10:00:00'),
(3, 49, 1, '08:00:00', '10:00:00'),
(4, 50, 1, '08:00:00', '10:00:00'),
(5, 51, 1, '08:00:00', '10:00:00'),
(6, 52, 1, '08:00:00', '10:00:00'),
(7, 53, 1, '08:00:00', '10:00:00'),
(8, 54, 1, '08:00:00', '10:00:00'),
(9, 55, 1, '08:00:00', '10:00:00'),
(10, 56, 1, '08:00:00', '10:00:00'),
(11, 57, 1, '08:00:00', '10:00:00'),
(12, 58, 1, '08:00:00', '10:00:00'),
(13, 59, 1, '08:00:00', '10:00:00'),
(14, 60, 1, '08:00:00', '10:00:00'),
(15, 61, 1, '08:00:00', '10:00:00'),
(16, 62, 1, '08:00:00', '10:00:00'),
(17, 63, 1, '08:00:00', '10:00:00'),
(18, 64, 1, '08:00:00', '10:00:00'),
(19, 65, 1, '08:00:00', '10:00:00'),
(20, 66, 1, '08:00:00', '10:00:00'),
(21, 67, 1, '08:00:00', '10:00:00'),
(22, 68, 1, '08:00:00', '10:00:00'),
(23, 69, 1, '08:00:00', '10:00:00'),
(24, 68, 2, '08:00:00', '10:00:00'),
(25, 68, 5, '08:00:00', '10:00:00'),
(26, 51, 4, '00:08:00', '00:10:00'),
(27, 52, 4, '00:08:00', '00:10:00'),
(28, 53, 4, '00:08:00', '00:10:00');
--
-- Indexes for dumped tables
--
--
-- Indexes for table `docenti`
--
ALTER TABLE `docenti`
ADD PRIMARY KEY (`id`),
ADD KEY `FK_id_persona_fisica` (`id_persona_fisica`);
--
-- Indexes for table `lezioni`
--
ALTER TABLE `lezioni`
ADD PRIMARY KEY (`id`),
ADD KEY `FK_id_docente` (`id_docente`);
--
-- Indexes for table `partecipanti`
--
ALTER TABLE `partecipanti`
ADD PRIMARY KEY (`id`),
ADD KEY `FK_persona_fisica` (`id_persona_fisica`);
--
-- Indexes for table `persona_fisica`
--
ALTER TABLE `persona_fisica`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `presenze`
--
ALTER TABLE `presenze`
ADD PRIMARY KEY (`id`),
ADD KEY `FK_id_lezione` (`id_lezione`),
ADD KEY `FK_id_partecipante` (`id_partecipante`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `docenti`
--
ALTER TABLE `docenti`
MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=12;
--
-- AUTO_INCREMENT for table `lezioni`
--
ALTER TABLE `lezioni`
MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=70;
--
-- AUTO_INCREMENT for table `partecipanti`
--
ALTER TABLE `partecipanti`
MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=6;
--
-- AUTO_INCREMENT for table `persona_fisica`
--
ALTER TABLE `persona_fisica`
MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=9;
--
-- AUTO_INCREMENT for table `presenze`
--
ALTER TABLE `presenze`
MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=29;
--
-- Constraints for dumped tables
--
--
-- Constraints for table `docenti`
--
ALTER TABLE `docenti`
ADD CONSTRAINT `FK_id_persona_fisica` FOREIGN KEY (`id_persona_fisica`) REFERENCES `persona_fisica` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `lezioni`
--
ALTER TABLE `lezioni`
ADD CONSTRAINT `FK_id_docente` FOREIGN KEY (`id_docente`) REFERENCES `docenti` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `partecipanti`
--
ALTER TABLE `partecipanti`
ADD CONSTRAINT `FK_persona_fisica` FOREIGN KEY (`id_persona_fisica`) REFERENCES `persona_fisica` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `presenze`
--
ALTER TABLE `presenze`
ADD CONSTRAINT `FK_id_lezione` FOREIGN KEY (`id_lezione`) REFERENCES `lezioni` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `FK_id_partecipante` FOREIGN KEY (`id_partecipante`) REFERENCES `partecipanti` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
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 */;
I'm trying with this query but I keep getting a blank line.
SELECT presenze.*, partecipanti.id, partecipanti.id_persona_fisica, persona_fisica.id, persona_fisica.nome, persona_fisica.cognome, docenti.id_persona_fisica, docenti.materia
FROM presenze
JOIN partecipanti ON presenze.id_partecipante = partecipanti.id
JOIN persona_fisica ON partecipanti.id_persona_fisica = persona_fisica.id
JOIN docenti ON docenti.id_persona_fisica = persona_fisica.id
WHERE persona_fisica.nome = 'Mario' AND persona_fisica.cognome = 'Rossi'
AND persona_fisica.nome = 'Andrea' AND persona_fisica.cognome = 'Bianchi'
AND docenti.materia = 'Matematica';
Where am I wrong?
************* S O L V E D *************
In the end I solved it by doing the second JOIN on the 'persona_fisica' table (alias pf2) without putting the 'ON' clause.
Thanks a lot to #blobtub for the tip!
SELECT
presenze.*,
partecipanti.id,
partecipanti.id_persona_fisica,
pf1.id,
pf1.nome,
pf1.cognome,
docenti.id_persona_fisica,
docenti.materia,
pf2.id,
pf2.nome,
pf2.cognome
FROM presenze
JOIN partecipanti
ON presenze.id_partecipante = partecipanti.id
JOIN persona_fisica pf1
ON partecipanti.id_persona_fisica = pf1.id
JOIN persona_fisica pf2
ON docenti.id_persona_fisica = pf2.id
WHERE pf1.nome = 'Mario' AND pf1.cognome = 'Rossi'
AND pf2.nome = 'Andrea' AND pf2.cognome = 'Bianchi'
AND docenti.materia = 'Matematica';
You need to use two joins onto persona_fisica, one for the partecipanti and one for the docenti
See how the persona_fisica table has two relation arrows going from the same attribute (id) on your diagram? This is what tells you you will need two joins if you want to use both relations.
Something like this (I'm afraid my Italian isn't good enough to test it, I'm sorry):
SELECT
lezioni.id_docente,
presenze.*,
partecipanti.id,
partecipanti.id_persona_fisica,
pf1.id,
pf1.nome,
pf1.cognome,
docenti.id_persona_fisica,
docenti.materia,
pf2.id,
pf2.nome,
pf2.cognome
FROM presenze
JOIN partecipanti
ON presenze.id_partecipante = partecipanti.id
JOIN persona_fisica pf1
ON partecipanti.id_persona_fisica = pf1.id
JOIN lezioni
ON presenze.id_lezioni = lezioni.id
JOIN docenti
ON docenti.id = lezioni.id_docenti
JOIN persona_fisica pf2
ON docenti.id_persona_fisica = pf2.id
WHERE pf1.nome = 'Mario' AND pf1.cognome = 'Rossi'
AND pf2.nome = 'Andrea' AND pf2.cognome = 'Bianchi'
AND docenti.materia = 'Matematica';

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')
);

import .sql file into mysql from mac command line. tried mysql -u root -p db_name > path/to/dbfile.sql

I have tried doing it from the command line
mysql -u root -p db_name > ~/Documents/db_name.sql
I have tried doing it from mysqlimport
mysqlimport -u root -p db_name ~/Documents/db_name.sql
I have tried both while being in the correct directory using just the file name.
I have tried entering mysql using
mysql -u root -p
use db_name;
source ~/Documents/db_name.sql;
(nothing happens - no response)
(tried with absolute path - no response)
\. ~/Documents/db_name.sql
(nothing happens)
I feel like I'm missing something. This seems like a trivial operation according to the last 30 minutes of googling and attempts.
Ultimately I had to copy and paste the entire .sql file into the mysql shell while using the correct db.
I feel like a caveman. Please help.
Edit: SQL file contents
-- phpMyAdmin SQL Dump
-- version 4.4.15.5
-- http://www.phpmyadmin.net
--
-- Host: 127.0.0.1:8889
-- Generation Time: May 09, 2017 at 09:27 PM
-- Server version: 5.6.34-log
-- PHP Version: 7.0.13
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: `movie-buff`
--
-- --------------------------------------------------------
--
-- Table structure for table `directors`
--
CREATE TABLE IF NOT EXISTS `directors` (
`director_id` int(11) NOT NULL,
`first` varchar(60) DEFAULT NULL,
`last` varchar(60) DEFAULT NULL,
`country` varchar(100) DEFAULT NULL
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1;
--
-- Dumping data for table `directors`
--
INSERT INTO `directors` (`director_id`, `first`, `last`, `country`) VALUES
(1, 'Jean-Pierre', 'Jeunet', 'France'),
(2, 'Jean', 'Renoir', 'France'),
(3, 'Akira', 'Kurosawa', 'Japan'),
(4, 'Jane', 'Campion', 'New Zealand'),
(5, 'Sally', 'Potter', 'UK'),
(6, 'Kasi', 'Lemmons', 'USA'),
(7, 'Ava', 'DuVernay', 'USA'),
(8, 'Todd', 'Haynes', 'USA'),
(9, 'Marleen', 'Gorris', 'Netherlands');
-- --------------------------------------------------------
--
-- Table structure for table `movies`
--
CREATE TABLE IF NOT EXISTS `movies` (
`movie_id` int(11) NOT NULL,
`title` varchar(130) DEFAULT NULL,
`year` int(11) DEFAULT NULL,
`director_id` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=latin1;
--
-- Dumping data for table `movies`
--
INSERT INTO `movies` (`movie_id`, `title`, `year`, `director_id`) VALUES
(1, 'The City of Lost Children', 1995, 1),
(2, 'Amelie', 2001, 1),
(3, 'The Rules of the Game', 1939, 2),
(4, 'La Grande Illusion', 1937, 2),
(5, 'The Lower Depths', 1936, 2),
(6, 'Alien: Resurrection', 1997, 1),
(7, 'Ran', 1985, 3),
(8, 'Seven Samurai', 1954, 3),
(9, 'Throne of Blood', 1957, 3),
(10, 'An Angel at My Table', 1990, 4),
(11, 'The Piano', 1993, 4),
(12, 'Orlando', 1992, 5),
(13, 'The Tango Lesson', 1997, 5),
(14, 'Talk to Me', 2007, 6),
(15, 'Eve''s Bayou', 1997, 6),
(16, 'Selma', 2014, 7),
(18, 'Far From Heaven', 2002, 8),
(19, 'I''m Not There', 2007, 8),
(20, 'Carol', 2015, 8),
(21, 'Antonia''s Line', 1995, 9),
(22, 'Mrs. Dalloway', 1997, 9);
-- --------------------------------------------------------
--
-- Table structure for table `viewers`
--
CREATE TABLE IF NOT EXISTS `viewers` (
`viewer_id` int(11) NOT NULL,
`first` varchar(60) DEFAULT NULL,
`last` varchar(60) DEFAULT NULL,
`email` varchar(80) DEFAULT NULL
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1;
--
-- Dumping data for table `viewers`
--
INSERT INTO `viewers` (`viewer_id`, `first`, `last`, `email`) VALUES
(1, 'Tim', 'Labonne', 'tim_labonne#live.com'),
(2, 'Alicen', 'Brightley', 'abrightley#yahoo.com'),
(3, 'Renard', 'Sartor', 'rsartor#washu.edu'),
(4, 'Luigi', 'Greco', 'elgreco#live.com'),
(5, 'Jackie', 'Linwood', 'jLinwood#yahoo.com'),
(6, 'Caroline', 'Smith', 'youknowwho#live.com');
-- --------------------------------------------------------
--
-- Table structure for table `viewings`
--
CREATE TABLE IF NOT EXISTS `viewings` (
`viewing_id` int(11) NOT NULL,
`viewer_id` int(11) NOT NULL,
`movie_id` int(11) NOT NULL,
`date_viewed` date DEFAULT NULL
) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=latin1;
--
-- Dumping data for table `viewings`
--
INSERT INTO `viewings` (`viewing_id`, `viewer_id`, `movie_id`, `date_viewed`) VALUES
(1, 1, 4, '2008-10-07'),
(2, 1, 2, '2009-12-18'),
(3, 1, 1, '2010-02-27'),
(4, 1, 21, '2010-03-14'),
(5, 2, 21, '2015-04-15'),
(6, 2, 22, '2015-10-04'),
(7, 2, 7, '2015-11-30'),
(8, 2, 9, '2016-01-05'),
(9, 2, 12, '2016-04-14'),
(10, 2, 16, '2017-01-23'),
(11, 3, 8, '2016-02-14'),
(12, 3, 18, '2016-03-20'),
(13, 3, 22, '2016-04-07'),
(14, 4, 20, '2017-01-03'),
(15, 4, 18, '2017-01-14'),
(16, 4, 15, '2017-02-08'),
(17, 4, 10, '2007-09-23'),
(18, 4, 2, '2017-03-05'),
(19, 4, 4, '2017-04-13'),
(20, 4, 12, '2017-04-30'),
(21, 4, 14, '2017-05-02'),
(22, 4, 21, '2017-05-08'),
(23, 5, 2, '2013-08-25'),
(24, 5, 3, '2013-12-16'),
(25, 5, 7, '2014-03-18'),
(26, 6, 11, '2013-11-30'),
(27, 6, 2, '2013-12-18'),
(28, 6, 14, '2014-04-29'),
(29, 6, 5, '2016-12-03'),
(30, 6, 13, '2017-01-09'),
(31, 6, 18, '2017-02-13'),
(32, 6, 21, '2017-03-14'),
(33, 6, 15, '2017-04-15');
--
-- Indexes for dumped tables
--
--
-- Indexes for table `directors`
--
ALTER TABLE `directors`
ADD PRIMARY KEY (`director_id`);
--
-- Indexes for table `movies`
--
ALTER TABLE `movies`
ADD PRIMARY KEY (`movie_id`),
ADD KEY `director_id` (`director_id`);
--
-- Indexes for table `viewers`
--
ALTER TABLE `viewers`
ADD PRIMARY KEY (`viewer_id`);
--
-- Indexes for table `viewings`
--
ALTER TABLE `viewings`
ADD PRIMARY KEY (`viewing_id`),
ADD KEY `viewer_id` (`viewer_id`),
ADD KEY `movie_id` (`movie_id`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `directors`
--
ALTER TABLE `directors`
MODIFY `director_id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=10;
--
-- AUTO_INCREMENT for table `movies`
--
ALTER TABLE `movies`
MODIFY `movie_id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=23;
--
-- AUTO_INCREMENT for table `viewers`
--
ALTER TABLE `viewers`
MODIFY `viewer_id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=7;
--
-- AUTO_INCREMENT for table `viewings`
--
ALTER TABLE `viewings`
MODIFY `viewing_id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=34;
--
-- Constraints for dumped tables
--
--
-- Constraints for table `movies`
--
ALTER TABLE `movies`
ADD CONSTRAINT `movies_ibfk_1` FOREIGN KEY (`director_id`) REFERENCES `directors` (`director_id`);
--
-- Constraints for table `viewings`
--
ALTER TABLE `viewings`
ADD CONSTRAINT `viewings_ibfk_1` FOREIGN KEY (`viewer_id`) REFERENCES `viewers` (`viewer_id`),
ADD CONSTRAINT `viewings_ibfk_2` FOREIGN KEY (`movie_id`) REFERENCES `movies` (`movie_id`);
/*!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 should use the mysql command in order to import a mysqldump sql file:
mysql -u root -p db_name < ~/Documents/db_name.sql
The mysqlimport utility is used to insert data from textfiles into the database, it is a wrapper around the LOAD DATA INFILE sql statement. From mysqlimport documentation:
The mysqlimport client provides a command-line interface to the LOAD
DATA INFILE SQL statement. Most options to mysqlimport correspond
directly to clauses of LOAD DATA INFILE syntax. See Section 13.2.6,
“LOAD DATA INFILE Syntax”.
I can't reproduce the problem:
File: ~/Documents/db_name.sql
CREATE DATABASE IF NOT EXISTS `movie-buff`;
USE `movie-buff`;
--
-- Table structure for table `directors`
--
CREATE TABLE IF NOT EXISTS `directors` (
`director_id` int(11) NOT NULL,
`first` varchar(60) DEFAULT NULL,
`last` varchar(60) DEFAULT NULL,
`country` varchar(100) DEFAULT NULL
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1;
--
-- Dumping data for table `directors`
--
INSERT INTO `directors` (`director_id`, `first`, `last`, `country`)
VALUES
(1, 'Jean-Pierre', 'Jeunet', 'France'),
(2, 'Jean', 'Renoir', 'France'),
(3, 'Akira', 'Kurosawa', 'Japan'),
(4, 'Jane', 'Campion', 'New Zealand'),
(5, 'Sally', 'Potter', 'UK'),
(6, 'Kasi', 'Lemmons', 'USA'),
(7, 'Ava', 'DuVernay', 'USA'),
(8, 'Todd', 'Haynes', 'USA'),
(9, 'Marleen', 'Gorris', 'Netherlands');
MySQL:
mysql> source ~/Documents/db_name.sql
Database changed
Query OK, 0 rows affected (0.01 sec)
Query OK, 9 rows affected (0.00 sec)
Records: 9 Duplicates: 0 Warnings: 0
It also works with:
mysql> \. ~/Documents/db_name.sql
$ mysql -u user -p movie-buff < ~/Documents/db_name.sql
UPDATE
In the case of mysql> source ~/Documents/db_name.sql, mysql> \. ~/Documents/db_name.sql and $ mysql -u user -p < ~/Documents/db_name.sql (without specifying the database) the database may not be created, but must be created in the script (see script above). In the case of $ mysql -u user -p movie-buff < ~/Documents/db_name.sql the database must be created before.

How to refactor, (shorten) this query

I have a database with tables: applicant (or candidate for a job), application (candidate applied for a certain job), test, selected_test(any application has a defined set of tests) and test_result.
When I need to show which applicant scored what result for any application and test I would use this query:
SELECT applicant.first_name, applicant.last_name, application.job, test.name, test_result.score
FROM applicant
INNER JOIN application ON application.applicant_id=applicant.id
INNER JOIN selected_test ON application.id=selected_test.application_id
INNER JOIN test ON selected_test.test_id=test.id
INNER JOIN test_result ON selected_test.test_id=test_result.test_id AND applicant.id=test_result.applicant_id
What I need to accomplish is sorting by certain test type (test.name) along with test.score
This is what I mean:
SELECT a.first_name, a.last_name, app.job, iq.score AS iqScore, math.score AS mathScore, personality.score AS personalityScore, logic.score AS logicScore
FROM applicant a
INNER JOIN application app ON a.id=app.applicant_id
LEFT JOIN
(SELECT app.id AS appId, tr.score
FROM applicant a
INNER JOIN application app ON app.applicant_id=a.id
INNER JOIN selected_test st ON app.id=st.application_id
INNER JOIN test t ON st.test_id=t.id AND t.name='iq'
INNER JOIN test_result tr ON st.test_id=tr.test_id AND a.id=tr.applicant_id) AS iq ON app.id=iq.appId
LEFT JOIN
(SELECT app.id AS appId, tr.score
FROM applicant a
INNER JOIN application app ON app.applicant_id=a.id
INNER JOIN selected_test st ON app.id=st.application_id
INNER JOIN test t ON st.test_id=t.id AND t.name='math'
INNER JOIN test_result tr ON st.test_id=tr.test_id AND a.id=tr.applicant_id) AS math ON app.id=math.appId
LEFT JOIN
(SELECT app.id AS appId, tr.score
FROM applicant a
INNER JOIN application app ON app.applicant_id=a.id
INNER JOIN selected_test st ON app.id=st.application_id
INNER JOIN test t ON st.test_id=t.id AND t.name='personality'
INNER JOIN test_result tr ON st.test_id=tr.test_id AND a.id=tr.applicant_id) AS personality ON app.id=personality.appId
LEFT JOIN
(SELECT app.id AS appId, tr.score
FROM applicant a
INNER JOIN application app ON app.applicant_id=a.id
INNER JOIN selected_test st ON app.id=st.application_id
INNER JOIN test t ON st.test_id=t.id AND t.name='logic'
INNER JOIN test_result tr ON st.test_id=tr.test_id AND a.id=tr.applicant_id) AS logic ON app.id=logic.appId
ORDER BY mathScore DESC, iqScore DESC, logicScore DESC
The query returns a set of applications, showing applicant data, job, test names and scores.
For instance, if I want candidate applications with higher "math" score, followed by highest scores in "IQ" and then in "logic" to be on top, 'ORDER BY' clause looks like the above.
The query works correct but the problem is that in real situation it deals with large data sets and I need a way to shorten/refactor this query.
Example database it works on is here:
CREATE TABLE IF NOT EXISTS `applicant` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`first_name` varchar(255) NOT NULL,
`last_name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=8 ;
--
-- Dumping data for table `applicant`
--
INSERT INTO `applicant` (`id`, `first_name`, `last_name`) VALUES
(2, 'Jack', 'Redburn'),
(4, 'Barry', 'Leon'),
(6, 'Elisabeth', 'Logan'),
(7, 'Jane', 'Doe');
-- --------------------------------------------------------
--
-- Table structure for table `application`
--
CREATE TABLE IF NOT EXISTS `application` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`applicant_id` int(11) NOT NULL,
`job` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=10 ;
--
-- Dumping data for table `application`
--
INSERT INTO `application` (`id`, `applicant_id`, `job`) VALUES
(2, 2, 'Salesman'),
(4, 4, 'Policeman'),
(6, 6, 'Journalist'),
(8, 6, 'Hostess'),
(9, 7, 'Journalist');
-- --------------------------------------------------------
--
-- Table structure for table `selected_test`
--
CREATE TABLE IF NOT EXISTS `selected_test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`application_id` int(11) NOT NULL,
`test_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=24 ;
--
-- Dumping data for table `selected_test`
--
INSERT INTO `selected_test` (`id`, `application_id`, `test_id`) VALUES
(1, 1, 1),
(2, 1, 2),
(3, 1, 3),
(5, 2, 1),
(6, 2, 2),
(7, 2, 3),
(8, 2, 4),
(9, 3, 4),
(10, 3, 2),
(11, 4, 1),
(12, 4, 2),
(13, 4, 3),
(14, 4, 4),
(15, 5, 2),
(16, 5, 3),
(17, 6, 1),
(18, 6, 4),
(19, 7, 3),
(20, 7, 2),
(21, 7, 1),
(22, 8, 2),
(23, 8, 3);
-- --------------------------------------------------------
--
-- Table structure for table `test`
--
CREATE TABLE IF NOT EXISTS `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;
--
-- Dumping data for table `test`
--
INSERT INTO `test` (`id`, `name`) VALUES
(1, 'math'),
(2, 'logic'),
(3, 'iq'),
(4, 'personality');
-- --------------------------------------------------------
--
-- Table structure for table `test_result`
--
CREATE TABLE IF NOT EXISTS `test_result` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`applicant_id` int(11) NOT NULL,
`test_id` int(11) NOT NULL,
`score` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=24 ;
--
-- Dumping data for table `test_result`
--
INSERT INTO `test_result` (`id`, `applicant_id`, `test_id`, `score`) VALUES
(2, 2, 1, 6),
(3, 4, 1, 7),
(6, 6, 1, 3),
(7, 7, 1, 8),
(9, 2, 2, 15),
(11, 4, 2, 12),
(13, 6, 2, 11),
(14, 7, 2, 9),
(15, 7, 3, 105),
(16, 6, 3, 112),
(18, 4, 3, 108),
(20, 2, 3, 117),
(22, 4, 4, 70);
And here is what results look like:
First query is just to show you how data is related:
The large query, shows score data horizontally so it is possible to sort by test name and score:
caveat I don't know mysql
Googling mysql pivot gives this result http://en.wikibooks.org/wiki/MySQL/Pivot_table
So if we apply the same logic using the test.id as the seed number (which is exam in the example from the google search) we get this:
SQLFIDDLE
select first_name, last_name, job,
sum(score*(1-abs(sign(testid-1)))) as math,
sum(score*(1-abs(sign(testid-2)))) as logic,
sum(score*(1-abs(sign(testid-3)))) as iq,
sum(score*(1-abs(sign(testid-4)))) as personality
from
(
SELECT applicant.first_name, applicant.last_name, application.job, test.name, test_result.score, test.id as testid
FROM applicant
INNER JOIN application ON application.applicant_id=applicant.id
INNER JOIN selected_test ON application.id=selected_test.application_id
INNER JOIN test ON selected_test.test_id=test.id
INNER JOIN test_result ON selected_test.test_id=test_result.test_id AND applicant.id=test_result.applicant_id
) t
group by first_name, last_name, job
Now you've got your short query yu can apply sorting as required - you can use case statement in you order by to dynamically change the order as required...
I noticed that you have only defined primary keys. You should see a noticeable performance improvement when you index other fields. Index at least the following: application.applicant_id, selected_test.application_id, selected_test.test_id, test_result.applicant_id, test_result.test_id, test_result.score.
You might be surprised how much this speeds things up for you. In fact, mysql tells us this is the best way to improve performance: https://dev.mysql.com/doc/refman/5.5/en/optimization-indexes.html.

search a set of values in other set of values for a row

Hello I am having issues with execution time on a query that searches for users ( from users table ) that are having at least one interest from one specified interests set and a location from a specified locations set. So I have this test DB:
CREATE TABLE IF NOT EXISTS `interests` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=10 ;
--
-- Dumping data for table `interests`
--
INSERT INTO `interests` (`id`, `name`) VALUES
(1, 'auto'),
(2, 'moto'),
(3, 'health'),
(4, 'garden'),
(5, 'house'),
(6, 'music'),
(7, 'video'),
(8, 'games'),
(9, 'it');
-- --------------------------------------------------------
--
-- Table structure for table `locations`
--
CREATE TABLE IF NOT EXISTS `locations` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=11 ;
--
-- Dumping data for table `locations`
--
INSERT INTO `locations` (`id`, `name`) VALUES
(1, 'engalnd'),
(2, 'austia'),
(3, 'germany'),
(4, 'france'),
(5, 'belgium'),
(6, 'italy'),
(7, 'russia'),
(8, 'poland'),
(9, 'norway'),
(10, 'romania');
-- --------------------------------------------------------
--
-- Table structure for table `users`
--
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=11 ;
--
-- Dumping data for table `users`
--
INSERT INTO `users` (`id`, `email`) VALUES
(1, 'email1#test.com'),
(2, 'email2#test.com'),
(3, 'email3#test.com'),
(4, 'email4#test.com'),
(5, 'email5#test.com'),
(6, 'email6#test.com'),
(7, 'email7#test.com'),
(8, 'email8#test.com'),
(9, 'email9#test.com'),
(10, 'email10#test.com');
-- --------------------------------------------------------
--
-- Table structure for table `users_interests`
--
CREATE TABLE IF NOT EXISTS `users_interests` (
`user_id` int(11) NOT NULL,
`interest_id` int(11) NOT NULL,
PRIMARY KEY (`user_id`,`interest_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--
-- Dumping data for table `users_interests`
--
INSERT INTO `users_interests` (`user_id`, `interest_id`) VALUES
(1, 1),
(1, 2),
(2, 5),
(2, 7),
(2, 8),
(3, 1),
(4, 1),
(4, 5),
(4, 6),
(4, 7),
(4, 8),
(5, 1),
(5, 2),
(5, 8),
(6, 3),
(6, 7),
(6, 8),
(7, 7),
(7, 9),
(8, 5);
-- --------------------------------------------------------
--
-- Table structure for table `users_locations`
--
CREATE TABLE IF NOT EXISTS `users_locations` (
`user_id` int(11) NOT NULL,
`location_id` int(11) NOT NULL,
PRIMARY KEY (`user_id`,`location_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--
-- Dumping data for table `users_locations`
--
INSERT INTO `users_locations` (`user_id`, `location_id`) VALUES
(2, 5),
(2, 7),
(2, 8),
(3, 1),
(4, 1),
(4, 5),
(4, 6),
(4, 7),
(4, 8),
(5, 1),
(5, 2),
(5, 8),
(6, 3),
(6, 7),
(6, 8),
(7, 7),
(7, 9),
(8, 5);
Is there a better way to query it than this:
SELECT email,
GROUP_CONCAT( DISTINCT ui.interest_id ) AS interests,
GROUP_CONCAT( DISTINCT ul.location_id ) AS locations
FROM `users` u
LEFT JOIN users_interests ui ON u.id = ui.user_id
LEFT JOIN users_locations ul ON u.id = ul.user_id
GROUP BY u.id
HAVING IF( interests IS NOT NULL , FIND_IN_SET( 2, interests )
OR FIND_IN_SET( 3, interests ) , 1 )
AND IF( locations IS NOT NULL , FIND_IN_SET( 2, locations )
OR FIND_IN_SET( 3, locations ) , 1 )
This is the best solution I found but it still slow on a 500k and 1mil rows in the relational tables ( locations and interests ). Especially when you are matching against a large set of values ( let's say above 50 locations and interests ).
So I am trying to achieve the result this query produces, but a bit faster:
email interests locations
email1#test.com 1,2 [BLOB - 0B]
email5#test.com 1,2,8 1,2,8
email6#test.com 3,7,8 3,7,8
email9#test.com [BLOB - 0B] [BLOB - 0B]
email10#test.com [BLOB - 0B] [BLOB - 0B]
I also tried to join against an SELECT UNION table - for the matching set - but it was even slower. Like this:
SELECT *
FROM `users` u
LEFT JOIN users_interests ui ON u.id = ui.user_id
LEFT JOIN users_locations ul ON u.id = ul.user_id
LEFT JOIN (SELECT 2 as interest UNION SELECT 3 as interest) as `is` ON ui.interest_id = is.interest
LEFT JOIN (SELECT 2 as location UNION SELECT 3 as location ) as `ls` ON ul.location_id = ls.location
WHERE IF(ui.user_id IS NOT NULL, `is`.interest IS NOT NULL,1) AND
IF(ul.user_id IS NOT NULL, ls.location IS NOT NULL,1)
GROUP BY u.id
I am using this for a basic targeting system.
I would appreciate very much, any suggestion! Thank you!
you have IS is reserved word for mysql
and also your group by can slow your query but i dont see any meaning to use group by u.id here since the u.id is already unique id.
look demo
try use backticks around it.
SELECT *
FROM `users` u
LEFT JOIN users_interests ui ON u.id = ui.user_id
LEFT JOIN users_locations ul ON u.id = ul.user_id
LEFT JOIN (SELECT 2 as interest UNION SELECT 3 as interest) as `is`
ON ui.interest_id = `is`.interest
LEFT JOIN (SELECT 2 as location UNION SELECT 3 as location ) as `ls`
ON ul.location_id = `ls`.location
WHERE IF(ui.user_id IS NOT NULL, `is`.interest IS NOT NULL,1)
AND
IF(ul.user_id IS NOT NULL, `ls`.location IS NOT NULL,1)