MYSQL: Union operator to add a 'total' row - mysql

I have created the below SQL query to calculate the total income from leases within the next 12 months .
SELECT DISTINCT apartment.addressLine1, lease.monthlyRent, lease.duration, lease.roomNumber, lease.monthlyRent*lease.duration AS totalLeaseRent
FROM `lease`
INNER JOIN apartment on (lease.roomNumber) = (apartment.roomNumber)
left Join tenantLease on tenantLease.leaseID = lease.leaseID
WHERE tenantLease.live = 1 AND lease.duration <= 12
This returns the following result:
AddressLine1 monthlyRent Duration(months) roomNumber totalLeaseRent
Chlorine Gardens1200 9 GF02 10800
May Road 800 12 GF03 9600
Beech Hill 900 8 BG06 7200
Ash Avenue 1000 12 AA04 12000
I now want to be able to have another row to include the total of the totalLeaseRent. Like this:
AddressLine1 monthlyRent Duration(months) roomNumber totalLeaseRent
Chlorine Garden1200 9 GF02 10800
May Road 800 12 GF03 9600
Beech Hill 900 8 BG06 7200
Ash Avenue 1000 12 AA04 12000
TOTAL *total*
I have tried the following code but keep getting the error code:
1222 - The used SELECT statements have a different number of columns
SELECT DISTINCT apartment.addressLine1, lease.monthlyRent, lease.duration, lease.roomNumber, lease.monthlyRent*lease.duration AS totalLeaseRent
FROM `lease`
INNER JOIN apartment on (lease.roomNumber) = (apartment.roomNumber)
left Join tenantLease on tenantLease.leaseID = lease.leaseID
WHERE tenantLease.live = 1 AND lease.duration <= 12
UNION ALL
SELECT 'Total', SUM(lease.monthlyRent * lease.duration)
FROM lease
How do I get this query to run?
Thanks

TRY THIS: We have to follow following three points while working with set operation
1- Each SELECT statement within UNION must have the same number of columns
2- The columns must also have similar data types
3- The columns in each SELECT statement must also be in the same order
SELECT DISTINCT apartment.addressLine1,
lease.monthlyRent,
lease.duration,
lease.roomNumber,
lease.monthlyRent*lease.duration AS totalLeaseRent
FROM `lease`
INNER JOIN apartment on (lease.roomNumber) = (apartment.roomNumber)
left Join tenantLease on tenantLease.leaseID = lease.leaseID
WHERE tenantLease.live = 1 AND lease.duration <= 12
UNION ALL
SELECT 'Total', NULL, NULL, NULL, SUM(lease.monthlyRent * lease.duration)
FROM lease

Related

SQL Sum Calculation Confusion

I am new with mysql and working to change a store application to make it have two stock. I created a table to store stock quantity:
Then I plan to create a view with stock quantity, per store, per SKU. I using the following query:
SELECT
`stockList`.`sku`,
SUM(A.`stockQty`) AS 'store1',
SUM(B.`stockQty`) AS 'store2',
SUM(`stockList`.`stockQty`) AS 'total'
FROM `stockList`
LEFT JOIN (
SELECT * FROM `stockList` WHERE `idStock`=1
) AS A
ON `stockList`.`sku`=A.`sku`
LEFT JOIN (
SELECT * FROM `stockList` WHERE `idStock`=2
) AS B
ON `stockList`.`sku`=B.`sku`
GROUP BY `stockList`.`sku`
Per resulting table, calculation is not proper and I could not identify the logic:
SKU 43 should show for store1 = 9 and for store2 = 10, total = 19. This is what they show if I execute the select queries alone. Please, let me know if I misunderstood how this sum logic works.
You might to use SUM on subquery to calculate Totle price by sku
LEFT JOIN may make some fields not match causing NULL so use IFNULL to preset value 0
You can try this.
SELECT
T.sku,
SUM(T.stockQty) as totle,
IFNULL(A.`store1`,0) AS `store1`,
IFNULL(B.`store2`,0) AS `store2`
FROM `stockList` AS T
LEFT JOIN
(
SELECT sku,SUM(`stockQty`) as `store1`
FROM `stockList`
WHERE `idStock`=1
GROUP BY sku
) as A ON A.sku = T.sku
LEFT JOIN
(
SELECT sku,SUM(`stockQty`) as `store2`
FROM `stockList`
WHERE `idStock`=2
GROUP BY sku
) AS B ON T.sku =B.sku
GROUP BY T.sku
sqlfiddle
Your query is much more complicated than it needs to be. You can just do this:
SELECT
sku,
SUM(stockQty) as total,
SUM(IF(idStock=1,stockQty,0)) AS `store1`,
SUM(IF(idStock=2,stockQty,0)) AS `store2`
FROM `stockList`
GROUP BY sku
Output:
sku total store1 store2
36 10 10 0
37 3 3 0
38 4 4 0
39 3 3 0
40 10 10 0
41 12 12 0
42 12 12 0
43 19 9 10

