MySQL 8 Recursive CTE Error Code: 1054. Unknown column - mysql

This MySQL 8 query:
WITH RECURSIVE cte_count (n)
AS (
SELECT 1
UNION ALL
SELECT
n + 1
FROM cte_count
WHERE n < 3
)
SELECT *
FROM cte_count;
Produces:
+------+
| n |
+------+
| 1 |
| 2 |
| 3 |
+------+
But this one:
WITH RECURSIVE cte_count (n)
AS (
SELECT 1
,"one" as `one`
UNION ALL
SELECT
n + 1
,"one" as `one`
FROM cte_count
WHERE n < 3
)
SELECT *
FROM cte_count;
generates the error:
Error Code: 1054. Unknown column 'n' in 'field list'
Can you explain why and how to solve that error?
What is the meaning of (n) after WITH RECURSIVE cte_count?

There are 2 ways that you can write this.
Without declaring the column names alongside with the cte's name:
WITH RECURSIVE cte_count
AS (
SELECT 1 as n
,'one' as `one`
UNION ALL
SELECT
n + 1
,'one'
FROM cte_count
WHERE n < 3
)
SELECT *
FROM cte_count;
and declaring them without the need to alias them inside the query's body:
WITH RECURSIVE cte_count (n, `one`)
AS (
SELECT 1
,'one'
UNION ALL
SELECT
n + 1
,'one'
FROM cte_count
WHERE n < 3
)
SELECT *
FROM cte_count;

You can look at WITH RECURSIVE cte_count (n) in a more abstract way.
You always need WITH RECURSIVE for your recursive query followed by a name for it (in your case cte_count).
What follows next is a comma separated list which defines the number of attributes for your query as well as the respective names for your columns (e.g. (n)).
The problem in the second query is that you introduced a new column with "one" as 'one'.
Try to only write "one" instead of "one" as 'one' (both times!) and make (n) to (n, one) to fix your problem.

Related

Mysql: insert multiple values with order number

