How is possible to reference an external field from a nested subquery?
I'll explain better very fastly with an example:
SELECT
x
, (SELECT t1.x) as x1
/*, (SELECT x FROM (SELECT t1.x) as t2) as x2*/
FROM
(SELECT 1 as x UNION SELECT 2 as x UNION SELECT 3 as x) as t1;
If I uncomment the commented subquery, I get a "Unknown table 't1' in field list" error but I need to refer for a complex calculation to that variable from a 2-level nested subquery (it's not possible to do with a Join).
This is not possible according to MySQL manual. You can try using VIEWs instead of derived tables or list all your derived tables in the outermost FROM clause
You can't use table alias in subquery, because it is out of scope. You should (eventually) recode the subquery like this:
SELECT
x,
t1.x as x1,
(SELECT x
FROM (SELECT 1 as x
UNION
SELECT 2 as x
UNION SELECT 3 as x) as t2) as x2
FROM
(SELECT 1 as x
UNION
SELECT 2 as x
UNION
SELECT 3 as x) as t1;
or create a proper view and use the view for access to the data
create view my_view as
SELECT 1 as x
UNION
SELECT 2
UNION
SELECT 3
;
SELECT x
, t1.x as x1
, (SELECT x FROM my_view as t2) as x2
FROM my_view as t1
;
Related
The table contains json data and i wanted to extract labelKey from this json
table: d_json
data
{"tag":null,"options":[{"labelKey":"key10","value":"yes","selected":true},{"labelKey":"key11","value":"no","selected":false}]}
{"tag":null,"options":[{"labelKey":"key20","value":"yes","selected":true},{"labelKey":"key21","value":"no","selected":false},{"labelKey":"key22","value":"no","selected":false}]}
I used following query to extract "labelKey"
SELECT JSON_EXTRACT(JSON_EXTRACT(j.data,'$.options'),'$[*].labelKey') FROM d_json j AS result;
It returns following result
result
["key10", "key12"]
["key20", "key21", "key22"]
However i want result in flat, each row contains one element instead of array, such as
result
"key10"
"key11"
"key21"
"key22"
"key23"
Not getting any clue how to flatten resulted arrays
On mysql v8+, you can do that using JSON_TABLE function like this:
SELECT p.*
FROM d_json,
JSON_TABLE(data, '$.options[*]' COLUMNS (
labelKey VARCHAR(40) PATH '$.labelKey')
) p;
Result:
labelKey
key10
key11
key20
key21
key22
Here's a demo fiddle
Edit:
On older MySQL version, try this:
SELECT TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(val2,',',rn),',',-1))
FROM (SELECT 1 rn UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) AS r
CROSS JOIN
(SELECT REPLACE(REPLACE(GROUP_CONCAT(val),'[',''),']','') AS val2
FROM
(SELECT JSON_EXTRACT(JSON_EXTRACT(j.data,'$.options'),'$[*].labelKey') AS val
FROM d_json j) v1
) v2;
Demo fiddle
The idea is to CROSS JOIN with a sequence of row numbers then use that same sequence to extract from a GROUP_CONCAT values using SUBSTRING_INDEX. In the query example above, I'm using a hardcoded row sequences in the form of:
(SELECT 1 rn UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) AS r
Ideally, the best approach is to figure out the sequence required and generate it dynamically.
Update:
Generating numbering sequences on older MySQL version is a challenge especially if we're aiming for a dynamic generating. There's a method that is not dynamic but can generate a large numbering sequence from a very long query but if you're planning to be using this sequences for a long time, I suggest you just create a table for it:
CREATE TABLE number_seq (
sequences INT);
INSERT INTO number_seq
SELECT #row := #row + 1 AS rn FROM
(SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION
SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t1 CROSS JOIN
(SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION
SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t2 CROSS JOIN
(SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION
SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t3 CROSS JOIN
(SELECT #row:=0) numbers;
The query above will generate a range of numbers from 1-1000 and insert into a table. Once you have that table, you just need to write your query like this:
SELECT TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(val2,',',sequences),',',-1))
FROM (SELECT sequences FROM
(SELECT (LENGTH(val2)-LENGTH(REPLACE(val2,',','')))+1 AS valLen FROM
(SELECT REPLACE(REPLACE(GROUP_CONCAT(val),'[',''),']','') AS val2 FROM
(SELECT JSON_EXTRACT(JSON_EXTRACT(j.data,'$.options'),'$[*].labelKey') AS val
FROM d_json j) v1
) v2 ) v3 JOIN number_seq t ON sequences <= valLen) r
CROSS JOIN
(SELECT REPLACE(REPLACE(GROUP_CONCAT(val),'[',''),']','') AS val2
FROM
(SELECT JSON_EXTRACT(JSON_EXTRACT(j.data,'$.options'),'$[*].labelKey') AS val
FROM d_json j) v1
) v2;
The highlight of change from the previous query is the switch between the hardcoded numbering sequences with a query that basically get the total values separated by comma in the final JSON_EXTRACT and join it against the created number_seq table to get the rows needed. This part here:
SELECT sequences FROM
(SELECT (LENGTH(val2)-LENGTH(REPLACE(val2,',','')))+1 AS valLen FROM
(SELECT REPLACE(REPLACE(GROUP_CONCAT(val),'[',''),']','') AS val2 FROM
(SELECT JSON_EXTRACT(JSON_EXTRACT(j.data,'$.options'),'$[*].labelKey') AS val
FROM d_json j) v1
) v2 ) v3 JOIN number_seq t ON sequences <= valLen
Here's an updated fiddle for reference https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=ace8babce8d7bbb97f7e016a754e93a9
When I use
select if (1=1,'true','false');
then everything is ok and I receive 'true' but if I try
select if (1=1,(select * from table1), (select * from table2));`
I receive syntax error in mysql!
With
if condition then <SQL-Expression1> else <SQL-Expression2> end if;
I have the same problem, when the SQL-Expression is complex like
select * from table1!
If I use a complex SQL-Expression like
select * from table1
or
insert into table1 (select field1 from table2 where
field1>(select Max(field) from table1));
then I always receive a syntax error, when such a expression is included in an if/else-Statement!
How can I fit it, that complex sql-Statements can be choosed?
My problem is:
I made 2 tables like
create table1 (x1 int4, x2 int4, x3 int4);
create table2 (x int4);
insert into table1 values(1,2,3);
insert into table1 values(4,0,5);
I wanted to transponse table1 to table2
For example:
The result should in table2 like this
1
2
3
4
5
If I enlarge table 1 with a new line like
insert into table1 values (6,7,8);
then table2 should be changed to
1
2
3
4
5
6
7
8
I tried to make it in this way
select if ((select count(*) from table2)=0,
(insert into table2 (select x1 from table1 where x1>0)),
(insert into table2 (select x1 from table1 where
x1>(select Max(x) from table1))));
The same also with x2 and x3.
but syntax errors occur!
If I use only
insert into table2 (select x1 from table1 where x1>(select Max(x) from table1));
then it works if table1 ist not empty otherwise I had to do
insert into table2 (select x1 from table1 where x1>0);
Subqueries in the SELECT clause may only return single values; i.e. not more than one result, and not more than one column. You can't "trick" a query into returning a varying number of columns.
Also, the if-then form of "if" is reserved for procedural sql; used in stored procedures, triggers, etc...
I have this two queries and I want to sum their results in one query, but union all is not working.
I use this query:
select sum(a.value1) from myTable a
and I get: 10, then I use this query
select b.value2*b.value3 from myTable b
and I get:10,I want to sum them and get 20, so I use union:
select sum(a.value1) from myTable a
union all
select b.value2*b.value3 from myTable b
But the query returns
10
10
How I can sum them to get 20?
You could do this:
select ((select sum(a.value1) from myTable a) +
(select b.value2*b.value3 from myTable b)
) as sum
Hope this helps!!
select (sum(a.value1)+(select sum(b.value2*b.value3) from myTable b )) as test from myTable a
I finnaly could using this query:
select a.value4 + b.value5
from (select sum(a.value1) value4 from myTable) a,
(select b.value2 * b.value3 value5 from myTable) b
Ok, here's the query (pseudo-query):
SELECT *, (t1.field + t2.field) as 'result', (t1.field * t2.field) as result2 from((select as t1 limit 1) UNION ALL (select as t2 limit 1))
I need both rows returned, then do the math on the two fields into the result aliases. I know it's not graceful, but I have to kludge two queries together (the first is the union, and the second is the math)
So, how do I reference and use those two inner aliases? The inner aliases aren't accessible to the outer select.
I have a suspicion there's an obvious solution here that my brain is missing.
When you union two statements together your result is a single resultset. What you'll build:
FROM
(
(SELECT f1, f2 FROM table1 LIMIT 1)
UNION
(SELECT g1, g2 FROM table2 LIMIT 1)
) derived_table_1
This will give you a single result set named derived_table_ with two fields named f1 and f2 respectively. There will be two rows, one from your first SELECT statement and another from your second. The table aliases that you assigned inside your UNION query are no longer referencable. They exist only within their own SELECT statements.
If you have a relationship between Table1 and Table2 then you want a JOIN here:
SELECT
t1.f1 + t2.g1 as result1,
t1.f2 + t2.g2 as result2,
FROM
table1 as t1
INNER JOIN table2 as t2 ON
t1.f1 = t2.g1
If, instead no relationship exists, then you are probably looking for you original, and kludgy, union with a SUM in the SELECT:
SELECT
sum(derived_table_1.f1) as result,
sum(derived_table_1.f2) as result2
FROM
(
(SELECT f1, f2 FROM table1 LIMIT 1)
UNION
(SELECT g1, g2 FROM table2 LIMIT 1)
) derived_table_1
Editted to add a SQLFIDDLE with the last example: http://sqlfiddle.com/#!2/c8707/10
The column names or aliases for the result of a UNION are always determined by the first query. The column names or aliases defined in the subsequent queries of the union are ignored.
Demo:
mysql> create table foo ( a int, b int, c int );
mysql> insert into foo values (1,2,3);
mysql> create table bar (x int, y int, z int);
mysql> insert into bar values (4,5,6);
mysql> select a, b, c from (select a, b, c from foo union select x, y, z from bar) as t;
+------+------+------+
| a | b | c |
+------+------+------+
| 1 | 2 | 3 |
| 4 | 5 | 6 |
+------+------+------+
mysql> select x from (select a, b, c from foo union select x, y, z from bar) as t;
ERROR 1054 (42S22): Unknown column 'x' in 'field list'
There are plenty of questions with similar titles, but I haven't been able to find an answer that doesn't involve group by (GROUP BY x HAVING COUNT(*) > 1), but what I'm looking for is a query that returns all rows ungrouped (in MySQL).
Say I have the following:
id data
1 x
2 y
3 y
4 z
What I want the query to return is:
2 y
3 y
based on the fact that rows 2 and 3 have identical values in the data column.
SELECT * FROM table WHERE [data contains a value that exists in some other row as well]
You have to put it in a subquery
select * from table where data in (
select data from table group by data having count(*) > 1
)
see it working live in an sqlfiddle
SELECT DISTINCT x.*
FROM table1 x
JOIN table1 y
ON y.id <> x.id -- ids are NOT equal
AND y.data = x.data; -- but data IS
http://sqlfiddle.com/#!2/f8910
This query and fP's above are probably roughly equivalent in terms of performace - but rewrite fP's this way and watch it go...
SELECT DISTINCT x.id
FROM table1 x
JOIN
( SELECT data FROM table1 GROUP BY data HAVING COUNT(0) > 1 ) y
ON y.data = x.data;