Adding up Alias with other MySQL column value - mysql

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 :)

Related

MySQL SUM Query with Joins and Union All

Can anybody tell me why the second LEFT JOIN in the query below (previous_spend) is returning double the amount it should?
It returns the correct amount if I remove the first LEFT JOIN, so I assume it's doubling the result due to the first LEFT JOIN, but I'm not sure how to rewrite the query to avoid that.
Any help would be much appreciated.
Update: I've created a slightly easier to understand version here: Here's a live example: http://sqlfiddle.com/#!9/6a9358/1 - as you can see 'current_spend' should return £300.
SELECT
COALESCE(SUM(current_spend.total_spend), 0) AS total_spend,
COALESCE(SUM(previous_spend.total_previous_spend), 0) AS total_previous_spend,
COALESCE(SUM(current_spend.total_spend), 0) - COALESCE(SUM(previous_spend.total_previous_spend), 0) AS total_spend_diff,
100 * (COALESCE(SUM(current_spend.total_spend), 0) - COALESCE(SUM(previous_spend.total_previous_spend), 0)) / COALESCE(SUM(previous_spend.total_previous_spend), 0) AS total_spend_diff_perc
FROM customer_scheme
LEFT JOIN (
SELECT SUM(spend_1 + spend_2) AS total_spend, user_id
FROM customer_spend
WHERE customer_spend.spend_year = '2017'
GROUP BY user_id
UNION ALL
SELECT SUM(spend_1 + spend_2 + spend_3 + spend_4 + spend_5 + spend_6 + spend_7 + spend_8 + spend_9 + spend_10 + spend_11 + spend_12) AS total_spend, user_id
FROM customer_spend
WHERE customer_spend.spend_year = '2018'
GROUP BY user_id
UNION ALL
SELECT SUM(spend_1 + spend_2 + spend_3 + spend_4 + spend_5 + spend_6 + spend_7 + spend_8 + spend_9 + spend_10 + spend_11 + spend_12) AS total_spend, user_id
FROM customer_spend
WHERE customer_spend.spend_year = '2019'
GROUP BY user_id
UNION ALL
SELECT SUM(spend_1 + spend_2) AS total_spend, user_id
FROM customer_spend
WHERE customer_spend.spend_year = '2020'
GROUP BY user_id
) as current_spend
ON current_spend.user_id = customer_scheme.user_id
LEFT JOIN
(
SELECT SUM(spend_1 + spend_2) AS total_previous_spend, user_id
FROM customer_spend
WHERE customer_spend.spend_year = '2013'
GROUP BY user_id
UNION ALL
SELECT SUM(spend_1 + spend_2 + spend_3 + spend_4 + spend_5 + spend_6 + spend_7 + spend_8 + spend_9 + spend_10 + spend_11 + spend_12) AS total_previous_spend, user_id
FROM customer_spend
WHERE customer_spend.spend_year = '2014'
GROUP BY user_id
UNION ALL
SELECT SUM(spend_1 + spend_2 + spend_3 + spend_4 + spend_5 + spend_6 + spend_7 + spend_8 + spend_9 + spend_10 + spend_11 + spend_12) AS total_previous_spend, user_id
FROM customer_spend
WHERE customer_spend.spend_year = '2015'
GROUP BY user_id
UNION ALL
SELECT SUM(spend_1 + spend_2) AS total_previous_spend, user_id
FROM customer_spend
WHERE customer_spend.spend_year = '2016'
GROUP BY user_id
) as previous_spend
ON previous_spend.user_id = customer_scheme.user_id
LEFT JOIN user
ON customer_scheme.user_id = user.user_id
WHERE customer_scheme.scheme_id = 36
AND customer_scheme.customer_scheme_access = 'Yes'
AND user.user_deleted_at IS NULL
AND user_type = 'Customer'
AND user.user_status IN (1)
ORDER BY total_spend_diff DESC
The summary of your query is
(customer_scheme LEFT JOIN current_spend) appended with (customer_scheme LEFT JOIN previous_spend)
If you remove the LEFT JOIN with current_spend :
Query would be customer_scheme LEFT JOIN previous_spend
That means, for one user in customer_scheme, you will get one row for previous_spend for 2013, one row for 2014, one row for 2015, one row for 2016
While summing, you will sum all the above said 4 rows.
If you have the LEFT JOIN with current_spend :
For first LEFT JOIN with current_spend, you will get one row for 2017, one for 2018, one for 2019 and one for 2020.
So, for one user_id , you will get 4 rows. Now, you are going to join previous_spend with these 4 rows (where as previously, you will join with only one row). While summing, this makes the difference.
I will try to provide much better insights if you can share an sql fiddle with some test data.
Try this:
SELECT
SUM(IFNULL(current_spend.total_spend, 0)) AS total_spend,
SUM(IFNULL(previous_spend.total_previous_spend, 0)) AS total_previous_spend,
SUM(IFNULL(current_spend.total_spend, 0)) - SUM(IFNULL(previous_spend.total_previous_spend, 0)) AS total_spend_diff,
100 * (SUM(IFNULL(current_spend.total_spend, 0)) - SUM(IFNULL(previous_spend.total_previous_spend, 0))) / SUM(IFNULL(previous_spend.total_previous_spend, 0)) AS total_spend_diff_perc
FROM
customer_scheme
LEFT JOIN
(
SELECT SUM(spend_1 + spend_2 + spend_3 + spend_4 + spend_5 + spend_6 + spend_7 + spend_8 + spend_9 + spend_10 + spend_11 + spend_12) AS total_spend, user_id, customer_spend.spend_year
FROM customer_spend
WHERE customer_spend.spend_year in ('2017','2018','2019','2020')
GROUP BY user_id, customer_spend.spend_year
) as current_spend
ON current_spend.user_id = customer_scheme.user_id
INNER JOIN
(
SELECT SUM(spend_1 + spend_2 + spend_3 + spend_4 + spend_5 + spend_6 + spend_7 + spend_8 + spend_9 + spend_10 + spend_11 + spend_12) AS total_previous_spend, user_id, customer_spend.spend_year
FROM customer_spend
WHERE customer_spend.spend_year in ('2013','2014','2015','2016')
GROUP BY user_id, customer_spend.spend_year
) as previous_spend
ON previous_spend.user_id = customer_scheme.user_id
LEFT JOIN user
ON customer_scheme.user_id = user.user_id
WHERE customer_scheme.scheme_id = 36
AND customer_scheme.customer_scheme_access = 'Yes'
AND user.user_deleted_at IS NULL
AND user_type = 'Customer'
AND user.user_status IN (1)
ORDER BY total_spend_diff DESC;