I want to split a string like ('abc', 'dev', dfg') and insert into a table with its order number like that:
index value
1 abc
2 dev
3 dfg
Is anyway I can do this in mysql? The size is unknown.
You probably can do something like this:
WITH RECURSIVE cte AS (
SELECT 1 idx, LENGTH(REGEXP_REPLACE(stringVal,'[^,]',''))+1 AS maxLen
FROM mytable UNION
SELECT idx+1, maxLen FROM cte WHERE idx+1 <= maxLen)
SELECT idx,
SUBSTRING_INDEX(SUBSTRING_INDEX(stringVal,',',idx),',',-1) AS val
FROM cte
CROSS JOIN mytable;
Generating idx using cte based on how many strings were separated by comma in the column. The steps are:
Use REGEXP_REPLACE() to replace any value that is not comma; returns ,,.
Use LENGTH() on the regexp to get the total of comma; returns 2.
Add 1 (+1) to the length result returned; final value 3.
The cte result are:
+-----+--------+
| idx | maxLen |
+-----+--------+
| 1 | 3 |
| 2 | 3 |
| 3 | 3 |
+-----+--------+
From the generated cte , we're going to use idx value with SUBSTRING_INDEX() to separate the comma-separated, single-row string into multiple rows.
Understanding what the query is doing:
This, we can emulate with 3 of the same query repeated UNION ALL together like the following:
SELECT 1 AS 'index',
SUBSTRING_INDEX(SUBSTRING_INDEX(stringVal,',',1),',',-1) AS val
FROM mytable
UNION ALL
SELECT 2,
SUBSTRING_INDEX(SUBSTRING_INDEX(stringVal,',',2),',',-1)
FROM mytable
UNION ALL
SELECT 3,
SUBSTRING_INDEX(SUBSTRING_INDEX(stringVal,',',3),',',-1)
FROM mytable;
Which also can be done as such; Same idea as the cte approach:
SELECT idx,
SUBSTRING_INDEX(SUBSTRING_INDEX(stringVal,',',idx),',',-1) AS val
FROM (SELECT 1 idx UNION
SELECT 2 UNION
SELECT 3 ) i
CROSS JOIN mytable;
Both of these query return the same result as the cte approach however it's not an ideal one; since we have to manually check how many string separated by comma and define (hard-code) it in the query. Imagine if a single row of string consists of something like a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z - all the 26 alphabet; then that means the UNION query need to be repeated 26 times.
Demo fiddle

way to populate number of rows in mysql without selecting table

I am looking for a way to populate values in row in mysql
for example if i execute query
select 1,2,3,4
it gives response
+---+---+---+---+
| 1 | 2 | 3 | 4 |
+---+---+---+---+
| 1 | 2 | 3 | 4 |
+---+---+---+---+
that is in row
is there a possible way to produce this data in column
like
1
2
3
4
With the introduction of Recursive with clause in MySQL version 8.0 or higher, We now have a row generator in MySQL -
WITH RECURSIVE cte_count (n)
AS (
SELECT 1
UNION ALL
SELECT n + 1
FROM cte_count
WHERE n < 100
)
SELECT n
FROM cte_count;
Before version 8.0 MySQL doesn't have any inbuilt row_generator functionality.
If you want values in a column, you can use:
select 1 as n union all
select 2 as n union all
select 3 as n union all
select 4 as n
This construct is often used in derived tables (or more recently in CTEs).
If you just need a set number of values, then an existing table (that is big enough) can be used:
select (#rn := #rn + 1) as n
from t cross join
(select #rn := 0) params
limit 4;

what is mysql query to print 1 to 10?

I know there is sql query to print count from 1 to 10 as below:
select rownum from dual where rownum<=10;
In the same way i am trying in the mysql but it is throwing error "Unknown column rownum in field list". So, It would be great if anyone provide me the mysql query to perform the same operation. Thanks in advance.
In MySQL 8+ you can use a recursive CTE to do this:
WITH RECURSIVE cte AS (
SELECT 1 AS n
UNION ALL
SELECT n + 1 FROM cte WHERE n < 10
)
SELECT n FROM cte
Output:
n
1
2
3
4
5
6
7
8
9
10
Demo on dbfiddle
There is no straightforward way to do this in MySQL.
MySQL does not fully support the DUAL table. It can be used as a placeholder table in certain queries which do not require a table, but it does not have the same behavior as the DUAL table in other database servers -- it will only ever return one row, even if more rows are requested:
mysql> SELECT ROW_NUMBER() OVER() FROM DUAL LIMIT 10;
+---------------------+
| row_number() over() |
+---------------------+
| 1 |
+---------------------+
mysql> SELECT ROW_NUMBER() OVER() FROM DUAL WHERE ROW_NUMBER() OVER() < 10;
ERROR 3593 (HY000): You cannot use the window function 'row_number' in this context.'
(Yes, there's really a stray apostrophe at the end of that error message.)
There is one really dumb way of creating a sequence:
mysql> SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5;
+---+
| 1 |
+---+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+---+
5 rows in set (0.00 sec)
Obviously, this gets unwieldy for large sequences, but it's about the best you'll get in stock MySQL. (Some of the forks, like MariaDB, have some features which can be used for this.)
Using the table function (the method for creating a temporary table only for the current query): like numbers function which will print 1 to 10:
SELECT * FROM numbers(1, 10);
By using below query you can get 1 to 10.
Sequence of 10 numbers
select * from (select 1 x 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 10) A
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=1f8b71c1fef4b8e0350f2b28eb15c3be

SELECT SUM(1) FROM ( SELECT '0' as R FROM dual UNION ALL SELECT '1' as R FROM dual )

Why the following query giving value 2 instead of my expectation 1?
SELECT SUM(1) FROM (
SELECT '0' as R FROM dual
UNION
SELECT '1' as R FROM dual
)
But this query satisfying the expectation?
SELECT SUM(R) FROM (
SELECT '0' as R FROM dual
UNION
SELECT '1' as R FROM dual
)
Because in the first query you're summing 1 for each occurrence of any row in the selection, yet for query 1 you're summing whatever the value of 'R' is for each row in the selection.
SUM(1) in the first query is equivalent to COUNT(*):
SELECT COUNT(*) FROM ...
because it adds 1 to the total for each row of the FROM table, regardless of the content of that row.
The second query pays attention to the value of R, so it adds 1 to 0, and arrives at zero.
When you do SELECT 1 you are extracting the hardcoded value 1 and not, as you likely expected, the first column; your query is
SQL> SELECT 1
2 FROM (SELECT '0' AS R FROM DUAL
3 UNION
4 SELECT '1' AS R FROM DUAL
5 );
1
----------
1
1
that is two rows containing 1; the SUM of these rows gives 2:
SQL> SELECT SUM(1)
2 FROM (SELECT '0' AS R FROM DUAL
3 UNION
4 SELECT '1' AS R FROM DUAL
5 );
SUM(1)
----------
2
For example, you can try
SQL> select 100
2 from ( select 1 from dual);
100
----------
100
this clarifies that select 100 does not look for the 100th column of the internal query, but simply gives the value 100.
In the following query you are extracting a variable value in R ( I edited the strings into numbers); in your query you have two rows like the following, where R is 0 in a row and 1 in the other one:
SQL> SELECT R
2 FROM (SELECT 0 AS R FROM DUAL
3 UNION
4 SELECT 1 AS R FROM DUAL
5 );
R
----------
0
1
The SUM of these two values is 0 + 1 = 1:
SQL> SELECT SUM(R)
2 FROM (SELECT 0 AS R FROM DUAL
3 UNION
4 SELECT 1 AS R FROM DUAL
5 );
SUM(R)
----------
1
SQL>
The first query is summing 1 for each record exists in the inner query. That is because you summed by a constant value : SUM(1) which will basically return the same result as COUNT(*)/COUNT(1) .
The second query is summing the values of R columns -> 0 and 1 which is equal to 1.

SQL split comma separated row [duplicate]

This question already has answers here:
MySQL: Split comma separated list into multiple rows
(4 answers)
Closed 9 years ago.
I have a column with a variable number of comma seperated values:
somethingA,somethingB,somethingC
somethingElseA, somethingElseB
And I want the result to take each value, and create a row:
somethingA
somethingB
somethingC
somethingElseA
somethingElseB
How can I do this in SQL (MySQL)?
(I've tried googling "implode" and "lateral view", but those don't seem to turn up related questions. All the related SO questions are trying to do much more complicated things)
You can do it with pure SQL like this
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(t.values, ',', n.n), ',', -1) value
FROM table1 t CROSS JOIN
(
SELECT a.N + b.N * 10 + 1 n
FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
ORDER BY n
) n
WHERE n.n <= 1 + (LENGTH(t.values) - LENGTH(REPLACE(t.values, ',', '')))
ORDER BY value
Note: The trick is to leverage tally(numbers) table and a very handy in this case MySQL function SUBSTRING_INDEX(). If you do a lot of such queries (splitting) then you might consider to populate and use a persisted tally table instead of generating it on fly with a subquery like in this example. The subquery in this example generates a sequence of numbers from 1 to 100 effectively allowing you split up to 100 delimited values per row in source table. If you need more or less you can easily adjust it.
Output:
| VALUE |
|----------------|
| somethingA |
| somethingB |
| somethingC |
| somethingElseA |
| somethingElseB |
Here is SQLFiddle demo
This is how the query might look with a persisted tally table
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(t.values, ',', n.n), ',', -1) value
FROM table1 t CROSS JOIN tally n
WHERE n.n <= 1 + (LENGTH(t.values) - LENGTH(REPLACE(t.values, ',', '')))
ORDER BY value
Here is SQLFiddle demo