UNION ignores column names? - mysql

Why does
select 1 as a, 2 as b
union all
select 20 as b, 10 as a
returns
a b
1 2
20 10
instead of
a b
1 2
10 20
?
Is there a way to make union match column names?

Nope, selecting them in order is required with UNION.

Column names are only pertinent for the first part of the union to deifne the union columns. Other unions will join in the same order the columns are given from the first select and often have differn names. If you want want to relate the first column to the second column, You can't. However you can adjust your second select statment to put the columns in the correct order.

Union only looks at the number of columns, and their relative positions in the query string. it does NOT mix-match based on aliases or the source column names. e.g. You could have two completely different tables:
SELECT x,y FROM foo
UNION
SELECT p,q FROM bar
What should MySQL do in this case? return a single row
x,y,p,q
because none of the column names match? Nope. That'd be incorrect.

I'm not sure if this solves your problem, but you can use subqueries within the union to put the columns in the "right" order:
(select a, b from (select 1 as a, 2 as b) t)
union all
(select a, b from (select 20 as b, 10 as a) t)
I realize the question is tagged MySQL, which doesn't support full outer join. If it did, you could do do the union all as:
select coalesce(t1.a, t2.a) as a, coalesce(t1.b, t2.b) as b
from (select 1 as a, 2 as b) t1 full outer join
(select 20 as b, 10 as a) t2
on 0 = 1;
You can do this in MySQL. This assumes that none of your values are never NULL:
select coalesce(t1.a, t2.a) as a, coalesce(t1.b, t2.b) as b
from (select 1 as a, 2 as b union all select NULL, NULL) t1 join
(select 20 as b, 10 as a union all select NULL, NULL) t2
on (t1.a is null or t2.a is null) and coalesce(t1.a, t2.a) is not null

Related

MySQL select unique pairs

My table looks like:
id A B
1 1 3
2 2 3
3 3 1
I want SELECT only unique AB pairs
13 is unique
23 is unique
31 not unique because pair 13 exists
Trying with SELECT a, b FROM test GROUP BY a, b but query return 3 pairs
You can use least() and greatest() functions both in SELECT-list and GROUP BY expression :
SELECT least(a, b) , greatest (a,b)
FROM test
GROUP BY least(a, b) , greatest (a,b)
Demo
Or just use DISTINCT within the SELECT-list :
SELECT DISTINCT least(a, b) , greatest (a,b)
FROM test
Below query may use indices.
SELECT DISTINCT a, b
FROM test
WHERE a >= b
UNION ALL
SELECT DISTINCT a, b
FROM test t1
WHERE a < b
AND NOT EXISTS ( SELECT NULL
FROM test t2
WHERE (t1.a, t1.b) = (t2.b, t2.a) )
Demo

Mysql Count multiple columns based on the same values

I have the following like table
A B
Yes OOS
No No
OOS Yes
OOS No
Yes No
I want to do the following
Criteria A B
Yes 2 1
No 1 3
OOS 2 1
I can get this right with one column like
Criteria A
Yes 2
No 1
OOS 2
Here is what I have to achieve the above:
SELECT A, count(A) FROM temp_db GROUP BY A;
For this sample data, you could do this with a join of derived tables:
SELECT qa.Criteria, qa.A, qb.B FROM
(SELECT A AS Criteria, count(A) AS A FROM temp_db GROUP BY A) qa
FULL OUTER JOIN
(SELECT B AS Criteria, count(B) AS B FROM temp_db GROUP BY B) qb
ON qa.Criteria=qb.Criteria
But if there are missing criteria in the A column, they will not appear in the results of this query, and you would need the UNION ALL approach others have suggested.
You need to get the values into a single column, so you can use group by. Here is one method:
select criteria, sum(A) as A, sum(B) as B
from ((select A as criteria, 1 as A, 0 as B
from liketable
) union all
(select B, 0, 1
from liketable
)
) t
group by criteria;
Using the union all approach is the safest way in MySQL, in case not all criteria are in both columns. The following is a slight tweak that might be a bit better performance-wise:
select criteria, sum(A) as A, sum(B) as B
from ((select A as criteria, count(*) as A, 0 as B
from liketable
group by A
) union all
(select B, 0, count(*)
from liketable
group by B
)
) t
group by criteria;
Often doing two aggregations on half the data is more efficient than a bigger aggregation on all the data.
select val, sum(cntA), sum(cntB)
from (SELECT A as val, count(A) as cntA, 0 as cntB FROM temp_db GROUP BY A;
union all
SELECT B as val, 0 as cntA, count(B) as cntB FROM temp_db GROUP BY B)
group by val;

