I have the mysql statement below all works fine until I add (sub_total - discount_total) AS total,.
I'm guessing this is because I am calling on aliases that are not defined yet (sub_total and discount_total).
How do I define the aliases so it doesn't throw an error #1054 - Unknown column 'sub_total' in 'field list'
SELECT SQL_CALC_FOUND_ROWS
`bookings`.`id`,
`bookings`.`client_id`,
`bookings`.`vehicle_id`,
`bookings`.`vehicle_hire`,
(insurance_driver_1 + insurance_driver_2 + insurance_driver_3) AS insurance_total,
`bookings`.`bedding_qty`,
`bookings`.`bedding_price`,
`bookings`.`promo_discount`,
`bookings`.`promo_is_percent`,
`bookings`.`promo_code`,
(vehicle_hire + insurance_driver_1 + insurance_driver_2 + insurance_driver_3) + (bedding_qty * bedding_price) AS sub_total,
CASE
WHEN promo_is_percent = 1
THEN (((vehicle_hire + insurance_driver_1 + insurance_driver_2 + insurance_driver_3) + (bedding_qty * bedding_price)) / 100) * promo_discount
WHEN promo_is_percent = 0
THEN promo_discount
END as discount_total,
(sub_total - discount_total) AS total
FROM `bookings`
WHERE `bookings`.`status` = 'Quote'
ORDER BY `bookings`.`id` desc
LIMIT 0, 10
Thanks
Update
Working example below,
`SELECT SQL_CALC_FOUND_ROWS *,
(sub_total - discount_total) AS total
FROM (
SELECT
`bookings`.`id`,
`bookings`.`client_id`,
`bookings`.`vehicle_id`,
`bookings`.`vehicle_hire`,
(insurance_driver_1 + insurance_driver_2 + insurance_driver_3) AS insurance_total,
`bookings`.`bedding_qty`,
`bookings`.`bedding_price`,
`bookings`.`promo_discount`,
`bookings`.`promo_is_percent`,
`bookings`.`promo_code`,
(vehicle_hire + insurance_driver_1 + insurance_driver_2 + insurance_driver_3) + (bedding_qty * bedding_price) AS sub_total,
CASE
WHEN promo_is_percent = 1
THEN (((vehicle_hire + insurance_driver_1 + insurance_driver_2 + insurance_driver_3) + (bedding_qty * bedding_price)) / 100) * promo_discount
WHEN promo_is_percent = 0
THEN promo_discount
END as discount_total
FROM `bookings`
WHERE `bookings`.`status` = 'Quote'
) AS src
ORDER BY src.`id` desc
LIMIT 0, 10`
For your question I would solve it like so:
SELECT *,
(sub_total - discount_total) AS total
FROM (
SELECT SQL_CALC_FOUND_ROWS
`bookings`.`id`,
`bookings`.`client_id`,
`bookings`.`vehicle_id`,
`bookings`.`vehicle_hire`,
(insurance_driver_1 + insurance_driver_2 + insurance_driver_3) AS insurance_total,
`bookings`.`bedding_qty`,
`bookings`.`bedding_price`,
`bookings`.`promo_discount`,
`bookings`.`promo_is_percent`,
`bookings`.`promo_code`,
(vehicle_hire + insurance_driver_1 + insurance_driver_2 + insurance_driver_3) + (bedding_qty * bedding_price) AS sub_total,
CASE
WHEN promo_is_percent = 1
THEN (((vehicle_hire + insurance_driver_1 + insurance_driver_2 + insurance_driver_3) + (bedding_qty * bedding_price)) / 100) * promo_discount
WHEN promo_is_percent = 0
THEN promo_discount
END as discount_total
FROM `bookings`
WHERE `bookings`.`status` = 'Quote'
) AS src
ORDER BY src.`id` desc
LIMIT 0, 10
but this is only if you're definitely trying to avoid retyping the whole formula for your column.
have you also considered creating a calculated column in mysql?
Related
How can I write this in a more optimized way?
SELECT week_day
, SUM(min_0 + min_1 + min_2 + min_3)
/ (SELECT SUM(min_0 + min_1 + min_2 + min_3)
FROM Hotel.RegIn) * 100 AS MIN_PERCENTAGE
FROM Hotel.RegIn
WHERE week_day = "Wednesday"
GROUP
BY week_day;
I'd write it as below:
SELECT
"Wednesday",
100 * SUM((week_day = "Wednesday") * (min_0 + min_1 + min_2 + min_3))
/ SUM(min_0 + min_1 + min_2 + min_3) AS MIN_PERCENTAGE
FROM Hotel.RegIn
;
or if you can use multiple statements, another one with easier filters:
SET #var_all_day_total :=
(SELECT SUM(min_0 + min_1 + min_2 + min_3) FROM Hotel.RegIn) / 100;
SELECT
week_day,
SUM(min_0 + min_1 + min_2 + min_3) / #var_all_day_total AS MIN_PERCENTAGE
FROM Hotel.RegIn
-- WHERE week_day = "Wednesday"
GROUP BY
week_day
;
The idea usually is not to redundantly calculate the same values more than once.
You should use derived table in the FROM clause. This way the subquery will be evaluated only once.
SELECT
week_day,
SUM(min_0 + min_1 + min_2 + min_3) / RegInSum.sum_all * 100 AS MIN_PERCENTAGE
FROM
Hotel.RegIn,
(SELECT
SUM(min_0 + min_1 + min_2 + min_3) as sum_all
FROM
Hotel.RegIn) as RegInSum
WHERE week_day = "Wednesday"
GROUP BY week_day;
Note that as far as you restrict your query only to one day of week, you won't get any performance gain by rewriting the query, because the subquery will be evaluated only once in both cases.
See CTE (Common Table Expressions) for more readable syntax of derived tables in newer versions of MySQL.
I have a table table_user in my MySQL having a column ip_address.
I would like to Update the values of ip_address in all the rows with random IP address
Example, like 12.345.678.90 but it must be different in each ip_address row for compatible with the new script code, yesterday I found 312892 records one IP :)
I tried this SQL but didn't work with IP address.
UPDATE `table_user` SET `ip_address` = CONCAT(
SUBSTRING('12.345.678.90', FLOOR(RAND()*26) + 1, 1),
SUBSTRING('12.345.678.90', FLOOR(RAND()*26) + 1, 1),
SUBSTRING('12.345.678.90', FLOOR(RAND()*26) + 1, 1),
SUBSTRING('12.345.678.90', FLOOR(RAND()*26) + 1, 1),
SUBSTRING('12.345.678.90', FLOOR(RAND()*26) + 1, 1),
SUBSTRING('12.345.678.90', FLOOR(RAND()*26) + 1, 1)
);
How can I do this ?
This method should work:
UPDATE `table_user` SET `ip_address` = CONCAT(
TRUNCATE( RAND() * (255 - 1 + 1) + 1, 0 ), '.',
TRUNCATE( RAND() * (255 - 1 + 1) + 1, 0 ), '.',
TRUNCATE( RAND() * (255 - 1 + 1) + 1, 0 ), '.',
TRUNCATE( RAND() * (255 - 1 + 1) + 1, 0 )
)
It basically generates numbers from 1 to 255. TRUNCATE function gets rid of decimal numbers (truncate to 0 decimals). RAND function generates numbers from 0 (inclusive) to 1 (exclusive).
I know this is for MySQL, but if you came here looking for T-SQL code, here it is:
select CONCAT(
round( RAND() * (255 - 1 + 1) + 1, 0 ), '.',
round( RAND() * (255 - 1 + 1) + 1, 0 ), '.',
round( RAND() * (255 - 1 + 1) + 1, 0 ), '.',
round( RAND() * (255 - 1 + 1) + 1, 0 ))
In my query, rating_food, rating_service and rating_decor returns the same value, for all my results.
select `restaurants`.*, `rating`.*, (rating.rating_food + rating.rating_service + rating.rating_decor) / 3 as rating_total from
(
SELECT
avg(reviews.rating_food) * (- 1 / (0.33 * count(reviews.id) + 1) + 1) + 5 * 1 / (count(reviews.id) + 1 ) as rating_food,
avg(reviews.rating_service) * (- 1 / (0.33 * count(reviews.id) + 1) + 1) + 5 * 1 / (count(reviews.id) + 1 ) as rating_service,
avg(reviews.rating_decor) * (- 1 / (0.33 * count(reviews.id) + 1) + 1) + 5 * 1 / (count(reviews.id) + 1 ) as rating_decor
FROM restaurants
JOIN reviews ON reviews.restaurant_id = restaurants.id
)
as rating, restaurants
order by `rating_total` asc limit 12
Expected result:
A array of 12 results with three additional calculated columns (rating_food etc)
Right now i get 12 results but all their rating_food, rating_service and rating_decor returns the same value for all results.
You need to join back your ratings subquery with the restaurants table.
Try this one:
select `restaurants`.*, `rating`.*,
(rating.rating_food + rating.rating_service + rating.rating_decor) / 3 as rating_total from
(
SELECT
restaurants.id,
avg(reviews.rating_food) * (- 1 / (0.33 * count(reviews.id) + 1) + 1) + 5 * 1 / (count(reviews.id) + 1 ) as rating_food,
avg(reviews.rating_service) * (- 1 / (0.33 * count(reviews.id) + 1) + 1) + 5 * 1 / (count(reviews.id) + 1 ) as rating_service,
avg(reviews.rating_decor) * (- 1 / (0.33 * count(reviews.id) + 1) + 1) + 5 * 1 / (count(reviews.id) + 1 ) as rating_decor
FROM restaurants
JOIN reviews ON reviews.restaurant_id = restaurants.id
GROUP by restaurants.id
)
as rating join restaurants on rating.id = restaurants.id
order by `rating_total` asc limit 12
SQL Fiddle: http://sqlfiddle.com/#!9/50b39/4/0
I have this data..
+------+--------------+------------+
+ id + position_id + name +
+------+--------------+------------+
+ 1 + 1 + name_1 +
+ 2 + 5 + name_2 +
+ 3 + 2 + name_3 +
+ 4 + 2 + name_4 +
+ 5 + 2 + name_5 +
+ 6 + 3 + name_6 +
+ 7 + 4 + name_7 +
+ 8 + 3 + name_8 +
+ 9 + 2 + name_9 +
+------+--------------+------------+
..then I want the the results is like
+--------------+-----------+----------+----------+-----------+
+ position_id + result1 + result2 + result3 + result4 +
+--------------+-----------+----------+----------+-----------+
+ 1 + name_1 + # + # + # +
+ 2 + name_3 + name_4 + name_5 + name_9 +
+ 3 + name_6 + name_8 + # + # +
+ 4 + name_7 + # + # + # +
+ 5 + name_2 + # + # + # +
+--------------+-----------+----------+----------+-----------+
I have some case for resulting data, this data is for my school reports. The data results must be dynamic following primary of position and if the result is empty will sowing #.
For more data or information you can ask with the following command
If a fixed number of columns then you could do something like this:-
SELECT a.position_id,
COALESCE(MIN(a.name), '#') AS result1,
COALESCE(MIN(b.name), '#') AS result2,
COALESCE(MIN(c.name), '#') AS result3,
COALESCE(MIN(d.name), '#') AS result4
FROM some_table a
LEFT OUTER JOIN some_table b ON a.position_id = b.position_id AND a.id < b.id
LEFT OUTER JOIN some_table c ON a.position_id = c.position_id AND b.id < c.id
LEFT OUTER JOIN some_table d ON a.position_id = d.position_id AND c.id < d.id
GROUP BY a.position_id
With a variable number of columns it isn't going to be possible really without dynamically creating the SQL based on the number of columns, or doing something nasty with GROUP_CONCAT.
But this isn't likely to be efficient.
It would probably be better to do a query to get the first results and then sort out the formatting in the calling script.
EDIT
Time for some nasty code, and i still needs polishing!
First bit is a stored procedure. This gets the max number of columns (gets it slightly wrong, but should be easy to fix with a bit of effort, and works for now) and dynamically builds up the SQL to create a temp table with this number of columns, and then populates it.
DELIMITER ;;
CREATE DEFINER=CURRENT_USER PROCEDURE stored_procedure_name()
BEGIN
DECLARE sql1 TEXT;
DECLARE sql2 TEXT;
DECLARE sql3 TEXT;
SET ##group_concat_max_len = 32000;
SELECT
GROUP_CONCAT(CONCAT('MIN(a', (1 + units.iCnt + 10 * tens.iCnt), '.name) AS result', (1 + units.iCnt + 10 * tens.iCnt)) ORDER BY (1 + units.iCnt + 10 * tens.iCnt)),
GROUP_CONCAT(CONCAT('LEFT OUTER JOIN some_table a', (1 + units.iCnt + 10 * tens.iCnt), ' ON a', (units.iCnt + 10 * tens.iCnt), '.position_id = a', (1 + units.iCnt + 10 * tens.iCnt), '.position_id AND a', (units.iCnt + 10 * tens.iCnt), '.id < a', (1 + units.iCnt + 10 * tens.iCnt), '.id') ORDER BY (1 + units.iCnt + 10 * tens.iCnt) SEPARATOR ' '),
GROUP_CONCAT(CONCAT('result',(1 + units.iCnt + 10 * tens.iCnt), ' VARCHAR(255)') ORDER BY (1 + units.iCnt + 10 * tens.iCnt))
INTO sql1, sql2, sql3
FROM
(
SELECT MAX(count_name) as max_count_name
FROM
(
SELECT COUNT(name) as count_name
FROM some_table
GROUP BY position_id
) sub0
) sub1,
(SELECT 1 iCnt UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 0) units,
(SELECT 1 iCnt UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 0) tens
WHERE max_count_name >= (units.iCnt + 10 * tens.iCnt);
DROP TEMPORARY TABLE IF EXISTS temp1;
SET #sqlmain1 = CONCAT('CREATE TEMPORARY TABLE temp1(position_id INT, result0 VARCHAR(255), ', sql3, ')');
PREPARE stmt FROM #sqlmain1;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET #sqlmain2 = CONCAT('INSERT INTO temp1 SELECT a0.position_id, MIN(a0.name) AS result0,', sql1, ' FROM some_table a0 ', sql2, ' GROUP BY a0.position_id ');
PREPARE stmt FROM #sqlmain2;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END;;
DELIMITER ;
You can then execute this and then select from the resulting temp table. Note that both statements must be done in the same SQL session, otherwise the temp table will have disappeared by the time you do the select:-
CALL stored_procedure_name();
SELECT * FROM temp1
Hopefully you can pass these both to Jasper.
I have one problem with this query; I can't seem to get ((total + rec_host) / 2) AS total2 to work. How would I go about this procedure without doing:
((((rank_ur + rank_scs + rank_tsk + rank_csb + rank_vfm + rank_orr) / 6) + rec_host ) / 2)
Here's my Query:
SELECT host_name,
SUM(rank_ur) AS cnt1,
SUM(rank_scs) AS cnt2,
SUM(rank_tsk) AS cnt3,
SUM(rank_csb) AS cnt4,
SUM(rank_vfm) AS cnt5,
SUM(rank_orr) AS cnt6,
SUM(IF(rec_host = 1,1,0)) AS rh1,
SUM(IF(rec_host = 0,1,0)) AS rh2,
((rank_ur + rank_scs + rank_tsk + rank_csb + rank_vfm + rank_orr) / 6) AS total,
((total + rec_host) / 2) AS total2
FROM lhr_reviews
GROUP BY host_name
ORDER BY total
DESC LIMIT 0,10
Use a subquery like so:
SELECT
host_name,
cnt1,
cnt2,
cnt3,
cnt4,
cnt5,
cnt6,
rh1,
rh2,
total,
((total + rec_host) / 2) AS total2
FROM
(
SELECT host_name,
rec_host,
SUM(rank_ur) AS cnt1,
SUM(rank_scs) AS cnt2,
SUM(rank_tsk) AS cnt3,
SUM(rank_csb) AS cnt4,
SUM(rank_vfm) AS cnt5,
SUM(rank_orr) AS cnt6,
SUM(IF(rec_host = 1,1,0)) AS rh1,
SUM(IF(rec_host = 0,1,0)) AS rh2,
((rank_ur + rank_scs + rank_tsk +
rank_csb + rank_vfm + rank_orr
) / 6) AS total
FROM lhr_reviews
GROUP BY host_name, rec_host
) t
ORDER BY total
DESC LIMIT 0,10;
What you could do is this:
select x.*, ((x.total + rec_host) / 2) AS total2
from (
SELECT host_name, rec_host,
SUM(rank_ur) AS cnt1,
SUM(rank_scs) AS cnt2,
SUM(rank_tsk) AS cnt3,
SUM(rank_csb) AS cnt4,
SUM(rank_vfm) AS cnt5,
SUM(rank_orr) AS cnt6,
SUM(IF(rec_host = 1,1,0)) AS rh1,
SUM(IF(rec_host = 0,1,0)) AS rh2,
((rank_ur + rank_scs + rank_tsk + rank_csb + rank_vfm + rank_orr) / 6) AS total
FROM lhr_reviews
GROUP BY host_name
ORDER BY total
DESC LIMIT 0,10
) as x
;
You cannot use the column as an alias when the alias and other column are in the same level of SELECT. So you can use a derived query which lets you basically rename your columns and/or name any computed columns.Check on Rubens Farias and Rob Van Dam answer here
PS: will search for a better article to update the answer :)