Reputation: 67
I am attempting to run a CTE statement in MySQL, and I am getting an error on the line that holds the WITH. This is my full syntax, what do I need to change so this query executes like I wish.
And this is the error that I receive:
Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) AS numbers(number) ), cte_tally10' at line 7
SET @v_start_date = '20190101';
SET @v_number_of_months = 12;
WITH
cte_input_values AS (
SELECT CAST(TIMESTAMPADD(MONTH, TIMESTAMPDIFF(MONTH, 0, @v_start_date), 0) AS date) AS start_date
),
cte_tally10 AS (
SELECT * FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) AS numbers(number)
),
cte_tally100 AS (
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) - 1 AS month_number
FROM cte_tally10 c1
CROSS JOIN cte_tally10 c2
),
cte_months_to_pull AS (
SELECT TIMESTAMPADD(MONTH, t.month_number, start_date) AS month_to_pull
FROM cte_tally100 t
CROSS JOIN cte_input_values
WHERE t.month_number BETWEEN 0 AND @v_number_of_months - 1
UNION ALL
SELECT TIMESTAMPADD(MONTH, t.month_number, TIMESTAMPADD(YEAR, -1, start_date)) AS month_to_pull
FROM cte_tally100 t
CROSS JOIN cte_input_values
WHERE t.month_number BETWEEN 0 AND @v_number_of_months - 1
)
SELECT
INSERT(DATE_FORMAT (month_to_pull, 7), 4, 4, '') AS month_year,
IFNULL(YRS.SaleAmount, 0) AS total_sales
FROM cte_months_to_pull
LEFT OUTER JOIN (
SELECT TIMESTAMPADD(MONTH, TIMESTAMPDIFF(MONTH, 0, SaleDate), 0) AS SaleMonth,
SUM(SaleAmount) AS SaleAmount
FROM CurrentYear
CROSS JOIN cte_input_values
WHERE SaleDate >= start_date AND
SaleDate < TIMESTAMPADD(MONTH, @v_number_of_months, start_date)
GROUP BY TIMESTAMPADD(MONTH, TIMESTAMPDIFF(MONTH, 0, SaleDate), 0)
UNION ALL
SELECT TIMESTAMPADD(MONTH, TIMESTAMPDIFF(MONTH, 0, SaleDate), 0) AS SaleMonth,
SUM(SaleAmount) AS SaleAmount
FROM PrevYear
CROSS JOIN cte_input_values
WHERE SaleDate >= TIMESTAMPADD(YEAR, -1, start_date) AND
SaleDate < TIMESTAMPADD(MONTH, @v_number_of_months, TIMESTAMPADD(YEAR, -1, start_date))
GROUP BY TIMESTAMPADD(MONTH, TIMESTAMPDIFF(MONTH, 0, SaleDate), 0)
) AS YRS ON SaleMonth = month_to_pull
ORDER BY MONTH(month_to_pull), YEAR(month_to_pull)
Upvotes: 2
Views: 1951
Reputation: 31812
MySQL doesn't support inline table construction with VALUES
. It's though supported by MariaDB
However - As I see, you only need it for cte_tally100
to generate sequence numbers from 0 to 99. But there is a better way to achieve that. See the first example for Recursive Common Table Expressions. The query would be:
with recursive cte_tally100 as (
select 0 as month_number
union all
select month_number + 1
from cte_tally100
where month_number < 99
)
...
If you only need numbers from 0 to 11 - change the WHERE clause to
where month_number < 11
To get 12 next and 12 previous months, you can use:
SET @start_date = '20190102';
SET @number_of_months = 12;
WITH RECURSIVE
cte_input_values AS (
# insure @start_date is the first day of the month
SELECT DATE_FORMAT(@start_date, '%Y-%m-01') AS start_date
),
cte_tally12 AS (
SELECT 0 as month_number
UNION ALL
SELECT month_number + 1
FROM cte_tally12
WHERE month_number < @number_of_months - 1
),
cte_months_to_pull AS (
SELECT start_date + INTERVAL t.month_number MONTH AS month_to_pull
FROM cte_tally12 t
CROSS JOIN cte_input_values
WHERE t.month_number BETWEEN 0 AND @number_of_months - 1
UNION ALL
SELECT start_date - INTERVAL 1 YEAR + INTERVAL t.month_number MONTH AS month_to_pull
FROM cte_tally12 t
CROSS JOIN cte_input_values
WHERE t.month_number BETWEEN 0 AND @number_of_months - 1
)
SELECT *
FROM cte_months_to_pull
That can also be done with a single (recursive) CTE:
SET @start_date = '20190102';
SET @number_of_months = 12;
WITH RECURSIVE
cte_months_to_pull AS (
# insure @start_date is the first day of the month
SELECT DATE_FORMAT(@start_date, '%Y-%m-01')
- INTERVAL @number_of_months MONTH AS month_to_pull
UNION ALL
SELECT month_to_pull + INTERVAL 1 MONTH
FROM cte_months_to_pull
WHERE month_to_pull < @start_date + INTERVAL @number_of_months - 2 MONTH
)
SELECT *
FROM cte_months_to_pull
Now you can use cte_months_to_pull
for your LEFT JOIN.
Upvotes: 0
Reputation: 15961
I could be mistaken, but I don't think MySQL supports that form of VALUES
; typically you'd do something like
SELECT * FROM (SELECT 0 AS number UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0) AS numbers
Upvotes: 2