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

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?

Related

add column to single row resultset

I have a query that gets me statistics about data in a table:
SELECT COUNT(1) batch_count,
ROUND(MAX(batch_duration_milliseconds) / 1000) max_batch_duration_seconds,
ROUND(AVG(batch_duration_milliseconds) / 1000) avg_batch_duration_seconds,
ROUND(MIN(batch_duration_milliseconds) / 1000, 1) min_batch_duration_seconds,
ROUND(SUM(total_queries_duration_milliseconds) / SUM(batch_duration_milliseconds) *
100) query_duration_percentage,
SUM(total_queries) queries,
ROUND(SUM(monitoring_queries) / SUM(total_queries) * 100) percent_monitoring_queries,
ROUND(SUM(total_queries) / SUM(batch_duration_milliseconds) * 1000) queries_per_second,
MAX(max_query_duration_milliseconds) max_query_duration,
ROUND(AVG(avg_query_duration_milliseconds)) avg_query_duration,
ROUND(SUM(retrieved_data_bytes) / 1024 / 1024) data_mb,
ROUND(MAX(retrieved_data_bytes) / 1024 / 1024) max_batch_data_mb,
ROUND(ROUND(AVG(retrieved_data_bytes)) / 1024 / 1024) avg_batch_data_mb,
ROUND(SUM(retrieved_data_bytes_calculation_duration_milliseconds) / SUM(batch_duration_milliseconds) *
100, 1) percent_data_calc_duration
FROM entrypoint_sql_queries
WHERE created_at > SUBDATE(NOW(), INTERVAL 1 HOUR);
now I want to add one more column that gets me the percent of queries caused by the entrypoint with the most queries:
SELECT ROUND(MAX(total_queries) / SUM(total_queries) * 100) percent_most_expensive_job_queries
FROM (
SELECT SUM(total_queries) AS total_queries
FROM entrypoint_sql_queries
WHERE created_at > SUBDATE(NOW(), INTERVAL 1 HOUR)
GROUP BY entrypoint
) as t;
How can I get both into the same resultset (i.e. I want to show the resulting number of query 2 as an additional column in query 1)
You can do it by adding your second query as a single column on the global select :
SELECT COUNT(1) batch_count,
ROUND(MAX(batch_duration_milliseconds) / 1000) max_batch_duration_seconds,
ROUND(AVG(batch_duration_milliseconds) / 1000) avg_batch_duration_seconds,
ROUND(MIN(batch_duration_milliseconds) / 1000, 1) min_batch_duration_seconds,
ROUND(SUM(total_queries_duration_milliseconds) / SUM(batch_duration_milliseconds) *
100) query_duration_percentage,
SUM(total_queries) queries,
ROUND(SUM(monitoring_queries) / SUM(total_queries) * 100) percent_monitoring_queries,
ROUND(SUM(total_queries) / SUM(batch_duration_milliseconds) * 1000) queries_per_second,
MAX(max_query_duration_milliseconds) max_query_duration,
ROUND(AVG(avg_query_duration_milliseconds)) avg_query_duration,
ROUND(SUM(retrieved_data_bytes) / 1024 / 1024) data_mb,
ROUND(MAX(retrieved_data_bytes) / 1024 / 1024) max_batch_data_mb,
ROUND(ROUND(AVG(retrieved_data_bytes)) / 1024 / 1024) avg_batch_data_mb,
ROUND(SUM(retrieved_data_bytes_calculation_duration_milliseconds) / SUM(batch_duration_milliseconds) *
100, 1) percent_data_calc_duration,
( SELECT ROUND(MAX(total_queries) / SUM(total_queries) * 100)
FROM (
SELECT SUM(total_queries) AS total_queries
FROM entrypoint_sql_queries
WHERE created_at > SUBDATE(NOW(), INTERVAL 1 HOUR)
GROUP BY entrypoint
) as t ) as percent_most_expensive_job_queries
FROM entrypoint_sql_queries
WHERE created_at > SUBDATE(NOW(), INTERVAL 1 HOUR);

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
;

use join in distance searching and mysql

