Calculating sum of a values after join - mysql

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

Related

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

SQL sorted by a diferent fields

I have the next tables and rows. And I need to write a SELECT that returns all categories sorted by:
(A) the number of items they have
and (B) the category name.
This query should fetch the following columns: the category name, the number of items (AS N_ITEMS) and the average price of the titles in that category (AS AVERAGE_PRICE)
CREATE TABLE `category` (
`CATEGORY_ID` int(11) NOT NULL,
`CATEGORY_NAME` varchar(50) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `category` (`CATEGORY_ID`, `CATEGORY_NAME`) VALUES
(1, 'Sports'),
(2, 'Actualités'),
(3, 'Animaux'),
(4, 'Economie'),
(5, 'Cuisine');
CREATE TABLE `item` (
`ITEM_ID` int(11) NOT NULL,
`CATEGORY_ID` int(11) NOT NULL,
`ITEM_NAME` varchar(50) NOT NULL,
`ITEM_PRICE` decimal(8,2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `item` (`ITEM_ID`, `CATEGORY_ID`, `ITEM_NAME`, `ITEM_PRICE`) VALUES
(1, 1, 'Equip', '6.00'),
(2, 2, 'Le Monde', '3.00'),
(3, 2, 'Le Parisien', '2.50'),
(4, 2, 'France soir', '3.00'),
(5, 3, '30 Million damis', '6.20'),
(6, 3, 'Cheval pratique', '4.50'),
(7, 4, 'Capital', '2.50');
ALTER TABLE `category`
ADD PRIMARY KEY (`CATEGORY_ID`);
ALTER TABLE `item`
ADD PRIMARY KEY (`ITEM_ID`);
ALTER TABLE `category`
MODIFY `CATEGORY_ID` int(11) NOT NULL AUTO_INCREMENT;
ALTER TABLE `item`
MODIFY `ITEM_ID` int(11) NOT NULL AUTO_INCREMENT;
COMMIT;
You can try below -
select CATEGORY_NAME, count(ITEM_ID) as noofItem,avg(item_price) as avgprice
from category inner join item on category.category_id=item.category_id
group by CATEGORY_NAME
order by noofItem,CATEGORY_NAME

how to calculate percentage and generate below result

I have a table schema
CREATE TABLE `charge` (
`charge_id` int(11) NOT NULL AUTO_INCREMENT,
`selling_date` date DEFAULT NULL,
`amount` decimal(10,2) DEFAULT NULL,
`is_deleted` tinyint(1) NOT NULL DEFAULT '0',
`charge_type_id` int(11) DEFAULT NULL,
PRIMARY KEY (`charge_id`)
);
CREATE TABLE `charge_type` (
`charge_type_id` int(11) NOT NULL AUTO_INCREMENT,
`charge_type` varchar(20) NOT NULL,
`is_deleted` tinyint(1) DEFAULT '0',
PRIMARY KEY (`charge_type_id`)
);
CREATE TABLE `charge_type_tax_list` (
`tax_type_id` int(11) NOT NULL,
`charge_type_id` int(11) NOT NULL,
PRIMARY KEY (`tax_type_id`,`charge_type_id`)
);
CREATE TABLE `tax_type` (
`tax_type_id` int(11) NOT NULL AUTO_INCREMENT,
`tax_type` varchar(35) NOT NULL,
`percentage` decimal(5,4) NOT NULL DEFAULT '0.0000',
`is_deleted` tinyint(1) DEFAULT '0',
PRIMARY KEY (`tax_type_id`)
);
INSERT INTO charge (
`selling_date`,
`amount`,
`is_deleted`,
`charge_type_id`
)
VALUES
("2013-12-01", 50, 0, 1),
("2013-12-01", 20, 0, 2),
("2013-12-02", 40, 0, 1),
("2013-12-02", 30, 0, 3),
("2013-12-02", 30, 1, 1),
("2013-12-03", 10, 0, 1);
INSERT INTO charge_type (
`charge_type_id`,
`charge_type`,
`is_deleted`
)
VALUES
(1, "room charge", 0),
(2, "snack charge", 0),
(3, "deleted charge", 1);
INSERT INTO charge_type_tax_list (
`tax_type_id`,
`charge_type_id`
)
VALUES
(1, 1),
(2, 1),
(3, 1),
(1, 2),
(1, 3);
INSERT INTO tax_type (
`tax_type_id`,
`tax_type` ,
`percentage`,
`is_deleted`
)
VALUES
(1, "GST", 0.05, 0),
(2, "HRT", 0.04, 0),
(3, "DELETED TAX", 0.10, 1);
I want you to produce a query that lists all charges and tax-calculated totals
With the given schema, your query should produce:
Selling Date Charge Type Amount Tax
2013-12-01 Room Charge 50.00 4.50
2013-12-01 Snack Charge 20.00 1.00
2013-12-02 Room Charge 40.00 3.60
2013-12-03 Room Charge 10.00 0.90
Do not display charges that are deleted (is_deleted is flagged)
Do not display charges that have charge_types that are deleted (is_deleted is flagged)
Do not consider tax_type that is deleted (is_deleted), but the containing charge_type should still be displayed)
Please help me I need it urgently.Thanks
Please read on MySQL Join Made Easy to understand how joins are used. Here is a query that should give the result you want by joining the tables on the common attributes.
SELECT A.`selling_date` AS `Selling Date`, B.`charge_type` AS `Charge Type`
, A.`amount` AS `Amount`, (A.`amount` * D.`percentage`) AS `Tax` FROM
`charge` A LEFT JOIN
`charge_type` B ON A.`charge_type_id`=B.`charge_type_id` INNER JOIN
`charge_type_tax_list` C ON B.`charge_type_id`=C.`charge_type_id`
INNER JOIN `tax_type` D ON C.`tax_type_id`=D.`tax_type_id`
WHERE
A.`is_deleted`=0 AND B.`is_deleted`=0 AND
D.`is_deleted`=0;
Here is an SQL FIDDLE DEMO
This query below will get the result that you want
select charge.selling_date as SellingDate,
charge.amount as Amount,
charge_type.charge_type as ChargeType,
sum(charge.amount * tax_type.percentage) as Tax
From charge
inner join charge_type on charge.charge_type_id=charge_type.charge_type_id,
tax_type
where charge.is_deleted=0 and charge_type.is_deleted=0 and tax_type.is_deleted=0
group by charge.selling_date, charge.amount,charge_type.charge_type

Else is not running in mysql Query

I have below query. In this I have yes and no case.
yes is accessing but else part is not working . Please have a look on this.
SELECT SalesChannel.name , count(Transaction.category_id) as count, (case when (Transaction.no_of_units > 0 and Transaction.mop > 0) THEN 'yes' ELSE 'No' END) AS Is_Present from outlets Outlet inner join transactions Transaction on Outlet.id = Transaction.outlet_id inner join sale_channels SalesChannel on SalesChannel.id = Outlet.sale_channel_id group by SalesChannel.name
the output should be as below
KU Electrical
Yes 6 2
No 1 2
6 is counter of KU and Yes refers the presence,similarly No is non presence of KU
select SalesChannel.name ,
Transaction.category_id,
count(Transaction.category_id) as count,
from outlets Outlet inner join transactions Transaction on Outlet.id = Transaction.outlet_id inner join sale_channels SalesChannel on SalesChannel.id = Outlet.sale_channel_id group by SalesChannel.name
below are three tables which i used
1. transactions
CREATE TABLE IF NOT EXISTS `transactions` (
`id` int(11) NOT NULL,
`zone_id` int(11) NOT NULL,
`state_id` int(11) NOT NULL,
`city_id` int(11) NOT NULL,
`category_id` int(11) NOT NULL,
`sub_category_id` int(11) NOT NULL,
`brand_id` int(11) NOT NULL,
`model_id` int(11) NOT NULL,
`outlet_id` int(11) NOT NULL,
`no_of_units` int(11) NOT NULL,
`mop` decimal(10,2) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
--
-- Dumping data for table `transactions`
--
INSERT INTO `transactions` (`id`, `zone_id`, `state_id`, `city_id`, `category_id`, `sub_category_id`, `brand_id`, `model_id`, `outlet_id`, `no_of_units`, `mop`) VALUES
(1, 2, 2, 2, 2, 1, 1, 1, 1, 3, '6.00'),
(2, 2, 2, 2, 2, 1, 1, 1, 1, 3, '6.00'),
(3, 1, 1, 1, 1, 1, 1, 1, 1, 4, '2.00'),
(4, 2, 2, 2, 1, 1, 1, 1, 2, 4, '2.00');
2.outlets
CREATE TABLE IF NOT EXISTS `outlets` (
`id` int(11) NOT NULL,
`outlet_code` varchar(255) NOT NULL,
`name` varchar(255) NOT NULL,
`zone_id` int(11) NOT NULL,
`state_id` int(11) NOT NULL,
`city_id` int(11) NOT NULL,
`sale_channel_id` int(11) NOT NULL,
`is_active` tinyint(1) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
--
-- Dumping data for table `outlets`
--
INSERT INTO `outlets` (`id`, `outlet_code`, `name`, `zone_id`, `state_id`, `city_id`, `sale_channel_id`, `is_active`, `created`, `modified`) VALUES
(1, '1508', 'Ashok electricals', 2, 2, 2, 1, 1, '2016-10-03 00:00:00', '2016-10-03 00:00:00'),
(2, '1233', 'vinayak electricals', 1, 1, 1, 2, 1, '2016-10-04 00:00:00', '2016-10-04 00:00:00');
3. sale_chennals
CREATE TABLE IF NOT EXISTS `sale_channels` (
`id` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
`is_active` tinyint(1) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
--
-- Dumping data for table `sale_channels`
--
INSERT INTO `sale_channels` (`id`, `name`, `is_active`, `created`, `modified`) VALUES
(1, 'KU', 1, '2016-10-03 00:00:00', '2016-10-03 00:00:00'),
(2, 'Electricals', 1, '2016-10-04 00:00:00', '2016-10-04 00:00:00');
There is no data in tables that match for the else condition. Your condition is that "Transaction.no_of_units >0 AND Transaction.mop >0" that is not match in table value of both fields are greater than 0.
Otherwise, else condition works fine.
You are aggregating your data so as to get one row per SalesChannel.name. There may be some transaction records that result in 'Yes' and others in 'No' for a SalesChannel.name, so what then is Is_Present supposed to be?
Another issue with your query is that the sale channels are in a table. There are currently two of them, but there could be three or four or thousands sometime. A SQL query doesn't produce a result with a variable number of columns. The columns must be known beforehand. So a possible result could look like this:
Name Yes No
KU 6 1
Electrical 2 2
because you know you want it to be Yes or No only, no matter how many channels.
The query:
select
sc.name,
count(case when t.no_of_units > 0 and t.mop > 0 then 1 end) as yes,
count(case when t.no_of_units <= 0 or t.mop <= 0 then 1 end) as no
from sale_channels sc
join outlet o on o.sale_channel_id = sc.id
join transactions t on t.outlet_id = o.id;

showing counter in mysql query

I have mysql query given below. I which counter has been used. if i enter category Id 1 for 3 times then counter is coming 3 which is correct but with this i want if i do not enter then different coloumn should come with NO.
output should be
KU Electrical
Yes 6 2
No 1 2
In this KU and Electrical are my sale channel name. Yes means counter of enteries of KU and No means which have not entered. Please help out in this. i am struggling
select
SalesChannel.name,
Transaction.category_id,
count(Transaction.category_id) as "count"
from outlets Outlet
inner join transactions Transaction on Outlet.id = Transaction.outlet_id
inner join sale_channels SalesChannel on SalesChannel.id = Outlet.sale_channel_id
group by Transaction.category_id;
below are three tables which I used
1) transactions
CREATE TABLE IF NOT EXISTS `transactions` (
`id` int(11) NOT NULL,
`zone_id` int(11) NOT NULL,
`state_id` int(11) NOT NULL,
`city_id` int(11) NOT NULL,
`category_id` int(11) NOT NULL,
`sub_category_id` int(11) NOT NULL,
`brand_id` int(11) NOT NULL,
`model_id` int(11) NOT NULL,
`outlet_id` int(11) NOT NULL,
`no_of_units` int(11) NOT NULL,
`mop` decimal(10,2) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
--
-- Dumping data for table `transactions`
--
INSERT INTO `transactions` (`id`, `zone_id`, `state_id`, `city_id`, `category_id`, `sub_category_id`, `brand_id`, `model_id`, `outlet_id`, `no_of_units`, `mop`) VALUES
(1, 2, 2, 2, 2, 1, 1, 1, 1, 3, '6.00'),
(2, 2, 2, 2, 2, 1, 1, 1, 1, 3, '6.00'),
(3, 1, 1, 1, 1, 1, 1, 1, 1, 4, '2.00'),
(4, 2, 2, 2, 1, 1, 1, 1, 2, 4, '2.00');
2) outlets
CREATE TABLE IF NOT EXISTS `outlets` (
`id` int(11) NOT NULL,
`outlet_code` varchar(255) NOT NULL,
`name` varchar(255) NOT NULL,
`zone_id` int(11) NOT NULL,
`state_id` int(11) NOT NULL,
`city_id` int(11) NOT NULL,
`sale_channel_id` int(11) NOT NULL,
`is_active` tinyint(1) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
--
-- Dumping data for table `outlets`
--
INSERT INTO `outlets` (`id`, `outlet_code`, `name`, `zone_id`, `state_id`, `city_id`, `sale_channel_id`, `is_active`, `created`, `modified`) VALUES
(1, '1508', 'Ashok electricals', 2, 2, 2, 1, 1, '2016-10-03 00:00:00', '2016-10-03 00:00:00'),
(2, '1233', 'vinayak electricals', 1, 1, 1, 2, 1, '2016-10-04 00:00:00', '2016-10-04 00:00:00');
3) sale_chennals
CREATE TABLE IF NOT EXISTS `sale_channels` (
`id` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
`is_active` tinyint(1) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
--
-- Dumping data for table `sale_channels`
--
INSERT INTO `sale_channels` (`id`, `name`, `is_active`, `created`, `modified`) VALUES
(1, 'KU', 1, '2016-10-03 00:00:00', '2016-10-03 00:00:00'),
(2, 'Electricals', 1, '2016-10-04 00:00:00', '2016-10-04 00:00:00');
SQL fiddle: http://sqlfiddle.com/#!9/3f497/1
You are grouping by category. That means you get one result row per category. In each of these rows you show the count and a sale channel name. This sale channel name is just one of the names found in the records for the category arbitrarily chosen.
I suppose you want to count per category and sale channel. Hence your group by clause should be group by SalesChannel.name, Transaction.category_id:
select
SalesChannel.name,
Transaction.category_id,
count(Transaction.category_id) as "count"
from outlets Outlet
inner join transactions Transaction on Outlet.id = Transaction.outlet_id
inner join sale_channels SalesChannel on SalesChannel.id = Outlet.sale_channel_id
group by SalesChannel.name, Transaction.category_id;
SQL fiddle: http://sqlfiddle.com/#!9/3f497/2
This result, however, doesn't show an entry for Electricals / category 2, because there is no transaction for this combination in the table. If you want to show a zero count for this, you'd have to create the complete result set (i.e. all combinations of channel and category, whether they have a transaction or not) first. Then you'd outer join the transactions:
select
sc.name,
c.id as category_id,
count(t.id) as "count"
from sale_channels sc
cross join categories c
left join outlets o on o.sale_channel_id = sc.id
left join transactions t on t.outlet_id = o.id and t.category_id = c.id
group by sc.name, c.id;
SQL fiddle: http://sqlfiddle.com/#!9/60e998/5