Thanks to this post, I was able to calculate the median for a corresponding vendor in the invoices table.
This was the query used:
SELECT AVG(middle_values) AS 'median'
FROM (
SELECT t1.invoice_total AS 'middle_values'
FROM
(
SELECT #row:=#row+1 as `row`, iv.invoice_total
FROM invoices AS iv, (SELECT #row:=0) AS r
WHERE iv.vendor_id = 97
ORDER BY iv.invoice_total
) AS t1,
(
SELECT COUNT(*) as 'count'
FROM invoices iv
WHERE iv.vendor_id = 97
) AS t2
-- the following condition will return 1 record for odd number sets, or 2 records for even number sets.
WHERE t1.row >= t2.count/2 and t1.row <= ((t2.count/2) +1)) AS t3;
Instead of this just outputting one column in the resultbox, I'd like it to display two columns: vendor_id, median_invoice.
CREATE TABLE IF NOT EXISTS `invoices` (
`invoice_id` int(11) NOT NULL AUTO_INCREMENT,
`vendor_id` int(11) NOT NULL,
`invoice_number` varchar(50) NOT NULL,
`invoice_date` date NOT NULL,
`invoice_total` decimal(9,2) NOT NULL,
`payment_total` decimal(9,2) NOT NULL DEFAULT '0.00',
`credit_total` decimal(9,2) NOT NULL DEFAULT '0.00',
`terms_id` int(11) NOT NULL,
`invoice_due_date` date NOT NULL,
`payment_date` date DEFAULT NULL,
PRIMARY KEY (`invoice_id`),
KEY `invoices_fk_vendors` (`vendor_id`),
KEY `invoices_fk_terms` (`terms_id`),
KEY `invoices_invoice_date_ix` (`invoice_date`),
CONSTRAINT `invoices_fk_terms` FOREIGN KEY (`terms_id`) REFERENCES `terms` (`terms_id`),
CONSTRAINT `invoices_fk_vendors` FOREIGN KEY (`vendor_id`) REFERENCES `vendors` (`vendor_id`)
) ENGINE=InnoDB AUTO_INCREMENT=119 DEFAULT CHARSET=latin1;
Insert statements:
INSERT INTO `invoices` VALUES (118, 97, '456792', '2011-08-03', 565.60, 0.00, 0.00, 2, '2011-09-02', NULL);
INSERT INTO `invoices` VALUES (117, 97, '456791', '2011-08-03', 4390.00, 0.00, 0.00, 2, '2011-09-02', NULL);
INSERT INTO `invoices` VALUES (116, 97, '456701', '2011-08-02', 270.50, 0.00, 0.00, 2, '2011-09-01', NULL);
INSERT INTO `invoices` VALUES (115, 97, '456789', '2011-08-01', 8344.50, 0.00, 0.00, 2, '2011-08-31', NULL);
INSERT INTO `invoices` VALUES (114, 123, '963253249', '2011-08-02', 127.75, 127.75, 0.00, 3, '2011-09-01', '2011-09-04');
INSERT INTO `invoices` VALUES (113, 37, '547480102', '2011-08-01', 224.00, 0.00, 0.00, 3, '2011-08-31', NULL);
INSERT INTO `invoices` VALUES (112, 110, '0-2436', '2011-07-31', 10976.06, 0.00, 0.00, 3, '2011-08-30', NULL);
INSERT INTO `invoices` VALUES (111, 123, '263253257', '2011-07-30', 22.57, 22.57, 0.00, 3, '2011-08-29', '2011-09-03');
Doing the following was no good:
SELECT t1.vendor_id, AVG(middle_values) AS 'median'
FROM (
SELECT vendor_id, t1.invoice_total AS 'middle_values'
FROM
(
SELECT #row:=#row+1 as `row`, iv.invoice_total
FROM invoices AS iv, (SELECT #row:=0) AS r
WHERE iv.vendor_id = 97
ORDER BY iv.invoice_total
) AS t1,
(
SELECT COUNT(*) as 'count'
FROM invoices iv
WHERE iv.vendor_id = 97
) AS t2, invoices
-- the following condition will return 1 record for odd number sets, or 2 records for even number sets.
WHERE t1.row >= t2.count/2 and t1.row <= ((t2.count/2) +1)) AS t3;
In order to use vendor_id in the parent query you need to return it (select it) in each nested subquery:
SELECT t3.vendor_id, AVG(middle_values) AS 'median'
FROM (
SELECT t1.invoice_total AS 'middle_values', t1.vendor_id
FROM
(
SELECT #row:=#row+1 as `row`, iv.invoice_total, iv.vendor_id
FROM invoices AS iv, (SELECT #row:=0) AS r
WHERE iv.vendor_id = 97
ORDER BY iv.invoice_total
) AS t1,
(
SELECT COUNT(*) as 'count'
FROM invoices iv
WHERE iv.vendor_id = 97
) AS t2
-- the following condition will return 1 record for odd number sets, or 2 records for even number sets.
WHERE t1.row >= t2.count/2 and t1.row <= ((t2.count/2) +1)) AS t3
Related
It's about get sum product's quantity and name from joined orders grouped by date
I have two tables:
CREATE TABLE IF NOT EXISTS `orderproduct` (
`id` int(5) UNSIGNED NOT NULL AUTO_INCREMENT,
`quantity` int(3) NOT NULL,
`name` varchar(100) NOT NULL,
`fk_orders_id` int(3) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
INSERT INTO `orderproduct` (`id`, `quantity`, `name`, `fk_orders_id`) VALUES
(1, 3, 'Boulgour de bléss', 1),
(2, 2, 'Casarecce d\'épeautre', 1),
(3, 1, 'Cerneaux de noix', 1),
(5, 2, 'Boulgour de bléss', 3),
(6, 2, 'Casarecce d\'épeautre', 3),
(7, 4, 'Casarecce d\'épeautre', 4),
(8, 4, 'Cerneaux de noix', 4);
INSERT INTO `orders` (`id`, `date`) VALUES
(1, '2020-06-29 17:02:11'),
(3, '2020-06-29 10:56:47'),
(4, '2020-06-30 11:20:24');
DROP TABLE IF EXISTS `orders`;
CREATE TABLE IF NOT EXISTS `orders` (
`id` int(3) NOT NULL AUTO_INCREMENT,
`date` timestamp NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
the exemple with the order grouped by date and make a sum from his same product quantity:
order 29/6
productsA quantity=1
productsB quantity=2
productsC quantity=3
order 29/6
productsA quantity=4
order 30/6
productsA quantity=1
productsB quantity=2
My knowledge of mysql is to basic here wath i have tried for the moment:
SELECT o.date, p.name, sum(p.quantity)
FROM `orders` o , `orderproduct` p
WHERE p.fk_orders_id = o.id
GROUP BY p.name
The sum of quantities are grouped by product but dont know how take care of grouping by orders date.
I tried also some sub query
(i know this not working because sub Q; return more than 1 row and shoul be used witn 'IN' but it is just for illustrate the idéé):
select o.date,p.name, (
SELECT sum(p.quantity)
FROM `orderproduct` p
GROUP BY p.name
)
FROM `orders` o , `orderproduct` p
WHERE p.fk_orders_id = o.id
Desired result could be:
order.date productname product.sumQuantity (name field)
2020-06-29 'Boulgour de bléss' 5, 'Casarecce d'épeautre' 4, 'Cerneaux de noix' 1
2020-06-30 'Casarecce d'épeautre' 4, 'Cerneaux de noix' 4,
thanks to #MdRanaHossain for the solution
SELECT date(o.date) date, p.name, sum(p.quantity)
from orderproduct p, orders o
where o.id = p.fk_orders_id
GROUP by date(o.date), p.name
CREATE TABLE `reviews` (
`id` int(11) NOT NULL,
`average` decimal(11,2) NOT NULL,
`house_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `reviews` (`id`, `average`, `house_id`) VALUES
(1, '10.00', 1),
(2, '10.00', 1);
ALTER TABLE `reviews`
ADD PRIMARY KEY (`id`);
ALTER TABLE `reviews`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
CREATE TABLE `dummy_reviews` (
`id` int(11) NOT NULL,
`average` decimal(11,2) NOT NULL,
`house_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `dummy_reviews` (`id`, `average`, `house_id`) VALUES
(0, '2.00', 1);
ALTER TABLE `dummy_reviews`
ADD PRIMARY KEY (`id`);
AND the query
SELECT
AVG(r.average) AS avg1,
AVG(dr.average) AS avg2
FROM
reviews r
LEFT JOIN
dummy_reviews dr ON r.house_id = dr.house_id
the result is
avg1 avg2
10.000000 2.000000
All good by now but (10 + 2) / 2 = 6 ... wrong result
I need (10+10+2) / 3 = 7,33 ... How can I get this result?
SQLFiddle
You have values joined and as such you wont have 3 rows, you will have 2. What you need is a union so you can have all rows from your average tables and do the calculation from it. Like this:
select avg(average) from
(select average from reviews
union all
select average from dummy_reviews
) queries
See it here: http://sqlfiddle.com/#!9/e0b75f/3
Jorge's answer is the simplest approach (and I duly upvoted it). In response to your comment, you can do the following:
select ( (coalesce(r.suma, 0) + coalesce(d.suma, 0)) /
(coalesce(r.cnt, 0) + coalesce(d.cnt, 0))
) as overall_average
from (select sum(average) as suma, count(*) as cnt
from reviews
) r cross join
(select sum(average) as suma, count(*) as cnt
from dummy_reviews
) d;
Actually, I suggest this not only because of your comment. Under some circumstances, this could be the better performing code.
Basically i have two tables:
Here's code to create two tables if this can help someone who will be willing to help me:
CREATE TABLE IF NOT EXISTS `coefficients` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`datetime` datetime NOT NULL,
`campaign_id` int(11) NOT NULL,
`score` decimal(10,2) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
INSERT INTO `coefficients` (`id`, `datetime`, `campaign_id`, `score`) VALUES
(1, '2017-01-29 22:32:13', 1, 20.00),
(2, '2017-01-29 22:36:22', 1, 34.00),
(3, '2017-01-29 22:36:30', 1, 30.00),
(4, '2017-01-29 22:36:43', 1, 1000.00),
(5, '2017-01-29 22:37:13', 2, 10.00),
(6, '2017-01-29 22:37:26', 2, 15.00),
(7, '2017-01-29 22:37:43', 2, 20.00),
(8, '2017-01-29 22:30:51', 2, 1000.00);
CREATE TABLE IF NOT EXISTS `statistics` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`campaign_id` int(11) NOT NULL,
`stats1` int(11) NOT NULL,
`stats2` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO `statistics` (`id`, `campaign_id`, `stats1`, `stats2`) VALUES
(1, 1, 34, 38),
(2, 2, 23, 45);
I would like to get average coefficient for each campaign_id calculated based on latest 3 logged coefficients for each campaign_id.
Here's screenshot of two tables and result that i need to get:
data + result (visual representation)
The main problem is that i have no idea how to join these two tables if i need only average coefficient for each campaign_id based on 3 latest logged nu,bers for it :(
I will appreciate any help
Following query will give you the top 3 records per campaign_id from coefficients table:
SET #currcount = NULL, #currvalue = NULL;
SELECT id, campaign_id, score, c_index FROM (
SELECT
id, campaign_id, score,
#currcount := IF(#currvalue = campaign_id, #currcount + 1, 1) AS c_index,
#currvalue := campaign_id AS s
FROM coefficients
order by id
) AS a where c_index <= 3
Now, all you have to do is, add a GROUP BY to this query, calculate average score and join it with statistics table, e.g.:
SET #currcount = NULL, #currvalue = NULL;
SELECT a.id, a.campaign_id, avg(score), c_index, s.stats1, s.stats2 FROM (
SELECT
id, campaign_id, score,
#currcount := IF(#currvalue = campaign_id, #currcount + 1, 1) AS c_index,
#currvalue := campaign_id AS s
FROM coefficients
order by id
) AS a join statistics s on a.campaign_id = s.campaign_id
where c_index <= 3
group by campaign_id
Here's the SQL Fiddle.
In MySQL, the best way is usually to use variables. Getting the statistics is just a join, so that is not interesting. Let's get the average from the coefficients table:
select c.campaign_id, avg(c.score) as avg_score
from (select c.*,
(#rn := if(#c = c.campaign_id, #rn + 1,
if(#c := c.campaign_id, 1, 1)
)
) as rn
from coefficients c cross join
(select #rn := 0, #c := -1) params
order by c.campaign_id, c.datetime desc
) c
where rn <= 3
group by c.campaign_id;
I have two tables t1 and t2, and would like to get as output t1 with an added column giving the count of rows in t2 where (id, category) are present.
Here is an example on a small data set:
CREATE TABLE IF NOT EXISTS `t1` (
`key` int(11) NOT NULL,
`id` int(11) NOT NULL,
`category` int(11) NOT NULL,
PRIMARY KEY (`key`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `t1` (`key`, `id`, `category`) VALUES
(1, 12, 101),
(2, 12, 104),
(3, 13, 102),
(4, 14, 101),
(5, 15, 102);
CREATE TABLE IF NOT EXISTS `t2` (
`key` int(11) NOT NULL,
`id` int(11) NOT NULL,
`category` int(11) NOT NULL,
PRIMARY KEY (`key`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `t2` (`key`, `id`, `category`) VALUES
(1, 12, 101),
(2, 12, 102),
(3, 13, 101),
(4, 13, 104),
(5, 12, 101),
(6, 15, 102);
Here is the output I wish to have, the last column being the desired infos:
t1 updated
key, id, category, count_t2_id_category
1, 12, 101, 2 # because (12,101) appears 2 times in t2
2, 12, 104, 0 # because (12,104) appears 0 times in t2
3, 13, 102, 0 # etc
4, 14, 101, 0
5, 15, 102, 1
I tried the following command to start with, but it misses some t1 rows in the output:
SELECT *
FROM t1
LEFT OUTER JOIN t2 ON t1.id=t2.id AND t1.category = t2.category
GROUP BY t1.id
output missing t1 key #2:
key id category key id category
1 12 101 1 12 101
3 13 102 NULL NULL NULL
4 14 101 NULL NULL NULL
5 15 102 6 15 102
Since you want zero values for your non-matched rows, it's a work for LEFT JOIN, like:
SELECT
t1.*,
IF(t2.`key` IS NULL, 0, COUNT(t1.`key`)) AS t2_row_count
FROM
t1
LEFT JOIN t2
ON t1.id=t2.id
AND
t1.category=t2.category
GROUP BY
t1.`key`
We're counting t1.key because for matched rows they will be same in first table (and not second) - thus, we should group by it - and not by field in second table.
Tip: avoid to name your tables/columns with mysql reserved words. This will save you lots of time if you'll accidentally forget backticks.
First of all please change your column name key to recid coz key is a reserved word of mysql
SELECT t1.recid, t1.id, t1.category, count(t2.category) as count FROM t1 LEFT JOIN t2 ON t1.id=t2.id AND t1.category = t2.category GROUP BY t1.id,t1.category
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