latest rate and sum of quantity from mysql table

I have a table look like below:
uid added_on rm_id qnty rate
1 2017-10-23 10:48:50 5 2 30
2 2017-10-23 10:48:50 6 4 70
3 2017-10-23 10:48:50 7 5 10
4 2017-10-24 11:02:10 5 10 28
5 2017-10-24 11:02:10 6 2 75
6 2017-10-24 11:03:37 7 1 15
7 2017-10-25 11:02:10 6 5 65
8 2017-10-25 11:03:37 7 8 12
I need the rm_id , its quantity (that is rm_id 5 is 12(2+10) ), and its last added rate(latest rate can find from the latest added_on rate or from last uid for each rm_id). Any way the result should look like below:
Result
rm_id total_qnty rate
5 12 28
6 11 65
7 14 12
I tried to achieve this by using
SELECT `rm_id`, sum(`qnty`),`rate` FROM `stock` group by `rm_id` having max(`uid`)
and
SELECT `rm_id`, sum(`qnty`),`rate` FROM `stock` group by `rm_id` having max(date(`added_on`))
But not getting the result as desired.. please help me..
You need to locate the max date, and from that determine the rate, and apply that rate to the summed quantity.
select
t.rm_id, t.rate, gd.sum_qty, gd.sum_qty * t.rate
from table1 t
inner join (
select rm_id, max(added_on) max_date, sum(qnty) sum_qty
from table1
group by rm_id
) gd on t.rm_id = gd.rm_id and t.added_on = gd.max_date
The data model is strange, why aren't rates separated?
having max(uid) translates to having 8 for rm_id = 7. And MySQL treats numbers > 0 as true, so this becomes having true, i.e. don't limit my results in any way. The aggregated result doesn't contain the single rates anyway, so it's too late to try to get it via HAVING. You'd need an aggregation function for this, such as Oracle's KEEP LAST, but MySQL doesn't feature this.
What you want instead is to get the maximum uid and with its help select the related record:
select
stock.rm_id,
stockagg.sum_qnty,
stock.rate as last_rate
from
(
select
rm_id,
sum(qnty) as sum_qnty,
max(uid) as max_uid
from stock
group by rm_id
) stockagg
join stock on stock.uid = stockagg.max_uid;
You can use subqueries:
SELECT `rm_id`, sum(`qnty`),
(SELECT `rate`
FROM `stock` s1
WHERE `uid` = (SELECT `uid`
FROM `stock` s2
WHERE s2.`rm_id` = s1.`rm_id`
ORDER BY `added_on` DESC
LIMIT 1)
) AS `rate`
FROM `stock`
GROUP BY `rm_id`

How to select one column with all distinct values based on some clause

