I currently have a query where I’m doing two subqueries to get X, Y data:
SELECT t.series AS week, ( ... ) X, ( ..., AND ... ) Y, ROUND(( ... ) * 100) / ( ..., AND ... ), 2) Z FROM series_tmp t
Y is kind of subset of X, since I apply just an additional condition to the existing ones, if X is:
SELECT COUNT(*) FROM t1 INNER JOIN t2 ON t2.id = t1.another_id WHERE t2.something = 1 AND t1.date BETWEEN t.series AND t.series + INTERVAL 6 DAY
Then Y has an additional AND condition:
SELECT COUNT(*) FROM t1 INNER JOIN t2 ON t2.id = t1.another_id WHERE t2.something = 1 AND t1.date BETWEEN t.series AND t.series + INTERVAL 6 DAY AND t1.some_state = 'x state'
And for the value of X I need to take those two results – X and Y and do some calculation. Since I can’t use the aliases, I have to use a subquery, right? But in that case it seems too much.
Is there a way to reuse those subqueries? It seems to be too much of the same.
series_tmp
is a temporary table used to create a range of dates with a specific step:
CALL generate_series(DATE('2020-08-23' - INTERVAL 12 WEEK), '2020-08-23', 'INTERVAL 7 DAY'); SELECT * FROM series_tmp; '2020-05-31' '2020-06-07' '2020-06-14' '2020-06-21' '2020-06-28' '2020-07-05' '2020-07-12' '2020-07-19' '2020-07-26' '2020-08-02' '2020-08-09' '2020-08-16' '2020-08-23'
The INNER JOIN
used is the only one in the query which is just used to compare against primary/foreign key to further filter by the value of t2.something
(t2.something = 1
).
The columns I’m using from t1 are just date
and some_state
, the count is performed using the wildcard.
This is to reproduce the scenario:
DROP TABLE IF EXISTS t3; CREATE TABLE t3 ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (id) ); DROP TABLE IF EXISTS t2; CREATE TABLE t2 ( id int(11) NOT NULL AUTO_INCREMENT, t3_id int(11) NOT NULL, PRIMARY KEY (id) ); DROP TABLE IF EXISTS t1; CREATE TABLE t1 ( id int(11) NOT NULL AUTO_INCREMENT, t2_id int(11) NOT NULL, created_at datetime NOT NULL, status varchar(255) COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (id) ); INSERT INTO t3 (name) VALUES ('t3 #1'); INSERT INTO t2 (t3_id) VALUES (1); INSERT INTO t1 (t2_id, status, created_at) VALUES ('1', 'sent', '2020-06-03 00:00:00'), ('1', 'sent', '2020-06-08 00:00:00'), ('1', 'sent', '2020-06-19 00:00:00'), ('1', 'responded', '2020-06-26 00:00:00'), ('1', 'responded', '2020-06-27 00:00:00'), ('1', 'sent', '2020-06-30 00:00:00'), ('1', 'sent', '2020-07-08 00:00:00'), ('1', 'sent', '2020-07-09 00:00:00'), ('1', 'responded', '2020-07-14 00:00:00'), ('1', 'sent', '2020-07-21 00:00:00'), ('1', 'sent', '2020-07-22 00:00:00'), ('1', 'sent', '2020-07-25 00:00:00'), ('1', 'responded', '2020-07-30 00:00:00'), ('1', 'sent', '2020-08-02 00:00:00'), ('1', 'sent', '2020-08-10 00:00:00'), ('1', 'responded', '2020-08-18 00:00:00'), ('1', 'responded', '2020-08-19 00:00:00'); -- expected result would be: -- '2020-05-31','1','0','0.00' -- '2020-06-07','1','0','0.00' -- '2020-06-14','1','0','0.00' -- '2020-06-21','2','2','100.00' -- '2020-06-28','1','0','0.00' -- '2020-07-05','2','0','0.00' -- '2020-07-12','1','1','100.00' -- '2020-07-19','3','0','0.00' -- '2020-07-26','1','1','100.00' -- '2020-08-02','1','0','0.00' -- '2020-08-09','1','0','0.00' -- '2020-08-16','2','2','100.00'
The SQLfiddle http://sqlfiddle.com/#!9/45f389.
I’m using MySQL 5.6 so I’m not able to use CTEs 🙁
PS: series_tmp
comes from [this].
Advertisement
Answer
You can’t use CTEs in MySQL* but you can use temporary tables which is a close MySQL equivalent (not sure how you calculate Z so I didn’t put that one in):
CREATE TEMPORARY TABLE temp_t3 AS ( SELECT t1.created_at, t1.status FROM t1 INNER JOIN t2 ON t2_id = t2.id WHERE t2.t3_id = 1 ); SELECT t.series AS week, (SELECT COUNT(*) FROM temp_t3 WHERE created_at BETWEEN t.series AND t.series + INTERVAL 6 DAY) X, (SELECT COUNT(*) FROM temp_t3 WHERE created_at BETWEEN t.series AND t.series + INTERVAL 6 DAY AND status = 'responded') Y FROM series_tmp t;
*prior to version 8 (https://dev.mysql.com/doc/refman/8.0/en/with.html)