SQL Query selects the same data - mysql

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

Related

Subset a table such that the samples are normally distributed around a value in a column

I have the following table called original_table:
name height age
personA 180 21
personB 190 37
personC 168 27
personD 182 56
...
My goal is to create two random samples of size 100 from the original_table such that the mean of age is normally distributed around 25, and height average is close to 175. Basically, a person with age 25 and height 175 has the highest chance of being in the tables, but not guaranteed.
The trick is to find the normal distribution function from other languages, and then convert it to mysql syntax. For example, convert from the following java code to mysql
//java.util.Random
synchronized public double nextGaussian() {
// See Knuth, ACP, Section 3.4.1 Algorithm C.
if (haveNextNextGaussian) {
haveNextNextGaussian = false;
return nextNextGaussian;
} else {
double v1, v2, s;
do {
v1 = 2 * nextDouble() - 1; // between -1 and 1
v2 = 2 * nextDouble() - 1; // between -1 and 1
s = v1 * v1 + v2 * v2;
} while (s >= 1 || s == 0);
double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
nextNextGaussian = v2 * multiplier;
haveNextNextGaussian = true;
return v1 * multiplier;
}
}
with recursive t0(v1, v2, s, num1, num2, rn) as (
select #v1:= rand() * 2 - 1,
#v2:= rand() * 2 - 1,
#s:= #v1*#v1 + #v2*#v2,
sqrt(-2 * log(#s) / (#s)) * #v1,
sqrt(-2 * log(#s) / (#s)) * #v2,
#rn:=case when #s < 1 and #s > 0 then 1 else 0 end
union all
select #v1:= rand() * 2 - 1,
#v2:= rand() * 2 - 1,
#s:= #v1*#v1 + #v2*#v2,
sqrt(-2 * log(#s) / (#s)) * #v1,
sqrt(-2 * log(#s) / (#s)) * #v2,
#rn:=case when #s < 1 and #s > 0 then 1 else 0 end + #rn
from t0
where #rn < 100
)
select 175 + t1.num1 * 10,
175 + t1.num2 * 10,
25 + t1.num1 * 8,
25 + t1.num2 * 8
from t0 t1
where t1.num1 is not null
order by t1.num1
;

How to use a calculated field in a subquery (sqlite3)

I have this code that works in MySQL
CASE
WHEN e.sex = 'M' THEN ROUND((salary / 30 * absents) + (salary / 30 / 8 * short_hours * 1.5))
ELSE ROUND((salary / 30 * absents) + (salary / 30 / 5 * short_hours * 1.5))
END AS deductions,
CASE
WHEN e.sex = 'M' THEN ROUND(salary / 30 / 8 * overtime * 1.5)
ELSE ROUND(salary / 30 / 5 * overtime * 1.5)
END AS overtime_bonus,
ROUND(salary - (SELECT deductions) + (SELECT overtime_bonus)) AS total_salary,
I am trying to make it work in SQLite but I get the error no such column: deductions
My question is: can I use a calculated field in a subquery in SQLite3?

How to use value from two different rows of a table in another table

I have a MySQL table with the following structure and data:
Increments
id emp_id starting_salary increment_rate increment_frequency
2 340 5000 250 1
3 340 5000 250 4
I need to have aliases, a and b which will hold some value based on the following formula:
starting_salary + (increment_rate * increment_frequency)
To be precise, I want a = 5250 (based on a = (5000 + (250 * 1))) and b = 6000 (based on b = (5000 + (250 * 4)))
Now I have another table with the following data:
PaySlips
id employee_id salary_month arrear
173824 340 '2015-06-01' 2350
I want to join a and b that I got from the table Increments with table PaySlips. And I want to use a and b in the following way:
((a * 8) / 30 + (b * 22) / 30)
My alias will be basic_salary. So basic_salary will hold this value from the above calculation:
basic_salary = ((a * 8) / 30 + (b * 22) / 30)
= ((5250 * 8) / 30 + (6000 *22) / 30)
= (1400 + 4400)
= 5800
I've got no idea how to do this. Can anyone please help me?
All I got are the common columns in both tables - emp_id and employee_id and I can join both tables using these columns. I just can't figure out how I can store the above values and organize the calculation inside my query.
Sample query:
SELECT x.id, x.employee_id,
(*my calculation using a and b from table Increments*) AS basic_salary,
x.salary_month, x.arrear
FROM PaySlips x
JOIN Increments y
ON x.employee_id = y.emp_id
For determining a:
SELECT
(
starting_salary +
(increment_rate * increment_frequency)
) AS a
FROM Increments
WHERE id = 2
And for determining b:
SELECT
(
starting_salary +
(increment_rate * increment_frequency)
) AS b
FROM Increments
WHERE id = 3
MySQL version: 5.2
I'm not clear on all the details, for example what should happen if there are three rows for one employee in increments? Anyhow, here's a sketch to start with:
select employee_id
, ((a * 8) / 30 + (b * 22) / 30) as basic_salary
from (
select x.employee_id
, min(starting_salary + (increment_rate * increment_frequency)) as a
, max(starting_salary + (increment_rate * increment_frequency)) as b
, x.salary_month, x.arrear
from payslips x
join increments y
on x.employee_id = y.emp_id
group by x.employee_id, x.salary_month, x.arrear
) as t
If id 2 and 3 are the criteria (I assumed they are examples) you can use a case statement like:
select employee_id
, ((a * 8) / 30 + (b * 22) / 30) as basic_salary
from (
select x.employee_id
, max(starting_salary + (increment_rate * case when y.id = 2 then increment_frequency end )) as a
, max(starting_salary + (increment_rate * case when y.id = 3 then increment_frequency end)) as b
, x.salary_month
, x.arrear
from payslips x
join increments y
on x.employee_id = y.emp_id
group by x.employee_id, x.salary_month, x.arrear
) as t;
In this case it does not matter what aggregate you use, it is to get rid of the row that contains null.
based on the requirements you added i think something like this will solve your problems:
SELECT PS.id, PS.employee_id, ((A.value * 8) / 30 + (B.value * 22) / 30) AS basic_salary
FROM PaySlips AS PS
JOIN (
SELECT I.emp_id, I.starting_salary + (increment_rate * increment_frequency) AS VALUE
FROM Increments AS I
WHERE I.id = 2
) AS A
ON A.emp_id = PS.employee_id
JOIN (
SELECT I.emp_id, I.starting_salary + (increment_rate * increment_frequency) AS value
FROM Increments AS I
WHERE I.id = 3
) AS B
ON B.emp_id = PS.employee_id
This version might need some alteration if it's not working on your real scenario, but please feel free to tell if anything else needs amending.
Hope it helps.
For determining and setting #a variable:
SET #a := (SELECT
(
starting_salary +
(increment_rate * increment_frequency)
) AS a
FROM Increments
WHERE id = 2);
And for determining and setting #b variable:
SET #b := (SELECT
(
starting_salary +
(increment_rate * increment_frequency)
) AS b
FROM Increments
WHERE id = 3);
Then you can use #a and #b in your main query;
you can test simply by
SELECT #a as a;
SELECT #b as b;
SELECT
x.id,
x.employee_id,
(y.a * 8) / 30 + (y.b * 22) / 30 as basic_salary,
x.salary_month,
x.arrear
FROM PaySlips x
JOIN (
select t1.emp_id, t1.a, t2.b
from (
select
emp_id,
starting_salary + increment_rate * increment_frequency as a
from Increments
where id = 2
) as t1
join (
select
emp_id,
starting_salary + increment_rate * increment_frequency as b
from Increments
where id = 3
) as t2
on t1.emp_id = t2.emp_id
) as y
ON x.employee_id = y.emp_id

Please anyone help about my case in mysql query

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.

How to use alias in SELECT

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?