SQL script is not working as intended: how to use an aggregate in a virtual column to order the results?

I have this:
SELECT * FROM `npt_articles` WHERE (date_discovered >= 1464534366 AND
date_discovered <= 1464534366 AND
npt_site_id = 4 AND
(#total_social := (comments_html + fb_total + google_plus_one + pinterest + linked_in ) + 0.0) >
865.0 AND
http_status_code = 200) ORDER BY #total_social DESC;
It works but no where near as intended.
total_social is the aggregate value of other named fields of the same row (record, object, etc.) which is then compared against a number which is injected into the query string. I want to also use this aggregate in a virtual column to then be used to order the results.
I tried this but I'm not sure if this is the way to go:
SELECT *, #total_social := (comments_html + fb_total + google_plus_one + pinterest + linked_in ) + 0.0 FROM `npt_articles`
WHERE (date_discovered >= 1464534366 AND
npt_site_id = 4 AND
#total_social >
865.0 AND
http_status_code = 200) ORDER BY #total_social DESC;
I think what I want is something like this:
SELECT *, ((comments_html + fb_total + google_plus_one + pinterest + linked_in ) + 0.0) as total_social FROM `npt_articles` WHERE (date_discovered >= 1464534366 AND
npt_site_id = 4 AND
total_social >
865.0 AND
http_status_code = 200) ORDER BY total_social DESC;
The only issue is that MySQL Workbench says total_social doesn't exist.
I've tried using a CTE like this:
WITH inner_table AS (
SELECT
((comments_html + fb_total + google_plus_one + pinterest + linked_in) + 0.0) AS total_social
FROM
`npt_articles`
)
select * FROM inner_table
WHERE
(date_discovered >= 1464534366
AND npt_site_id = 4
AND total_social > 865.0
AND http_status_code = 200)
ORDER BY total_social DESC;
like in "Referring to a Column Alias in a WHERE Clause" but MySQL Workbench won't accept it because it doesn't like the WITH at that position, which I know now isn't supported by MySQL.
Right, so the solution was to use the HAVING clause which I found from "How to use a temp column in the where clause", which I think is basicly a WHERE clause that happens after a SELECT.
Now my SQL looks like this:
SELECT *,
(comments_html + fb_total + google_plus_one + pinterest + linked_in) + 0.0 AS total_social FROM `npt_articles` WHERE (
date_discovered >= 1464534366
AND
npt_site_id = 4
AND
http_status_code = 200
)
HAVING total_social > 865.0 ORDER BY total_social DESC;
Now it does the query, does the select, calculates the total_social column and then does a second query using total_social and then orders by total_social in descending order.

SELECT *, sum() with equation only returns one row

SELECT *,
(SUM(`q6`) /
(`q1` *
(`q1` + `q2` + `q3` + `q4` + `q5` + `q6`) / 6)
* 100) AS percent
FROM table
WHERE field2 = 'xxx'
ORDER BY `percent` ASC
The code above is returning me the correct value for "percent" but only returns one row. I need it to return all the rows, 15 of them.
In my equation I am trying to get the value "percent" for each row and ORDER by the highest percent.
It seems, as soon as I add the sum() to my select statement, that it then returns only one row.
Assuming all comments, you should get something like:
SELECT
*, (SUM(`q6`) / (`q1` * (`q1` + `q2` + `q3` + `q4` + `q5` + `q6`) / 6) * 100)
AS percent
FROM table
WHERE field2 = 'xxx'
GROUP BY id ORDER BY `percent` DESC
In MySQL you can include columns in the select that are not aggregated and not in the group by. Because your query has an aggregation function, MySQL recognizes it as an aggregation query, and only returns one row.
Actually, you need to bring in the total value for a calculation on each row. Here is one way using a subquery in the select statement:
SELECT *,
(select sum(q6) as sumq6 from table where field2 = 'xxx') / (`q1` * (`q1` + `q2` + `q3` + `q4` + `q5` + `q6`) / 6)
* 100) AS percent
FROM table
WHERE field2 = 'xxx'
ORDER BY `percent` ASC;
Here is another way, using a cross join:
SELECT *,
(sumq6 / (`q1` * (`q1` + `q2` + `q3` + `q4` + `q5` + `q6`) / 6)
FROM table cross join
(select sum(q6) as sumq6 from table where field2 = 'xxx') as const
WHERE field2 = 'xxx'
ORDER BY `percent` ASC;

Merge two complex MYSQL queries

i want help on a way to merge two complex MYSQL queries.
Query 1:
SELECT p.*
FROM posts p
INNER JOIN
(
SELECT a.ID
FROM posts a
INNER JOIN post_tags b
ON a.ID = b.post_ID
WHERE a.post LIKE '%mmmm%' AND
b.tagname IN ('#test','#iseeyou')
GROUP BY ID
HAVING COUNT(DISTINCT b.tagname) = 2
) sub ON p.ID = sub.ID
ORDER BY p.upvotes DESC, p.unix_timestamp DESC
Query 2:
SELECT p.*, ((upvotes + 1.9208) / (upvotes + downvotes) - 1.96 * SQRT((upvotes * downvotes)
/ (upvotes + downvotes) + 0.9604) / (upvotes + downvotes))
/ (1 + 3.8416 / (upvotes + downvotes)) AS ci_lower_bound
FROM posts p WHERE upvotes + downvotes > 0
AND p.unix_timestamp BETWEEN 1363023402 AND 1363109802 ORDER BY ci_lower_bound DESC
A small table definition is given at SQL Fiddle
Actually, the first one is a search query and the second one gives the most popular results based on votes in the last 24 hours, so i want use the search query based on the formula used in the second one and also the time range
With minimal changes something like this (if I have understood what you want correctly)
SELECT p.*, ((upvotes + 1.9208) / (upvotes + downvotes) - 1.96 * SQRT((upvotes * downvotes)
/ (upvotes + downvotes) + 0.9604) / (upvotes + downvotes))
/ (1 + 3.8416 / (upvotes + downvotes)) AS ci_lower_bound
FROM posts p
INNER JOIN
(
SELECT a.ID
FROM posts a INNER JOIN post_tags b ON a.ID = b.post_ID
WHERE a.post LIKE '%mmmm%' AND b.tagname IN ('#test','#iseeyou')
GROUP BY ID
HAVING COUNT(DISTINCT b.tagname) = 2
) sub ON p.ID = sub.ID
WHERE upvotes + downvotes > 0
AND p.unix_timestamp BETWEEN 1363023402 AND 1363109802
ORDER BY ci_lower_bound DESC
Possibly a touch more efficient to swap around the WHERE clause on the subselect (the leading % on the like will not use an index, hence probably more efficient to join that against the easily indexed check on post_tags))
SELECT p.*, ((upvotes + 1.9208) / (upvotes + downvotes) - 1.96 * SQRT((upvotes * downvotes)
/ (upvotes + downvotes) + 0.9604) / (upvotes + downvotes))
/ (1 + 3.8416 / (upvotes + downvotes)) AS ci_lower_bound
FROM posts p
INNER JOIN
(
SELECT a.ID
FROM post_tags b STRAIGHT_JOIN posts a ON a.ID = b.post_ID
WHERE a.post LIKE '%mmmm%' AND b.tagname IN ('#test','#iseeyou')
GROUP BY ID
HAVING COUNT(DISTINCT b.tagname) = 2
) sub ON p.ID = sub.ID
WHERE upvotes + downvotes > 0
AND p.unix_timestamp BETWEEN 1363023402 AND 1363109802
ORDER BY ci_lower_bound DESC