GROUP_CONCAT on two tables

I have two tables, with independent ids (can't be connected via joins), I want to query and get a GROUP_CONCAT of both columns.
Example: table "a" has ids: 1, 2, 3. table "b" has the ids: 10, 11.
End result should be: 1, 2, 3, 10, 11
I have tried a few queries:
SELECT CONCAT_WS(',', GROUP_CONCAT(a.id), GROUP_CONCAT(b.id)) AS combined FROM a, b
SELECT GROUP_CONCAT(a.id, b.id) AS combined FROM a, b
These queries are returning me duplicate results though 8as in, all results from a twice and all results from b twice as well)
Try union all:
select group_concat(ab.id) as ids
from ((select id from a
) union all
(select id from b
)
) ab;
Your queries are doing cross join's between the tables, so data after the cross join is:
a.id b.id
1 10
1 11
2 10
2 11
3 10
3 11
After the union all, the data is:
ab.id
1
2
3
10
11
GROUP_CONCAT(DISTINCT [])
will help
https://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat
The following query will generate that you want.
You can play with the table_position dynamic column for deciding which table goes first.
Select group_concat(id order by table_position) from
(
select id, 1 as table_position from a
union all
select id, 2 as table_position from b
)
If you want duplicates, use union all. If you don't want duplicates, use union.
In either case, the query you need is as follows:
select group_concat(id) from
(select id from a
union
select id from b) as ids;

MySQL union all remove duplicates

I want to optimyse my query (not the results) to remove redundant data, make it easy to read and update when I need to.
Table:
A, B, C
1 B1 1.99
2 B2 6.99
3 B3 7.99
I have a query that looks like:
SELECT A, B FROM TABLE
UNION ALL
SELECT A, C FROM TABLE
UNION ALL
SELECT A, 'string' FROM TABLE;
In this instance A is redundant in my query, as it is written multiple times. How can I make this query to have it only once? Thanks.
EDIT: I want to see EXACTLY the same result but SQL code to refer to column A only once.
The following code:
SELECT A, B FROM TABLE
UNION ALL
SELECT A, C FROM TABLE
UNION ALL
SELECT A, 'string' FROM TABLE;
Reads from table three times. It actually can be optimized:
select A,
(case when n = 1 then B
when n = 2 then C
when n = 3 then 'string'
end) as B
from TABLE cross join
(select 1 as n union all select 2 union all select 3) n;
The SQL engine would normally scan TABLE only once for this query, looping through the 3 rows in n. This could be a performance improvement.

How to address multiple columns as one in MySQL?

Columns a, b and c contain some values of the same nature. I need to select all the unique values. If I had just one column I'd use something like
SELECT DISTINCT a FROM mytable ORDER BY a;
but I need to treat a, b and c columns as one and gett all the unique values ever occurring among them.
As an example, let this be a CSV representation of mytable, the first row naming the columns:
a, b, c
1, 2, 3
1, 3, 4
5, 7, 1
The result of the query is to be:
1
2
3
4
5
7
UPDATE: I don't understand why do all of you suggest wrapping it in an extra SELECT? It seems to me that the answer is
(SELECT `a` AS `result` FROM `mytable`)
UNION (SELECT `b` FROM `mytable`)
UNION (SELECT `c` FROM `mytable`)
ORDER BY `result`;
isn't it?
So you want one column all with unique values from a, b and c? Try this:
(select a as yourField from d1)
union
(select b from d2)
union
(select c from d3)
order by yourField desc
limit 5
Working example
Edited after requirements changed... There you have the order by and limit you requested. Of course, you'll get only 5 records in this example
sorry i miss understood your question. here is updated query.
select a from my table
UNION
select b from my table
UNION
select c from my table
SELECT tmp.a
FROM
(SELECT column_1 AS a
FROM table
UNION
SELECT column_2 AS a
FROM table
UNION
SELECT column_3 AS a
FROM table) AS tmp
ORDER BY `tmp`.`a` ASC
try this:
SELECT b.iResult
FROM
(SELECT a as iResult FROM tableName
UNION
SELECT b as iResult FROM tableName
UNION
SELECT c as iResult FROM tableName) b
ORDER BY b.iResult
LIMIT BY 10 -- or put any number you want to limit.