MySQL custom order by another table - mysql

http://sqlfiddle.com/#!9/d865cf/2/1
Schema:
CREATE TABLE IF NOT EXISTS `letters` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`letter` char(1) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
INSERT INTO `letters` (`id`, `letter`) VALUES
(1, 'd'),
(2, 'f'),
(3, 'a'),
(4, 'e'),
(5, 'c'),
(6, 'b');
CREATE TABLE IF NOT EXISTS `sort` (
`next` int(11) NOT NULL,
`prev` int(11) DEFAULT NULL,
PRIMARY KEY (`next`),
UNIQUE KEY `prev` (`prev`),
CONSTRAINT `fk` FOREIGN KEY (`next`) REFERENCES `letters` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;
INSERT INTO `sort` (`next`, `prev`) VALUES
(3, NULL),
(4, 1),
(6, 3),
(2, 4),
(1, 5),
(5, 6);
If I run now select letter from letters I get the order d,f,a,e,c,b but I want to get the alphabetical order a,b,c,d,e,f not with the help of order by letter but by using the sort table. If you look at the entries in sort table, a with id=3 is first because next=3 and prev is null then b with id=6 is second because next=6 and prev=3, then c with id=5 is third because next=5 and prev=6, etc.
How can I do a custom order using another table in MySQL?
UPDATE
I did it and it may be the only way to do this in mysql:
DELIMITER //
CREATE PROCEDURE `custom_select`()
begin
declare v_next int;
declare v_letter char(1);
declare v_count tinyint;
DROP TEMPORARY TABLE IF EXISTS temp;
CREATE TEMPORARY TABLE temp (id int,letter char(1),idx int AUTO_INCREMENT,PRIMARY KEY (idx));
select id,letter,count(*) into v_next,v_letter,v_count from letters where sort=0;
while v_next is not null do
insert into temp(id,letter)values(v_next,v_letter);
select id,letter,count(*) into v_next,v_letter,v_count from letters where sort=v_next;
end while;
select id,letter from temp order by idx;
end//
DELIMITER ;
CREATE TABLE IF NOT EXISTS `letters` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`letter` char(1) DEFAULT NULL,
`sort` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `sort` (`sort`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=latin1;
DELETE FROM `letters`;
INSERT INTO `letters` (`id`, `letter`, `sort`) VALUES
(1, 'd', 5),
(2, 'f', 4),
(3, 'a', 0),
(4, 'e', 1),
(5, 'c', 6),
(6, 'b', 3);
Then i get a,b,c,d,e,f as expected with:
CALL custom_select

Related

Duplicate Primary Key Entry

I am trying to create 2 tables for poll and poll answers using the following SQL. I am getting the error "Duplicate entry '1' for key 'PRIMARY". Any help is appreciated.
CREATE DATABASE IF NOT EXISTS `phppoll` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `phppoll`;
CREATE TABLE IF NOT EXISTS `polls` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` text NOT NULL,
`desc` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO `polls` (`id`, `title`, `desc`) VALUES (1, 'What''s your favorite way to browse?', '');
INSERT INTO `polls` (`id`, `title`, `desc`) VALUES (2, 'What''s your favorite way to use tech?', '');
CREATE TABLE IF NOT EXISTS `poll_answers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`poll_id` int(11) NOT NULL,
`title` text NOT NULL,
`votes` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
INSERT INTO `poll_answers` (`id`, `poll_id`, `title`, `votes`) VALUES (1, 1, 'Laptop', 0), (2, 1, 'Desktop', 0), (3, 1, 'Tablet', 0), (4, 1, 'Other', 0);
INSERT INTO `poll_answers` (`id`, `poll_id`, `title`, `votes`) VALUES (2, 1, 'Laptop', 0), (2, 2, 'Desktop', 0), (2, 3, 'Tablet', 0), (2, 4, 'Other', 0);
As I point out in my comment, your code is fine.
Your problem is probably due to CREATE TABLE IF NOT EXISTS.
You are probably running the code multiple times, and the table is not replaced the second time. What you want instead is DROP TABLE IF EXISTS.
i think if you try INSERT IGNORE it may help you, go here for more details:
(https://www.mysqltutorial.org/mysql-insert-ignore/)

Calculating sum of a values after join

I have these tables:
CREATE TABLE `items` (
`itemId` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`itemCategoryId` mediumint(8) unsigned DEFAULT NULL,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`itemId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `orders` (
`orderId` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`customerId` tinyint(3) unsigned NOT NULL,
PRIMARY KEY (`orderId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `orders_items` (
`orderItemId` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`orderId` mediumint(8) unsigned NOT NULL,
`itemId` mediumint(8) unsigned NOT NULL,
`price` decimal(10,2) unsigned NOT NULL DEFAULT '0.00',
PRIMARY KEY (`orderItemId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `order_items_quantity` (
`orderItemId` mediumint(8) unsigned NOT NULL,
`size` tinyint(3) unsigned DEFAULT NULL,
`quantity` smallint(5) unsigned NOT NULL,
UNIQUE KEY `unique` (`orderItemId`,`size`,`quantity`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `items` (`itemId`, `itemCategoryId`, `name`)
VALUES
(1, 1, 'Jeans Model A (Category Jeans)'),
(2, 1, 'Jeans Model B (Category Jeans)'),
(3, 2, 'T-Shirt Model A (Category T-Shirt)');
INSERT INTO `orders` (`orderId`, `customerId`)
VALUES
(1, 1),
(2, 2),
(3, 1);
INSERT INTO `orders_items` (`orderItemId`, `orderId`, `itemId`)
VALUES
(1, 1, 1),
(2, 1, 2),
(3, 2, 1),
(4, 2, 2),
(5, 3, 1),
(6, 3, 3);
INSERT INTO `order_items_quantity` (`orderItemId`, `size`, `quantity`)
VALUES
(1, 1, 2),
(1, 2, 3),
(2, 1, 3),
(2, 2, 5),
(3, 1, 1),
(3, 2, 2),
(4, 1, 1),
(4, 2, 1),
(5, 1, 4),
(6, 1, 3);
I can't merge 'order_items' with 'order_items_quantity' because I have other fields in the first table about the items regardless the size (es. their prices in that moment) that would be wasted disk space if I repeat them in only one table.
I need a query to get the sum of all the ordered quantities of any item of a certain category by each customer regerdless of the size. Something like:
customerId itemCategoryId total_quantity_ordered
1 1 17
2. 1 5
2. 2. 3
I wrote this query:
SELECT total_quantities.total_quantity_ordered, orders.customerId, items.itemCategoryId FROM orders
JOIN (
SELECT orders_items.orderId, SUM(order_items_quantity.quantity) AS total_quantity_ordered
FROM orders_items
JOIN order_items_quantity ON order_items_quantity.orderItemId=orders_items.orderItemId
GROUP BY orders_items.orderId
) AS total_quantities ON total_quantities.orderId=orders.orderId
JOIN orders_items ON orders_items.orderId=orders.orderId
JOIN items ON items.itemId=orders_items.itemId
GROUP BY orders.customerId, items.itemCategoryId
but it selects only the first order of every customer containing that categoryId. Any help is appreciated.
SQL Fiddle: https://www.db-fiddle.com/f/bnxomXfobBN25nTJvASVdL/0
You don't need the subquery:
SELECT o.customerId, i.itemCategoryId SUM(q.quantity) AS total_quantity_ordered
FROM orders o
INNER JOIN orders_items oi ON oi.orderId=o.orderId
JOIN order_items_quantity q ON oi.orderItemId=q.orderItemId
JOIN items i ON i.itemId=oi.itemId
GROUP BY o.customerId, i.itemCategoryId

mysql finding not exist records in mutiple tables

CREATE TABLE `Students` (
`id` int(11) NOT NULL,
`name` varchar(500) NOT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `Students` (`id`, `name`) VALUES
(1, 'Student 1'),
(2, 'Student 2'),
(3, 'Student 3');
CREATE TABLE `lessons` (
`id` int(11) NOT NULL,
`name` varchar(500) NOT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `lessons` (`id`, `name`) VALUES
(1, 'Lesson 1'),
(2, 'Lesson 2'),
(3, 'Lesson 3');
CREATE TABLE `completed` (
`student` int(11) NOT NULL,
`lesson` varchar(500) NOT NULL,
`completed` int(11) NOT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `completed` (`student`, `lesson`, `completed`) VALUES
(1, 2, 1),
(3, 3, 1),
(2, 1, 1);
we are adding students who completed lessons to "completed" table. we need to get 5 student with lesson which id not exists in "completed" table.
example output is;
1, 1
1, 3
2, 2
2, 3
3, 1
3, 2
thank you
You can use NOT EXISTS
SELECT s.Id, s.Name
FROM Students s
WHERE NOT EXISTS (
SELECT 1
FROM Completed
WHERE s.Id = student
)
Following should show all of the students that don't have a completed lesson, which is what I think you're asking for:
SELECT Students.id, Students.name FROM Students LEFT JOIN completed
ON Students.id = completed.student WHERE completed.student IS NULL;

what is the best query for tags and other related table

I want to build a query to be suitable for searching in the book.title and the tag.tag
I also want a suitable for counting rows for search query for pagination
Here is my db schema and data
-- Table structure for table `book`
CREATE TABLE IF NOT EXISTS `book` (
`book_id` int(11) NOT NULL,
`title` varchar(200) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
ALTER TABLE `book`
ADD PRIMARY KEY (`book_id`);
-- Dumping data for table `book`
INSERT INTO `book` (`book_id`, `title`) VALUES
(1, 'Alice Journey'),
(2, 'Rody Journey'),
(3, 'My Journey to Amsterdam'),
(4, 'How to train your ketty'),
(5, 'The red fox');
-- --------------------------------------------------------
-- Table structure for table `tag`
CREATE TABLE IF NOT EXISTS `tag` (
`tag_id` int(11) NOT NULL,
`tag` varchar(50) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
ALTER TABLE `tag`
ADD PRIMARY KEY (`tag_id`);
-- Dumping data for table `tag`
INSERT INTO `tag` (`tag_id`, `tag`) VALUES
(1, 'pets'),
(2, 'tale'),
(3, 'Journey');
-- --------------------------------------------------------
-- Table structure for table `tag_book`
CREATE TABLE IF NOT EXISTS `tag_book` (
`tag_id` int(11) NOT NULL,
`book_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `tag_book`
ADD PRIMARY KEY (`tag_id`,`book_id`);
-- Dumping data for table `tag_book`
INSERT INTO `tag_book` (`tag_id`, `book_id`) VALUES
(1, 4),
(2, 1),
(2, 2),
(2, 5),
(3, 1),
(3, 2),
(3, 3);
search = 'rody' // exists in book table
search = 'pets' // exists in tag tab
search = 'journey' // exists in book and tag tables
thanks

Count of multiple columns from a table in mysql

I have total 3 tables
tbl_projects,tbl_bug,tbl_bug_history
i need to display total of 3 counts for each projects.
1.total bug for each projects- this is from tbl_bug
total count of "invalid", total count of "duplicate"-- this is from bug history
Output should be in the following sample format
project name | total bug | invalid | duplicate |
project-one | 5 | 6 | 7 |
Please help me table structure is define below
CREATE TABLE IF NOT EXISTS `tbl_bug` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`project_id` int(10) NOT NULL,
`bugname` varchar(250) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ;
Dumping data for table tbl_bug
INSERT INTO `tbl_bug` (`id`, `project_id`, `bugname`) VALUES
(1, 1, 'first-bug'),
(2, 1, 'second-bug'),
(3, 1, 'bug-third'),
(4, 1, 'bug-four'),
(5, 1, 'bug-give'),
(6, 1, 'master-bug'),
(7, 2, 'error-notice'),
(8, 3, 'invalid bug'),
(9, 4, 'insufficinet memory'),
(10, 4, 'hello bug');
CREATE TABLE IF NOT EXISTS `tbl_bug_history` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`bug_id` int(10) NOT NULL,
`status` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=21 ;
Dumping data for table tbl_bug_history
INSERT INTO `tbl_bug_history` (`id`, `bug_id`, `status`) VALUES
(2, 1, 'invalid'),
(3, 2, 'invalid'),
(6, 3, 'duplicate'),
(7, 4, 'feedback'),
(10, 5, 'duplicate'),
(11, 6, 'duplicate'),
(12, 6, 'invalid'),
(13, 7, 'feedback'),
(14, 7, 'normal'),
(15, 8, 'duplicate'),
(16, 8, 'normal'),
(18, 9, 'feedback'),
(19, 10, 'invalid'),
(20, 10, 'feedback');
CREATE TABLE IF NOT EXISTS `tbl_projects` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`projectname` varchar(250) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
Dumping data for table tbl_projects
INSERT INTO `tbl_projects` (`id`, `projectname`) VALUES
(1, 'project-one'),
(2, 'project-two'),
(3, 'project-three'),
(4, 'project-four');
Try this.This is your expected output I think.
http://sqlfiddle.com/#!2/1d756/3