SUM a grouped field

I need to SUM the contents of a column which is already worked out using GROUP BYs.. How exactly would you go about that?
The group should be based on the user name, not the entire contents of the result set. I believe this essentially a group by on that username field, but that i believe would break how the query currently works..
Example below:
SELECT A1.USERNAME, DATE_FORMAT(FROM_UNIXTIME(A1.TIME_STAMP),'%Y-%m-%d') AS DTTM, A1.ACCTSESSIONID,
MAX(IFNULL(A1.ACCTINPUTGW,0) * POW(2,32) + IFNULL(A1.ACCTINPUTOCT, 0)) - MAX(IFNULL(A2.ACCTINPUTGW,0) * POW(2,32) + IFNULL(A2.ACCTINPUTOCT, 0)) as TOTAL_UPLOAD,
MAX(IFNULL(A1.ACCTOUTPUTGW,0) * POW(2,32) + IFNULL(A1.ACCTOUTPUTOCT, 0)) - MAX(IFNULL(A2.ACCTOUTPUTGW,0) * POW(2,32) + IFNULL(A2.ACCTOUTPUTOCT, 0)) as TOTAL_DOWNLOAD
FROM ACCOUNTING A1
LEFT JOIN ACCOUNTING A2
ON A1.ACCTSESSIONID = A2.ACCTSESSIONID
AND DATE_FORMAT(FROM_UNIXTIME(A2.TIME_STAMP), '%Y-%m-%d') = '2011-07-04'
WHERE DATE_FORMAT(FROM_UNIXTIME(A1.TIME_STAMP), '%Y-%m-%d') = '2011-07-05'
GROUP BY A1.ACCTSESSIONID,A2.ACCTSESSIONID
ORDER BY A1.USERNAME
Edit:
The columns would be: TOTAL_DOWNLOAD and TOTAL_UPLOAD
Thanks # ypercube, worked a treat
SELECT A3.USERNAME
, SUM(A3.TOTAL_UPLOAD) AS FINAL_UPLOAD
, SUM(A3.TOTAL_DOWNLOAD) AS FINAL_DOWNLOAD
FROM
( SELECT
A1.USERNAME
, DATE_FORMAT(FROM_UNIXTIME(A1.TIME_STAMP),'%Y-%m-%d') AS DTTM
, A1.ACCTSESSIONID
, MAX(IFNULL(A1.ACCTINPUTGW,0) * POW(2,32) + IFNULL(A1.ACCTINPUTOCT, 0))
- MAX(IFNULL(A2.ACCTINPUTGW,0) * POW(2,32) + IFNULL(A2.ACCTINPUTOCT, 0))
AS TOTAL_UPLOAD
, MAX(IFNULL(A1.ACCTOUTPUTGW,0) * POW(2,32) + IFNULL(A1.ACCTOUTPUTOCT, 0))
- MAX(IFNULL(A2.ACCTOUTPUTGW,0) * POW(2,32) + IFNULL(A2.ACCTOUTPUTOCT, 0))
AS TOTAL_DOWNLOAD
FROM ACCOUNTING A1
LEFT JOIN ACCOUNTING A2
ON A1.ACCTSESSIONID = A2.ACCTSESSIONID
AND DATE_FORMAT(FROM_UNIXTIME(A2.TIME_STAMP), '%Y-%m-%d') = '2011-07-04'
WHERE DATE_FORMAT(FROM_UNIXTIME(A1.TIME_STAMP), '%Y-%m-%d') = '2011-07-05'
GROUP BY A1.ACCTSESSIONID,A2.ACCTSESSIONID
ORDER BY A1.USERNAME
) AS A3
GROUP BY A3.USERNAME