I essentially like to have one query which I'll execute one time and like to have the result (no multiple query execution) and definitely, the query should use simple MySQL structure (no complex/advanced structure to be used like BEGIN, loop, cursor).
Say I've two tables.
1st Table = Country (id(PK), name);
2nd Table = Businessman (id(PK), name, city, country_id(FK))
Like to SELECT all countries, whose businessmen are from distinct cities. No two businessmen exist in one country, who are from the same city. If so, that country will not be selected by the SELECT clause.
Country
id name
1 India
2 China
3 Bahrain
4 Finland
5 Germany
6 France
Businessman
id name city country_id
1 BM1 Kolkata 1
2 BM2 Delhi 1
3 BM3 Mumbai 1
4 BM4 Beijing 2
5 BM5 Paris 6
6 BM6 Beijing 2
7 BM7 Forssa 4
8 BM8 Anqing 2
9 BM9 Berlin 5
10 BM10 Riffa 3
11 BM11 Nice 6
12 BM12 Helsinki 4
13 BM13 Bremen 5
14 BM14 Wiesbaden 5
15 BM15 Angers 6
16 BM16 Sitra  3
17 BM17 Adliya 3
18 BM18 Caen 6
19 BM19 Jinjiang 2
20 BM20 Tubli 3
21 BM21 Duisburg 5
22 BM22 Helsinki 4
23 BM23 Kaarina 4
24 BM24 Bonn 5
25 BM25 Kemi 4
In this respect, China and Finland shouldn't be listed.
I've attempted using count and group by, but no luck.
Can you please help me to build up this query.
Here it is, all you need is to join Businessman table and count cities and distinct cities and if they equal that means all businessmen are from different cities:
SELECT
c.`id`,
c.`name`,
COUNT(b.`id`) AS BusinessmanCount,
COUNT(b.`city`) AS CityCount,
COUNT(DISTINCT b.`city`) AS DistinctCityCount
FROM `countries` c
INNER JOIN Businessman b ON c.`id` = b.`country_id`
GROUP BY c.`id`
HAVING CityCount = DistinctCityCount
For minified version what you exactly need:
SELECT
c.`id`,
c.`name`
FROM `countries` c
INNER JOIN Businessman b ON c.`id` = b.`country_id`
GROUP BY c.`id`
HAVING COUNT(b.`city`) = COUNT(DISTINCT b.`city`)
Well, I think we should have waited for you to show your own query, because one learns best from mistakes and their explanations. However, now that you've got answers already:
Yes, you need group by and count. I'd group by cities to see if I got duplicates. Then select countries and exclude those that have duplicate cities.
select *
from country
where id not in
(
select country_id
from businessmen
group by city, country_id
having count(*) > 1
);
You need either nested aggregations:
select *
from Country
where id in
(
select country_id
from
(
select city, country_id,
count(*) as cnt -- get the number of rows per country/city
from Businessman
group by city, country_id
) as dt
group by country_id
having max(cnt) = 1 -- return only those countries where all counts are unique
)
Or compare two counts:
select *
from Country
where id in
(
select country_id
from Businessman
group by country_id
having count(*) = count(distinct city) -- number of cities is equal to umber of rows
)

Update table based on conditions from another table,that include functions

I have 2 mysql tables like in the example below:
CARS:
RaceID CarID Dis Grd Date Time
8 1 200 A 2010-10-10 20.50
8 2 300 A 2010-10-10 30.50
8 3 200 A 2010-10-10 20.10
9 1 200 A 2010-11-10 20.00
12 1 200 A 2011-12-11 19.50
RACES:
RaceId CarID Dis Grd Date Exp_Time
10 1 200 A 2011-11-11
10 2 200 A 2011-11-11
10 3 200 A 2011-11-11
I want to Add data on Races table at column Exp_Time based on data from CARS table.
For example:
RACES.Exp_Time=AVG(CARS.Time)
WHERE
CARS.CarID=RACES.CarID
CARS.Dis=RACES.Dis
CARS.Grd=RACES.Grd
CARS.Date<RACES.Date
The idea is that expected Time is AVG from previous races times on same distance and grd. Future races should be excluded from calculation AVG.
The problem is getting the date condition from RACES table.
I do this query:
UPDATE `RACES` c
INNER JOIN (
SELECT CARS.CarID, CARS.Dis, CARS.Grd, CARS.Date, AVG(Time) AS `Exp_Time`
FROM CARS
WHERE CARS.Date<'2011-11-11'
GROUP BY CarID, Dis, Grd
)
x ON c.CarID=x.CarID AND c.Dis=x.Dis AND c.Grd=x.Grd
SET c.Exp_Time=x.Exp_Time
And it works when I type myseld the date - 2011-11-11
I don't know how to get the data from RACES table.
Can somebody help?
Thanks in advance!
Ivan
UPDATE `RACES` c
INNER JOIN (
SELECT CARS.CarID, CARS.Dis, CARS.Grd, CARS.Date, AVG(Time) AS `Exp_Time`
FROM CARS
WHERE CARS.Date < (SELECT Date
FROM RACES
WHERE CARS.Date<RACES.Date
AND CARS.Grd=RACES.Grd
AND CARS.CarID=RACES.CarID
AND CARS.Dis=RACES.Dis
LIMIT 1
)
GROUP BY CarID, Dis, Grd
)
x ON c.CarID=x.CarID AND c.Dis=x.Dis AND c.Grd=x.Grd
SET c.Exp_Time=x.Exp_Time
2011-11-11 I don't know how to get the data from RACES table.
You can move this predicate to the JOIN condition like so:
UPDATE `RACES` c
INNER JOIN (
SELECT
CarID, Dis, Grd, Date, AVG(Time) AS `Exp_Time`
FROM CARS
GROUP BY CarID, Dis, Grd
)x ON c.CarID = x.CarID
AND c.Dis = x.Dis
AND c.Grd = x.Grd
AND x.DATE(`Date`) < c.DATE(`Date`)
SET c.Exp_Time = x.Exp_Time;