In mysql I am calculating all the points between two zip codes and that's working fine for me. Now I want update that query to join an additional table, but I am getting an error. Here is the query please have a look:
SELECT *
FROM users
INNER JOIN
(SELECT *,
ACOS(
COS(RADIANS(30.7261629))
* COS(RADIANS(lat_collection))
* COS(RADIANS(76.7596221) - RADIANS(`long_collection`))
+ SIN(RADIANS(30.7261629))
* SIN(RADIANS(lat_collection))
) * 3956 AS `distance`
FROM quote q
WHERE lat_collection BETWEEN 30.7261629 - (30 / 69) AND 30.3345816 + (30 / 69)
AND `long_collection` BETWEEN 76.7596221 - (30 / (69 * COS(RADIANS(30.7261629)))) AND 78.0537813 + (30 / (69* COS(RADIANS(30.7261629))))
) AS u
ON q.user_id=u.id
WHERE `distance` < 30
I need to join four-five table in the same query; how can I do that? I am getting an error when trying to join the tables (I have two zip codes and then I calculate lat long for both the zip codes).
You are using an alias in where condition .. this is not allowed you must reuse the full code instead of alias
SELECT *
FROM users inner join (
SELECT *, 3956 * ACOS(COS(RADIANS(30.7261629)) * COS(RADIANS(lat_collection)) * COS(RADIANS(76.7596221) -
RADIANS(`long_collection`))
+ SIN(RADIANS(30.7261629)) * SIN(RADIANS(lat_collection))) AS `distance`
FROM quote q
WHERE lat_collection BETWEEN 30.7261629 - (30 / 69) AND 30.3345816 + (30 / 69)
AND `long_collection` BETWEEN 76.7596221 - (30 / (69 * COS(RADIANS(30.7261629)))) AND 78.0537813 + (30 / (69* COS(RADIANS(30.7261629))))
) as u on users.id=u.user_id
WHERE (3956 * ACOS(COS(RADIANS(30.7261629)) * COS(RADIANS(lat_collection)) * COS(RADIANS(76.7596221) - RADIANS(`long_collection`))
+ SIN(RADIANS(30.7261629)) * SIN(RADIANS(lat_collection)))) < 30

SQL Query selects the same data

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

Filter rows based on a custom calculated field

I would like to filter the rows returned using a WHERE condition. The problem is that MySQL is not allowing me to use a custom column name in the WHERE clause. It gives a syntax error.
SELECT jobs.*,
CASE
WHEN job_status = 'submitted' THEN ((2 * 86400) - ($mktime - job_timestamp))/86400
WHEN job_status = 'agreement_pending' THEN ((1 * 86400) - ($mktime - job_tstamp_agpending))/86400
WHEN job_status = 'payment_complete' THEN ((job_duration * 86400) - ($mktime - job_tstamp_pcomplete))/86400
ELSE 1000000
END AS sla
FROM jobs
WHERE sla < 0
Is it possible to still filter rows out WHERE sla < 0 condition?
MySQL has a special extension where you can do this using the having clause:
SELECT jobs.*,
CASE
WHEN job_status = 'submitted' THEN ((2 * 86400) - ($mktime - job_timestamp))/86400
WHEN job_status = 'agreement_pending' THEN ((1 * 86400) - ($mktime - job_tstamp_agpending))/86400
WHEN job_status = 'payment_complete' THEN ((job_duration * 86400) - ($mktime - job_tstamp_pcomplete))/86400
ELSE 1000000
END AS sla
FROM jobs
HAVING sla < 0;
This is not supported in other databases.
A valid solution for all RDBMSes uses a Derived Table:
SELECT *
FROM
(
SELECT jobs.*,
CASE
WHEN job_status = 'submitted' THEN ((2 * 86400) - ($mktime - job_timestamp))/86400
WHEN job_status = 'agreement_pending' THEN ((1 * 86400) - ($mktime - job_tstamp_agpending))/86400
WHEN job_status = 'payment_complete' THEN ((job_duration * 86400) - ($mktime - job_tstamp_pcomplete))/86400
ELSE 1000000
END AS sla
FROM jobs
) AS dt
WHERE sla < 0