Count of multiple columns from a table in mysql - 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

Related

How to create dynamic columns using prepared statements in MySQL?

I have 4 tables related to each other.
CREATE TABLE `location` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `location` (`id`, `name`) VALUES
(1, 'Dallas'),
(2, 'Boston'),
(3, 'Houston');
CREATE TABLE `item` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`brand` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `item` (`id`, `brand`) VALUES
(1, 'Nissan Almera M/T 2009-2015'),
(2, 'Toyota Corolla A/T 2005-2012'),
(3, 'Nissan Terra A/T 2010-2017'),
(4, 'Suzuki Esteem M/T 1980-1990'),
(5, 'Toyota Fortuner A/T 2014-2020');
CREATE TABLE `item_in` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`location_id` bigint(20) UNSIGNED NOT NULL,
`item_id` bigint(20) UNSIGNED NOT NULL,
`quantity` int(11) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `item_in` (`id`, `location_id`, `item_id`, `quantity`) VALUES
(1, 1, 1, 1000),
(2, 1, 2, 500),
(3, 2, 2, 200),
(4, 2, 2, 300),
(5, 3, 3, 300),
(6, 1, 3, 800),
(7, 3, 5, 300),
(8, 3, 4, 400);
CREATE TABLE `item_out` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`location_id` bigint(20) UNSIGNED NOT NULL,
`item_id` bigint(20) UNSIGNED NOT NULL,
`quantity` int(11) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `item_out` (`id`, `location_id`, `item_id`, `quantity`) VALUES
(1, 1, 2, 20),
(2, 1, 1, 25),
(3, 2, 2, 25),
(4, 3, 3, 25),
(5, 3, 5, 10),
(6, 3, 4, 15),
(7, 1, 1, 200),
(8, 2, 2, 50);
Using dynamic SQL, I was able to get the individual remaining quantities per item based on their location and item (item_in quantity subtracted by item_out quantity) and have the location names as columns. (see code below):
SET #sql = NULL, #sql1 = NULL, #sql2 = NULL;
SELECT GROUP_CONCAT( DISTINCT
CONCAT('SUM(CASE WHEN `location_id` = ''',`location_id`, ''' THEN quantity END) AS ',`name`))
INTO #sql1
FROM item_in
JOIN location on location.id = item_in.location_id;
SELECT GROUP_CONCAT( DISTINCT
CONCAT('SUM(CASE WHEN `location_id` = ''',`location_id`, ''' THEN quantity END) AS ',`name`))
INTO #sql2
FROM item_out
JOIN location on location.id = item_out.location_id;
SET #sql = CONCAT('SELECT item.brand AS Item, IFNULL(item_in.Dallas, 0) - IFNULL(item_out.Dallas, 0) AS Dallas, IFNULL(item_in.Boston, 0) - IFNULL(item_out.Boston, 0) AS Boston, IFNULL(item_in.Houston, 0) - IFNULL(item_out.Houston, 0) AS Houston FROM item LEFT JOIN (SELECT item_in.item_id, ', #sql1, ' FROM item_in
GROUP BY item_in.item_id) AS item_in ON item.id = item_in.item_id LEFT JOIN (SELECT item_out.item_id, ', #sql2, ' FROM item_out
GROUP BY item_out.item_id) AS item_out ON item.id = item_out.item_id');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Result:
Item | Dallas | Boston | Houston
Nissan Almera M/T 2009-2015 775 0 0
Toyota Corolla A/T 2005-2012 480 425 0
Nissan Terra A/T 2010-2017 800 0 275
Suzuki Esteem M/T 1980-1990 0 0 385
Toyota Fortuner A/T 2014-2020 0 0 290
My question, how do I go about changing the code so that the location name columns is displayed dynamically instead of hardcoding them manually in the query since users can add new locations anytime? if anyone can take a look at my code, i'd really appreciate the help. The only part I'm having trouble is how to not hardcode these lines and do them dynamically:
IFNULL(item_in.Dallas, 0) - IFNULL(item_out.Dallas, 0) AS Dallas, IFNULL(item_in.Boston, 0) - IFNULL(item_out.Boston, 0) AS Boston, IFNULL(item_in.Houston, 0) - IFNULL(item_out.Houston, 0) AS Houston
By way of example, consider the following, which uses PHP and the mysqli_ API. (I've used procedural code, but dbo would be more efficient)...
<?php
/*
DROP TABLE IF EXISTS location;
CREATE TABLE `location` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (id)
);
INSERT INTO `location` (`id`, `name`) VALUES
(1, 'Dallas'),
(2, 'Boston'),
(3, 'Houston');
DROP TABLE IF EXISTS item;
CREATE TABLE `item` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`brand` varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
);
INSERT INTO `item` (`id`, `brand`) VALUES
(1, 'Nissan Almera M/T 2009-2015'),
(2, 'Toyota Corolla A/T 2005-2012'),
(3, 'Nissan Terra A/T 2010-2017'),
(4, 'Suzuki Esteem M/T 1980-1990'),
(5, 'Toyota Fortuner A/T 2014-2020');
DROP TABLE IF EXISTS item_in;
CREATE TABLE `item_in` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`location_id` bigint(20) UNSIGNED NOT NULL,
`item_id` bigint(20) UNSIGNED NOT NULL,
`quantity` int(11) DEFAULT NULL,
PRIMARY KEY (id)
);
INSERT INTO `item_in` (`id`, `location_id`, `item_id`, `quantity`) VALUES
(1, 1, 1, 1000),
(2, 1, 2, 500),
(3, 2, 2, 200),
(4, 2, 2, 300),
(5, 3, 3, 300),
(6, 1, 3, 800),
(7, 3, 5, 300),
(8, 3, 4, 400);
DROP TABLE IF EXISTS item_out;
CREATE TABLE `item_out` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`location_id` bigint(20) UNSIGNED NOT NULL,
`item_id` bigint(20) UNSIGNED NOT NULL,
`quantity` int(11) DEFAULT NULL,
PRIMARY KEY (id)
);
INSERT INTO `item_out` (`id`, `location_id`, `item_id`, `quantity`) VALUES
(1, 1, 2, 20),
(2, 1, 1, 25),
(3, 2, 2, 25),
(4, 3, 3, 25),
(5, 3, 5, 10),
(6, 3, 4, 15),
(7, 1, 1, 200),
(8, 2, 2, 50);
*/
require('path/to/connect.ion');
$query = "
SELECT l.name city
, i.brand item
, SUM(x.quantity) total
FROM
( SELECT location_id,item_id,'in' type, quantity FROM item_in
UNION ALL
SELECT location_id,item_id,'out',quantity*-1 FROM item_out
) x
JOIN location l
ON l.id = x.location_id
JOIN item i
ON i.id = x.item_id
GROUP
BY item
, city
ORDER
BY city
, item
";
$result = mysqli_query($db,$query);
$array = array();
while($row = mysqli_fetch_assoc($result)){
$array[] = $row;
}
foreach($array as $v){
$new_array[$v['city']][$v['item']] = $v['total'];
}
print_r($new_array);
?>
Outputs:
Array
(
[Boston] => Array
(
[Toyota Corolla A/T 2005-2012] => 425
)
[Dallas] => Array
(
[Nissan Almera M/T 2009-2015] => 775
[Nissan Terra A/T 2010-2017] => 800
[Toyota Corolla A/T 2005-2012] => 480
)
[Houston] => Array
(
[Nissan Terra A/T 2010-2017] => 275
[Suzuki Esteem M/T 1980-1990] => 385
[Toyota Fortuner A/T 2014-2020] => 290
)
)
Or you can swap city and item around in $new_array[$v['city']][$v['item']] = $v['total'];, to get:
Array
(
[Toyota Corolla A/T 2005-2012] => Array
(
[Boston] => 425
[Dallas] => 480
)
[Nissan Almera M/T 2009-2015] => Array
(
[Dallas] => 775
)
[Nissan Terra A/T 2010-2017] => Array
(
[Dallas] => 800
[Houston] => 275
)
[Suzuki Esteem M/T 1980-1990] => Array
(
[Houston] => 385
)
[Toyota Fortuner A/T 2014-2020] => Array
(
[Houston] => 290
)
)

How to pull the last data from table 2 using LEFT JOIN with 2 tables?

I'm coding a chat room using 2 mysql tables. One of these tables is the inbox and the other is the messages table.
I want to find the table "user_mailboxes" from another table belonging to someone else and sort it by grouping advert_id.
I want the last sent message to be at the top and at the specified location. I would be glad if you help.
The SQL code I use:
SELECT *
FROM user_mailboxes
LEFT
JOIN mbox
ON mbox.id = user_mailboxes.message_id
WHERE (user_mailboxes.user = '$users['id']'
AND user_mailboxes.mailbox = 'Out')
|| (user_mailboxes.user = '$users['id']'
AND user_mailboxes.mailbox = 'In')
GROUP
BY user_mailboxes.advert_id
ORDER
BY mbox.created DESC
I'm using a Foreach loop. Result:
user_mailboxes TABLE
mysql
CREATE TABLE `mbox` (
`id` int(100) NOT NULL,
`message` text COLLATE utf8_unicode_ci,
`sentby` int(100) DEFAULT NULL,
`sentto` int(100) DEFAULT NULL,
`created` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `mbox` (`id`, `message`, `sentby`, `sentto`, `created`) VALUES
(1, 'Hello!', 1, 4, '2019-10-25 00:25:38'),
(2, 'Last Messages How are you ?', 1, 4, '2019-10-25 00:26:14'),
(3, 'Welcome', 1, 2, '2019-10-25 00:26:45'),
(4, ':) last messages', 1, 2, '2019-10-25 00:27:02');
mbox TABLE
mysql
CREATE TABLE `user_mailboxes` (
`id` int(100) NOT NULL,
`user` int(100) DEFAULT NULL,
`mailbox` enum('Out','In') COLLATE utf8_unicode_ci DEFAULT NULL,
`message_id` int(100) DEFAULT NULL,
`advert_id` int(100) DEFAULT NULL,
`room_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `user_mailboxes` (`id`, `user`, `mailbox`, `message_id`, `advert_id`, `room_name`) VALUES
(1, 1, 'Out', 1, 67, '67-1'),
(2, 4, 'In', 1, 67, '67-1'),
(3, 1, 'Out', 2, 67, '67-1'),
(4, 4, 'In', 2, 67, '67-1'),
(5, 1, 'Out', 3, 1, '1-1'),
(6, 2, 'In', 3, 1, '1-1'),
(7, 1, 'Out', 4, 1, '1-1'),
(8, 2, 'In', 4, 1, '1-1');

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 custom order by another table

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

select all column of table but row should be filtered by unique or disticnt entry in a column

CREATE TABLE IF NOT EXISTS `history` (
`bill_no` int(11) NOT NULL,
`cid` int(11) NOT NULL,
`pid` int(11) NOT NULL,
`TIME` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
`price` decimal(65,4) unsigned NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Dumping data for table history
INSERT INTO `history` (`cid`, `pid`, `TIME`, `price`) VALUES
(3, 1, '2014-11-12 17:39:14', '71500.0000'),
(3, 3, '2014-11-12 17:39:14', '22500.0000'),
(3, 1, '2014-11-12 17:40:36', '71500.0000'),
(3, 1, '2014-11-12 17:52:36', '71500.0000'),
(3, 3, '2014-11-12 19:09:23', '22500.0000'),
(3, 5, '2014-11-12 19:09:23', '29000.0000'),
(3, 9, '2014-11-12 19:09:23', '29000.0000');
I WANT A QUERY WHICH SHOULD GIVE THE FOLLOWING OUTPUT on the basis of cid but unique/distinct TIME
PRINTING UNIQUE/DISTINCT VALUE
(3, '2014-11-12 17:39:14')
(3, '2014-11-12 17:40:36')
(3, '2014-11-12 17:52:36')
(3, '2014-11-12 19:09:23')
(3, '2014-11-12 19:09:23')
What if you try with a simple sub query like
select * from history where `time` in (select distinct `time` from history);