having trouble writing a query that list all salesmen that did not sell to a particular customer

I was successful in writing the query that lists salesmen that did sell to a particular customer, but not those that have not. I suspect it is because the same salesmen that sold to the specific customer, also sold to other customers.
select a.name from salesperson a inner join orders b on
a.salesperson_id = b.salesperson_id where cust_id="4";
I was thinking that modifying the same query like this would do the trick:
.... a.salesperson_id <> b.salesperson_id where cust_id="4";
But the result lists all the salesmen. This is most likely due to the fact that the same salesmen that were returned in the original query, also sold to other customers
The 3 tables look like this:
Salesperson table
salesperson_ID, Name, Age, Salary
1 Abe 61 140000
2 Bob 34 44000
5 Chris 34 40000
7 Dan 41 52000
8 Ken 57 115000
11 Joe 38 38000
Customer table
cust_ID, Name, City Industry Type
4 faralon sacramento H
6 Apple cupertino S
7 Honda NY B
9 Kolb Oshkosh B
Orders table
Number, Order_date, cust_id, salesperson_id, Amount
10 8/2/1996 4 2 540
20 1/30/1999 4 8 1800
30 7/14/1995 9 1 460
40 1/29/1998 7 2 2400
50 2/3/1998 6 7 600
60 3/2/1998 6 7 720
70 5/6/1998 9 7 150
Any help would be greatly appreciated. ~Alpinehyker
You can do something like this:
select a.name from salesperson a
left join orders b on a.salesperson_id = b.salesperson_id and b.cust_id="4"
where b.Number is null
So, get all salepersons, left join to orders for customer 4, and return only rows where there is no such order.
I am assuming that Number is the primary key for Orders, or at least not null.
All salespeople who have NOT sold to customer_ID 4:
SELECT s.Name FROM Salesperson AS s
LEFT JOIN Orders AS o
ON s.salesperson_ID = o.salesperson_ID
WHERE o.customer_ID <> 4
GROUP BY o.salesperson_ID;
Perhaps this will work
SELECT
s.*
FROM `Salesperson` AS s
LEFT JOIN `Orders` AS o ON o.`salesperson_id` = s.`salesperson_ID`
WHERE
o.`cust_id` NOT IN (4)
GROUP BY s.`salesperson_ID`;
Answer to your 2nd question:
SELECT
COUNT(*) AS num_of_orders
,s.`Name`
FROM `Salesperson` AS s
LEFT JOIN `Orders` AS o ON o.`salesperson_id` = s.`salesperson_ID`
GROUP BY s.`salesperson_ID`
HAVING num_of_orders >= 2;
...and 3rd question. (assuming you have your highAchiever table ready)
INSERT INTO `highAchiever`
(`Name`,`Age`)
SELECT
`Name`
,`Age`
FROM `Salesperson`
WHERE
`Salary` >= 100000;