I have three MySQL tables:
For example
A Table is menu ID, name
B table is customer_order ID, order_date
C table is order_item ID, menu_item_id, customer_order_id, order_quantity
I try to output name, sum(order_quantity) in this month
Currently i have two separate query which working ok, but the second query is inside of foreach loop, which seem not so good.
First query which output all the menu items:
$results = $wpdb->get_results( "SELECT * FROM menu WHERE post_id = $pid ORDER BY sort_order ");
Second query will output total of each item sold on each month:
$total = $wpdb->get_col( "SELECT SUM(oi.order_item_quantity)
from order_item as oi
INNER JOIN customer_order as ho ON ho.ID = oi.order_id
WHERE oi.order_item_id = $subC->ID AND YEAR(ho.order_date) = $current_year AND MONTH(ho.order_date) = $current_month ");
I try to merge the two queries into one query, which has taken me whole day but still not able to solve it, can anyone give me some help please.
update
thanks Rene.
Select m.name, m.name as name, sum(oi.order_item_quantity) as sold_monthly from menu as m left join order_item as oi on oi.order_item_id = m.ID left join cusomter_order as co on co.ID = oi.order_id where m.post_id = 110 group by m.ID, m.name
this will output
name sold_monthly
Sushi Lunch Special NULL
Sushi Lunch 19
Sashimi Lunch 61
jason NULL
egg roll NULL
if i add YEAR(co.order_date) = 2016 AND MONTH(co.order_date) = 9
which i only get
name sold_monthly
Sushi Lunch 7
Sashimi Lunch 14
how can i keep sushi lunch special, jason, egg roll, the null item, when i add the YEAR(co.order_date) = 2016 AND MONTH(co.order_date) = 9.
here i try
(year(co.order_date) = 2016 and month(co.order_date) = 10) or sold_monthly is null
which give me a query error
update
thanks Rene again
it's working now
(year(co.order_date) = 2016 and month(co.order_date) = 10) or co.order_date is null
finally solve it, upper have little bug, when i change business_id which may not catch the result i want, so i am add a subquery to it.
Select m.*, p.sold_monthly from menu as m left join ( SELECT SUM(oi.order_item_quantity) as sold_monthly, oi.order_item_id as ID, oi.order_item_name from order_item as oi LEFT JOIN cusomter_order as ho ON ho.ID = oi.order_id WHERE ho.business_id = $pid AND (year(ho.order_date) = $current_year and month(ho.order_date) = $current_month) OR ho.order_date is NULL GROUP by oi.order_item_id )p on p.ID = m.ID where m.post_id = $pid
So you're trying to get a list per post_id limited by the selected month.
The following query will yield that for the following sample data.
SELECT m.ID as ID, m.Name as Name, SUM(oi.order_quantity) as Quantity
FROM menu as m
LEFT JOIN order_item as oi ON oi.menu_item_id = m.ID
LEFT JOIN customer_order as co ON co.ID = oi.customer_order_id
WHERE m.post_id = 0 AND YEAR(co.order_date) = 2016 AND MONTH(co.order_date) = 9 OR co.order_date is NULL
GROUP BY m.ID,m.Name,m.sort_order
ORDER BY m.sort_order
Sample Data
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
DROP TABLE IF EXISTS `customer_order`;
CREATE TABLE `customer_order` (
`ID` int(11) NOT NULL,
`order_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_german2_ci;
TRUNCATE TABLE `customer_order`;
INSERT INTO `customer_order` (`ID`, `order_date`) VALUES
(1, '2016-09-06 00:00:00'),
(2, '2016-09-13 00:00:00'),
(3, '2016-08-09 00:00:00'),
(4, '2016-09-19 00:00:00');
DROP TABLE IF EXISTS `menu`;
CREATE TABLE `menu` (
`ID` int(11) NOT NULL,
`sort_order` int(11) NOT NULL,
`post_id` int(11) NOT NULL,
`Name` varchar(20) COLLATE utf8_german2_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_german2_ci;
TRUNCATE TABLE `menu`;
INSERT INTO `menu` (`ID`, `sort_order`, `post_id`, `Name`) VALUES
(2, 0, 0, 'Test 1'),
(4, 1, 0, 'Test 2'),
(5, 2, 0, 'Test 3');
DROP TABLE IF EXISTS `order_item`;
CREATE TABLE `order_item` (
`ID` int(11) NOT NULL,
`menu_item_id` int(11) NOT NULL,
`customer_order_id` int(11) NOT NULL,
`order_quantity` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_german2_ci;
TRUNCATE TABLE `order_item`;
INSERT INTO `order_item` (`ID`, `menu_item_id`, `customer_order_id`, `order_quantity`) VALUES
(1, 2, 1, 1),
(2, 2, 2, 3),
(3, 4, 1, 1),
(4, 4, 2, 4),
(5, 2, 3, 3),
(6, 4, 3, 1),
(7, 2, 4, 4);
ALTER TABLE `customer_order`
ADD PRIMARY KEY (`ID`);
ALTER TABLE `menu`
ADD PRIMARY KEY (`ID`),
ADD KEY `idx_pid` (`post_id`);
ALTER TABLE `order_item`
ADD PRIMARY KEY (`ID`),
ADD KEY `idx_coid` (`customer_order_id`),
ADD KEY `idx_miid` (`menu_item_id`);
ALTER TABLE `customer_order`
MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5;
ALTER TABLE `menu`
MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=6;
ALTER TABLE `order_item`
MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=8;
ALTER TABLE `order_item`
ADD CONSTRAINT `CostomerOrderConstrain` FOREIGN KEY (`customer_order_id`) REFERENCES `customer_order` (`ID`),
ADD CONSTRAINT `MenuItemConstrain` FOREIGN KEY (`menu_item_id`) REFERENCES `menu` (`ID`);
Good luck integrating the query, let me know if it worked.
Update: Updated sample data to reproduce the actual problem. Updated the Solution Query.
Related
I have a MYSQL table called tbl_product
Another table called tb_opciones_productos
And a third table called tb_opciones
I need to show every item from tbl_product as follows:
How can I get one item from tbl_product and the needed rows from tb_opciones_producto to get the needed result?
EDIT:
This is my current query proposal:
SELECT tbl_product.*,
GROUP_CONCAT( (SELECT CONCAT(tb_opciones.nombre, "(+$", tb_opciones.precio, ")")
FROM tb_opciones WHERE tb_opciones.id_opcion = tb_opciones_productos.id_opcion) SEPARATOR "<br>" ) as options FROM tbl_product
INNER JOIN tb_opciones_productos ON tbl_product.id = tb_opciones_productos.producto
I've create a little sqlfiddle to test : http://sqlfiddle.com/#!9/fc3316/16
You can GROUP_CONCAT a sub-query. It may not be optimized, but it do the job.
PS: next time, can you provide a sample structure ?
Structure :
CREATE TABLE IF NOT EXISTS `products` (
`id` int(6) unsigned NOT NULL,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `products` (`id`, `name`) VALUES
(1, 'Product Lorem'),
(2, 'Product Ipsum');
CREATE TABLE IF NOT EXISTS `products_options` (
`id_product` int(6) unsigned NOT NULL,
`id_option` int(6) unsigned NOT NULL,
PRIMARY KEY (`id_product`, `id_option`)
) DEFAULT CHARSET=utf8;
INSERT INTO `products_options` (`id_product`, `id_option`) VALUES
(1, 1),
(1, 2),
(1, 3),
(2, 3);
CREATE TABLE IF NOT EXISTS `options` (
`id` int(6) unsigned NOT NULL,
`name` varchar(255) NOT NULL,
`value` double NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `options` (`id`, `name`, `value`) VALUES
(1, 'Option A', 42),
(2, 'Option B', 6),
(3, 'Option C', 12);
Request :
SELECT products.*,
GROUP_CONCAT(options.name, " (+$", options.value, ")" SEPARATOR "<br>")
FROM products
INNER JOIN products_options
ON products.id = products_options.id_product
INNER JOIN options
ON products_options.id_option = options.id
GROUP BY products.id
With your Structure, I think this one will work :
SELECT tbl_product.*,
GROUP_CONCAT(tb_opciones.nombre, " (+$", tb_opciones.precio, ")" SEPARATOR "<br>")
FROM tbl_product
INNER JOIN tb_opciones_productos
ON tbl_product.id = tb_opciones_productos.producto
INNER JOIN tb_opciones
ON tb_opciones_productos.opcion = tb_opciones.id
GROUP BY tbl_product.id
I have 3 tables, but data is only fetch from 2 tables.
I'm trying to get the lowest bids for selected items and display user name with the lowest bid.
Currently query works until when we display user name, it shows wrong user name, which does not match the bid.
Below is working example of structure and query.
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE `bid` (
`id` int(11) NOT NULL,
`amount` float NOT NULL,
`user_id` int(11) NOT NULL,
`item_id` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1;
INSERT INTO `bid` (`id`, `amount`, `user_id`, `item_id`) VALUES
(1, 9, 1, 1),
(2, 5, 2, 1),
(3, 4, 3, 1),
(4, 3, 4, 1),
(5, 4, 2, 2),
(6, 22, 5, 1);
-- --------------------------------------------------------
CREATE TABLE `item` (
`id` int(11) NOT NULL,
`name` varchar(100) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
INSERT INTO `item` (`id`, `name`) VALUES
(1, 'chair'),
(2, 'sofa'),
(3, 'table'),
(4, 'box');
-- --------------------------------------------------------
CREATE TABLE `user` (
`id` int(11) NOT NULL,
`name` varchar(100) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
INSERT INTO `user` (`id`, `name`) VALUES
(1, 'James'),
(2, 'Don'),
(3, 'Hipes'),
(4, 'Sam'),
(5, 'Zakam');
ALTER TABLE `bid`
ADD PRIMARY KEY (`id`);
ALTER TABLE `item`
ADD PRIMARY KEY (`id`);
ALTER TABLE `user`
ADD PRIMARY KEY (`id`);
ALTER TABLE `bid`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=7;
ALTER TABLE `item`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=5;
ALTER TABLE `user`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=5;
Query 1:
SELECT b.id, b.item_id, MIN(b.amount) as amount, b.user_id, p.name
FROM bid b
LEFT JOIN user p ON p.id = b.user_id
WHERE b.item_id in (1, 2)
GROUP BY b.item_id
ORDER BY b.amount, b.item_id
Results:
| id | item_id | amount | user_id | name |
|----|---------|--------|---------|-------|
| 5 | 2 | 4 | 2 | Don |
| 1 | 1 | 3 | 1 | James |
Explanation of query:
Get the selected items (1, 2).
get the lowest bid for thous items - MIN(b.amount)
display user names, who has given the bid - LEFT JOIN user p on p.id = b.user_id (this is not working or I'm doing something wrong)
[Note] I can't use sub-query, I'm doing this in doctrine2 (php code) which limits mysql sub-query
No, you are not necessarily fetching the user_id who has given the bid. You group by item_id, so you get one result row per item. So you are aggregating and for every column you say what value you want to see for that item. E.g.:
MIN(b.amount) - the minimum amount of the item's records
MAX(b.amount) - the maximum amount of the item's records
AVG(b.amount) - the avarage amount of the item's records
b.amount - one of the amounts of the item's records arbitrarily chosen (as there are many amounts and you don't specify which you want to see, the DBMS simply choses one of them)
This said, b.user_id isn't necessarily the user who made the lowest bid, but just one random user of the users who made a bid.
Instead find the minimum bids and join again with your bid table to access the realted records:
select bid.id, bid.item_id, bid.amount, user.id as user_id, user.name
from bid
join
(
select item_id, min(amount) as amount
from bid
group by item_id
) as min_bid on min_bid.item_id = bid.item_id and min_bid.amount = bid.amount
join user on user.id = bid.user_id
order by bid.amount, bid.item_id;
You can solve this using a subquery. I am not 100% sure if this is the most efficient way, but at least it works.
SELECT b1.id, b1.item_id, b1.amount, b1.user_id, p.name
FROM bid b1
LEFT JOIN user p ON p.id = b1.user_id
WHERE b1.id = (
SELECT b2.id
FROM bid b2
WHERE b2.item_id IN (1, 2)
ORDER BY b2.amount LIMIT 1
)
This first selects for the lowest bid with for item 1 or 2 and then uses the id of that bid to find the information you need.
Edit
You are saying that Doctrine does not support subqueries. I have not used Doctrine a lot, but something like this should work:
$subQueryBuilder = $entityManager->createQueryBuilder();
$subQuery = $subQueryBuilder
->select('b2.id')
->from('bid', 'b2')
->where('b2.item_id IN (:items)')
->orderBy('b2.amount')
->setMaxResults(1)
->getDql();
$queryBuilder = $entityManager->createQueryBuilder();
$query = $queryBuilder
->select('b1.id', 'b1.item_id', 'b1.amount', 'b1.user_id', 'p.name')
->from('bid', 'b1')
->leftJoin('user', 'p', 'with', 'p.id = b1.user_id')
->where('b1.id = (' . $subQuery . ')')
->setParameter('items', [1, 2])
->getQuery()->getSingleResult();
I have two tables: categories and items. i have stored categories using nested set structure. Categories have items. Items can be only added to leaf nodes of a root category.
For eg:
Categories
Vehicles
Bikes
Bajaj
Automobiles
Art & Antiques
Amateur Art
Items can be added to category Bajaj, Automobiles and Amateur Art in this case.
Lets say there are 2 items inside Bajaj, 5 items inside Automobiles, 2 inside Amateur Art
For root level categories I want to display as follow:
- Vehicles (7 items)
- Art & Antiques (2 items)
How can I do this ?
Here is the sql dump to work with some sample data
--
-- Table structure for table `categories`
--
CREATE TABLE IF NOT EXISTS `categories` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`parent_id` int(11) DEFAULT NULL,
`title` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`lft` int(11) NOT NULL,
`lvl` int(11) NOT NULL,
`rgt` int(11) NOT NULL,
`root` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `IDX_3AF34668727ACA70` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=28 ;
--
-- Dumping data for table `categories`
--
INSERT INTO `categories` (`id`, `parent_id`, `title`, `lft`, `lvl`, `rgt`, `root`) VALUES
(22, NULL, 'Vehicles', 1, 0, 8, 22),
(23, 22, 'Bikes', 2, 1, 5, 22),
(24, 23, 'Bajaj', 3, 2, 4, 22),
(25, 22, 'Automobiles', 6, 1, 7, 22),
(26, NULL, 'Art & Antiques', 1, 0, 4, 26),
(27, 26, 'Amateur Art', 2, 1, 3, 26);
-- --------------------------------------------------------
--
-- Table structure for table `items`
--
CREATE TABLE IF NOT EXISTS `items` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`category_id` int(11) NOT NULL,
`title` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
KEY `FK_403EA91BA33E2D84` (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
--
-- Dumping data for table `items`
--
INSERT INTO `items` (`id`, `category_id`, `title`) VALUES
(1, 24, 'Pulsor 150 cc'),
(2, 24, 'Discover 125 cc'),
(3, 27, 'Art of dream'),
(4, 25, 'Toyota Car');
--
-- Constraints for dumped tables
--
--
-- Constraints for table `categories`
--
ALTER TABLE `categories`
ADD CONSTRAINT `FK_3AF34668727ACA70` FOREIGN KEY (`parent_id`) REFERENCES `categories` (`id`) ON DELETE SET NULL;
--
-- Constraints for table `items`
--
ALTER TABLE `items`
ADD CONSTRAINT `FK_403EA91BA33E2D84` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE;
root nodes have NULL in the field of parent_id
Update:
I was able to fetch for roots using this query:
SELECT c.id,c.title,cte.co FROM categories c
JOIN
(SELECT
c0_.id,c0_.root,COUNT(i.id) co
FROM
categories c0_
JOIN items i ON c0_.id=i.category_id
WHERE c0_.rgt = 1 + c0_.lft
GROUP BY c0_.id
) cte
ON cte.root=c.id
WHERE c.parent_id is null
The above query works for root level category. Now when the user clicks on root level category, I want to do the same.
for eg when somebody clicks on vehicles I should get:
Bikes (2)
Automobiles (5)
For that I tried :
SELECT c.id,c.title,cte.co FROM categories c
JOIN
(SELECT
c0_.id,c0_.root,COUNT(i.id) co
FROM
categories c0_
JOIN items i ON c0_.id=i.category_id
WHERE
c0_.rgt = 1 + c0_.lft
GROUP BY c0_.id
) cte
ON cte.root=c.id
WHERE c.parent_id=1
This returned empty result set. what is wrong in this query ?
SELECT parent.title,
( SELECT count(i.id) count FROM items i
WHERE category_id IN
(
SELECT child.id FROM categories child WHERE child.lft>=parent.lft AND
child.rgt<=parent.rgt AND child.root=parent.root
)
)
FROM categories parent
WHERE parent.parent_id=#parent_id;
Please inform me if this does not work
How about something like this:
SELECT COUNT(items.id),
(SELECT lookup.title
FROM categories lookup
WHERE lookup.id = categories.root)
FROM items, categories
WHERE categories.id = items.category_id
GROUP BY categories.root;
based on the input from the script above gives me:
3 | Vehicles
1 | Art & Antiques
to select for a particular root add
AND categories.root = #id
where #id is your root id you're looking for.
Alternatively if you want to select by the root name do something (scary) like this:
SELECT title, total
FROM
(SELECT COUNT(items.id) total,
(SELECT lookup.title
FROM categories lookup
WHERE lookup.id = categories.root) title
FROM items, categories
WHERE categories.id = items.category_id
GROUP BY categories.root;
) AS some_table
WHERE some_table.title = #root_name
where #root_name is the name of your root node (in quotes of course)
Something like this should work.
select c1.title, count(*) itemcount
from categories c1 join categories c2
on c2.parent_id = c1.id
join items on items.category_id = c2.id
group by c1.title
I have three tables:
"products" - contains products
"location" - store location
"product_orders" - joins data from products and location
SQL DUMP:
--
-- Table structure for table `location`
--
CREATE TABLE IF NOT EXISTS `location` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=77 ;
--
-- Dumping data for table `location`
--
INSERT INTO `location` (`id`, `name`) VALUES
(1, 'Miami'),
(2, 'Denver');
-- --------------------------------------------------------
--
-- Table structure for table `products`
--
CREATE TABLE IF NOT EXISTS `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(255) NOT NULL DEFAULT '',
`product` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=6014552 ;
--
-- Dumping data for table `products`
--
INSERT INTO `products` (`id`, `type`, `product`) VALUES
(1, 'shirt', 'red shirt'),
(2, 'shirt', 'red shirt'),
(3, 'pants', 'blue pants'),
(4, 'pants', 'blue pants');
-- --------------------------------------------------------
--
-- Table structure for table `product_orders`
--
CREATE TABLE IF NOT EXISTS `product_orders` (
`product_id` int(11) NOT NULL,
`location_id` int(11) NOT NULL,
`status` varchar(255) NOT NULL,
PRIMARY KEY (`product_id`,`location_id`),
KEY `ix_product_orders` (`location_id`),
KEY `ix_product_orders_1` (`product_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
--
-- Dumping data for table `product_orders`
--
INSERT INTO `product_orders` (`product_id`, `location_id`, `status`) VALUES
(1, 1, 'sold'),
(2, 2, 'sold'),
(1, 2, 'available'),
(2, 1, 'sold');
If I want to select all sold products from store 'miami - this query works:
SELECT * FROM `products`
INNER JOIN `product_orders`
ON `product_orders`.`product_id`= `products`.`id`
WHERE `product_orders`.`location_id` = '1'
AND
status = 'sold'
How would you rewrite to delete all sold products from the miami store? My query is not working:
DELETE `products` FROM `products`
INNER JOIN `product_orders`
ON `product_orders`.`location_id` = `products`.`id`
WHERE `product_orders`.`location_id` = '2'
AND
status = 'sold'
DELETE FROM products WHERE id IN (SELECT location_id FROM products_orders WHERE location = 'miami' AND status = 'sold');
Try this one,
DELETE `products` FROM `products` INNER JOIN `products_orders`
ON `products_orders`.`location_id` = `products`.`id`
WHERE `products_orders`.`location` = 'miami'
AND
status = 'sold'
OR
DELETE prod FROM `products` AS prod INNER JOIN `products_orders`
ON `products_orders`.`location_id` = `products`.`id`
WHERE `products_orders`.`location` = 'miami'
AND
status = 'sold'
I am not sure how you have set foreign keys in your tables. But looking at it with the most primary assumptions, product table holds products data and location holds location data. In your common table product orders you are having one foreign key to products table by product id and one another relation to location table by location.
So to back my comment, I am posting the following query. It is your query with a change to a field that I ASSUME WAS A TYPO....in your query. :-) Again as foampile said, I might be doing it with consistency...
DELETE FROM `products`
INNER JOIN `products_orders`
ON `products_orders`.`product_id` = `products`.`id`
WHERE `products_orders`.`location` = 'miami'
AND `products_orders`.status = 'sold'
;
I have the following sample database set up -
CREATE TABLE IF NOT EXISTS `companies`(
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`company` varchar(75) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
INSERT INTO `companies` (`id`, `company`) VALUES
(1, 'Acme Widget Company'),
(2, 'Intrepid Inc.'),
(3, 'Allied Corp.');
CREATE TABLE IF NOT EXISTS `companies_customers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`company_id` int(11) NOT NULL,
`customer_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
INSERT INTO `companies_customers` (`id`, `company_id`, `customer_id`) VALUES
(1, 2, 1),
(2, 2, 2),
(3, 2, 4),
(4, 1, 3),
(5, 1, 1);
CREATE TABLE IF NOT EXISTS `customers` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`firstname` varchar(25) NOT NULL,
`lastname` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
INSERT INTO `customers` (`id`, `firstname`, `lastname`) VALUES
(1, 'John', 'Smith'),
(2, 'Sue', 'Jones'),
(3, 'David', 'Flanders'),
(4, 'Kathy', 'Freeman');
CREATE TABLE IF NOT EXISTS `orders` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`customer_id` int(11) NOT NULL,
`amount` decimal(10,0) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
INSERT INTO `orders` (`id`, `customer_id`, `amount`) VALUES
(1, 1, 500),
(2, 3, 1000),
(3, 1, 250),
(4, 4, 800),
(5, 4, 100);
I need to write a query which retrieves a list of all company names, a count of the number of customers in each company, and a sum of the customers orders in each company, like this -
Company Total Customers All Orders Total
Acme Widget Company 2 750
Intrepid Inc. 3 1650
Allied Corp. 0 0
I nearly have it resolved with the following SQL -
SELECT company AS 'Company', customersCount AS 'Total Customers', customerOrdersTotal AS 'All Orders Total'
FROM
( SELECT cc.customer_id, SUM(innerQuery.ordersTotal) customerOrdersTotal
FROM (SELECT cu.id customerId, SUM(amount) ordersTotal
FROM customers cu
JOIN orders o ON o.customer_id = cu.id
GROUP BY customerId
) innerQuery
JOIN companies_customers cc ON innerQuery.customerId = cc.customer_id
GROUP BY cc.customer_id
) inner_1
RIGHT JOIN
( SELECT cc.id, c.company, COUNT(*) customersCount
FROM companies c
JOIN companies_customers cc ON c.id = cc.company_id
GROUP BY c.id
) inner_2
ON inner_1.customer_id = inner_2.id
It does not print out the company (Allied) without a customer or total. So close, I just need a nudge in the right direction. Thanks.
Since the orders are linked to the companies via the customers, I don't think you need to perform two separate subqueries and join them; rather, I think you can just write:
SELECT companies.company AS "Company",
IFNULL(COUNT(DISTINCT companies_customers.customer_id), 0) AS "Total Customers",
IFNULL(SUM(orders.amount), 0) AS "All Orders Total"
FROM companies
LEFT
JOIN companies_customers
ON companies_customers.company_id = companies.id
LEFT
JOIN orders
ON orders.customer_id = companies_customers.customer_id
GROUP
BY companies.id
;
Edited to add: That said, I have to say that the schema doesn't really make sense to me. You have a many-to-many relationship between customers and companies — so, for example, John Smith is a customer of Acme Widget Company and of Intrepid Inc. — but then orders are just a property of the customer, not of the company. This means that if an order belongs to John Smith, then it necessarily belongs both to Acme Widget Company and to Intrepid Inc.. I don't think that can be right. Instead of having a customer_id field, I think orders needs to have a companies_customers_id field.
I have 3 table that to keep team,tournament_round AND score_team_member about competition TEAM_A Vs TEAM_B ,multiple of round.(1,2,3...n) and multiple of members of team there is score by oneself.This code above are useful very much.
SELECT team.name AS "TEAM",team.id,
IFNULL(COUNT(DISTINCT `tournament_round`.id), 0) AS "TotalWin",
IFNULL(SUM(`score_team_member`.`score`)/(select count(*) from `team_member`where team_id=team.id group by team_id ), 0) AS "ScoreofTeam"
FROM `team`
LEFT
JOIN `tournament_round`
ON `tournament_round`.team_winner_id = `team`.id
LEFT
JOIN `score_team_member`
ON `score_team_member`.team_id = `team`.id
WHERE `team`.thematch_id='6' AND `team`.`category1`='MEP'
GROUP BY `team`.id ORDER by `TotalWin`DESC ,`ScoreofTeam` DESC
Sample out put click here JPG
Table Designer JPG