What is wrong with my SQL query which uses Joins and Unions? - mysql

What's wrong with my sql query? I am trying to use a Join and at the same time a UNION to get all table from another table while joining other tables together based on a relationship ..
However I get the following error:
"The used SELECT statements have a different number of columns"
My query:
SELECT a.ESN, a.UnixTime, a.Payload, a.Timestamp
,b.AlarmingStatus
,b.STxModel
,c.GroupID
FROM STxMessage a
JOIN STx b ON b.ESN = a.ESN
JOIN GroupInfo c ON b.GroupID = c.GroupID
WHERE b.STxModel = 190
AND a.AlarmsChecked="y"
AND c.AlertsMasterSwitch="on"
UNION ALL
SELECT d.ESN , d.UnixTime, d.Payload, d.Timestamp FROM STxMessageArchive d

The error message says it all.
When using UNION, the columns return by the combined SELECT statement must be the same, eg.
SELECT col1, col2, col3 FROM table1
UNION
SELECT col1, col2, col3 FROM table2
if the columns do not match, you can still combine it provided that you have to provide dummy data for the column, eg
SELECT col1, col2, col3 FROM table1
UNION
SELECT col1, col2, '' AS col3 FROM table2
so in your query, it should look like this
SELECT a.ESN, a.UnixTime, a.Payload, a.Timestamp ,
b.AlarmingStatus, b.STxModel, c.GroupID
FROM STxMessage a
INNER JOIN STx b
ON b.ESN = a.ESN
INNER JOIN GroupInfo c
ON b.GroupID = c.GroupID
WHERE b.STxModel = 190 AND
a.AlarmsChecked="y" AND
c.AlertsMasterSwitch="on"
UNION ALL
SELECT d.ESN, d.UnixTime, d.Payload, d.Timestamp,
NULL AS AlarmingStatus, NULL AS STxModel, NULL AS GroupID
FROM STxMessageArchive d

hi this are the extra columns in your first query
,b.AlarmingStatus
,b.STxModel
,c.GroupID
you need this same columns in second query to do union or you need to remove this column to do union operation

Your first query is selecting 7 columns where as the second query is only selecting 4. You need to make sure the second query is selecting the same number of columns as the first to make the Union All work.
SELECT a.ESN, a.UnixTime, a.Payload, a.Timestamp
,b.AlarmingStatus
,b.STxModel
,c.GroupID
FROM STxMessage a
JOIN STx b ON b.ESN = a.ESN
JOIN GroupInfo c ON b.GroupID = c.GroupID
WHERE b.STxModel = 190
AND a.AlarmsChecked="y"
AND c.AlertsMasterSwitch="on"
UNION ALL
SELECT d.ESN , d.UnixTime, d.Payload, d.Timestamp, 'null' as AlarmingStatus,
'null' as STxModel, 'null' as GroupID FROM STxMessageArchive d

As the error says, the first part has 7 columns, and the second part has only 4. An unions needs to have the same columns on both sides. Either remove
b.AlarmingStatus ,b.STxModel ,c.GroupID
from the first part, or add (even bogus) columns in the second part.

Related

How to filter out duplicates from a union query?

I have two similar SELECT queries that retrieve data from the same table "my_table".
-- 1st select
SELECT
my_table.id,
a,
b
FROM my_table
JOIN table2 ON u = v
JOIN table3 ON x = y
UNION ALL
-- 2st select
SELECT
my_table.id,
a,
b
FROM my_table
JOIN table2 ON r = s
JOIN table3 ON t = u
Duplicates are to be filtered out under the following conditions:
If the second select returns an id that is already present in the 1st select, it should be discarded.
Is there an easy solution without using a common table expression?
Note: The SQL does not have to be a UNION and can also be changed.
UNION filters out duplicate rows by default. UNION ALL does not remove duplicates.
But the duplicates are based on all columns being identical, not just the id column. If a given id value occurs in both queries, but any of the other two columns are different, then it counts as a distinct row.
If you want to reduce the result to a single row per id, the use a GROUP BY:
SELECT id, ...aggregate expressions...
FROM (
SELECT my_table.id, a, b ...
UNION
SELECT my_table.id, a, b ...
) AS t
GROUP BY id;
When you GROUP BY id, then any other expressions of the outer select-list must be in aggregate functions like MAX() or SUM(), etc.
The reason it is important to use an aggregate function is that when there are multiple rows with the same id value which you want to reduce to one row, what value should be displayed for a and b?
Example:
id
a
b
4
12
24
4
18
28
If you group by id, you would get one row for id=4, but what value for the other two columns?
id
a
b
4
?
?
Read https://dev.mysql.com/doc/refman/8.0/en/group-by-handling.html for more details on this. Or my answer to Reason for Column is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause
You must use an aggregate function, which includes GROUP_CONCAT() to append all the values from that column in a comma-separated list. Or you can use ANY_VALUE() which picks one of the values from that column arbitrarily.
I think this should do it:
-- 1st select
SELECT
my_table.id,
a,
b
FROM my_table
JOIN table2 ON u = v
JOIN table3 ON x = y
WHERE id NOT IN (
SELECT
my_table.id,
FROM my_table
JOIN table2 ON r = s
JOIN table3 ON t = u
)
UNION ALL
-- 2st select
SELECT
my_table.id,
a,
b
FROM my_table
JOIN table2 ON r = s
JOIN table3 ON t = u

How to merge(columns) outputs of two SELECT statements in oracle sql?

I have two Select queries.
The first Select query gives the output which has two columns viz.
A B
------
1 2
3 4
5 6
7 8
The second Select query given the output which as two columns viz Column B and Column C. All the values in Column B of this select statement matches the values of Column B of the first Select statement.i.e
B C
------
2 25
4 50
6 30
8 50
Now, I need to merge the outputs of the above two Select queries. i.e
A B C
----------
1 2 25
3 4 50
5 6 30
7 8 50
I cannot use views to store the output of the two select queries. I need to use the Column B in both select queries to merge. However, I am not able to figure out how to go about it.
If you have elaborated queries (not just tables to join), you may try using with construction
with
Query1 as ( -- <- Put your 1st Query text here
select A,
B
...
),
Query2 as ( -- <- Put your 2nd Query text here
select B,
C
...
)
select Query1.A,
Query1.B,
Query2.C
from Query1,
Query2
where Query1.B = Query2.B
If your case is not that complicated, e.g. both Query1 and Query2 are in fact tables, say Table1 and Table2 you can do well with a simpler solution:
select Table1.A,
Table1.B,
Table2.C
from Table1,
Table2
where Table1.B = table2.B
Consider you tables like having fields like
TableA(A ,B) , TableB(B,C)
Try using JOIN like
SELECT TableA.A , TableA.B, TableB.C
FROM TableA
JOIN TableB ON TableA.B = TableB.B;
This can be accomplished by joining your first table to your second table using an INNER JOIN on the B column:
SELECT T1.A,
T1.B,
T2.C
FROM Table1 T1
INNER JOIN Table2 T2 ON T2.B = T1.B
Note that I called your first table Table1 (alias T1) and your second table Table2 (alias T2) as I was unsure of their names.
SELECT one.a, one.b, two.c
FROM table1 one JOIN table2 two
ON one.b = two.b
You can use Join
SELECT A.A,
A.B,
B.C
FROM Table1 A
INNER JOIN Table2 B ON B.B = A.B

Alternative to UNION clause in Mysql

I have two table :- table a, table b.
table a
---ID---
1
2
3
4
5
7
table b
---ID----
2
3
4
5
6
I have to get Output Like this without UNION Command:-
----ID-----
1
2
3
4
5
6
7
Note: I have one solution with union:-
**select * from a
UNION
select * from b;**
I need alternative to this. please experts suggest.
We need another table with (at least) 2 rows for this:
CREATE TABLE d
( id INT NOT NULL
);
INSERT INTO d
(id)
VALUES
(0), (1) ;
Then, if we want to have only one query, we can use (this is for fun, DO NOT USE in production, that's why we have UNION):
SELECT DISTINCT
COALESCE(aa.id, bb.id) AS id
FROM
d
LEFT JOIN a AS aa ON d.id = 0
LEFT JOIN b AS bb ON d.id = 1
WHERE
COALESCE(aa.id, bb.id) IS NOT NULL
ORDER BY
id ;
Tested at SQLfiddle.com, and for other table combinations:
1 row - 1 row
2 rows - 2 rows
0 rows - 1 row
0 rows - 2 rows
0 rows - 0 rows
try this:
I think it works well in MS-SQL, change it to MySQL if you need, but MYSql doesnot support full outer join! Good luck
SELECT (
CASE
WHEN b.ID IS NULL
THEN a.ID
WHEN b.ID=a.ID
THEN b.ID
ELSE b.ID
END)
FROM
(SELECT ID FROM table2
)b
FULL OUTER JOIN
(SELECT ID FROM table1
) a
ON a.ID=b.ID
and play around with the query
Fiddle: http://sqlfiddle.com/#!3/c657d/13
And here is the MYSQL version:
SELECT DISTINCT COALESCE(t1.id, t2.id) id
FROM
(
SELECT TABLE_NAME <> 'table_a' n
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = SCHEMA()
AND TABLE_NAME IN('table_a', 'table_b')
) t LEFT JOIN table_a t1
ON t.n = 0 LEFT JOIN table_b t2
ON t.n = 1
Working fiddle: http://sqlfiddle.com/#!2/c657d8/34
I don't know why you are avoiding UNION but you can do like following
CREATE TABLE temp_ids(ID INT);
INSERT INTO temp_ids SELECT ID FROM a;
INSERT INTO temp_ids SELECT ID FROM b;
SELECT DISTINCT ID FROM temp_ids;
Try a full outer join and filter the NULL values.
As an abstract exercise (if this is an interview question we expect a kickback!) one ugly, innefficient solution would be to create a cartesian product and filter the unique values:
SELECT DISTINCT IF(a<>b, b.id, a.id)
FROM a, b
ORDER BY 1
;
Use FULL OUTER JOIN, like this:
SELECT CASE
WHEN t1.id IS NULL THEN t2.id
ELSE t1.id
END AS id
FROM t1
FULL OUTER JOIN t2
ON t1.id = t2.id
ORDER BY id
Note: Mysql does not support full outer joins.
Working demo: http://sqlfiddle.com/#!6/b7684/10

SQL Query, query to having single field name from different table

I have two table with some identical field. (please don't blame the design).
Below only for the example schema
Table A
id
name
phone
keys
Table B
id
name
keys
address
So, i want to query id, name from either table A or B which meet condition 'keys' on single query, with return Field just "ID" and "NAME" no matter it's from tableA or tableB
with simple query
SELECT a.id, a.name, b.id, b.name FROM TABELA as a, TABLEB as b WHERE a.keys = '1' or b.keys = '1'
It return duplicate id, name, id1, name1 to the result field.
Use UNION instead of CROSS JOIN:
SELECT a.id, a.name
FROM TABELA as a
WHERE a.keys = '1'
UNION
SELECT b.id, b.name
FROM TABLEB as b
WHERE b.keys = '1'
use union or union all. Union returns only distinct rows, union all returns all rows
see examples in manual manual on unions
SELECT a.id, a.name FROM TABELA as a WHERE a.keys = '1'
union
SELECT b.id, b.name FROM TABELb as b WHERE b.keys = '1'
You are not actually joining tables, but you just want to combine the result of two different queries. We have UNION SELECT for that:
SELECT id, name FROM tableA
WHERE keys = '1'
UNION SELECT id, name FROM tableB
WHERE keys= '1'
If you want to order the result, you can use above as a subquery.

SQL how to append columns to a single-row result set?

The issue arises from the need to return values from need to return a single-row result set that will be used for a web service.
For example, if I have a select statement which currently returns a result set with 3 columns and 1 row, is there a way to "append" a value to it in its own column? The new value could be the result of any arbitrary select which returns exactly one row.
select a, b, c from d where a = 'id' gives
col1 col2 col3
a b c
The new select should give:
col1 col2 col3 col4
a b c *NEW*
Arbitrary in this case is used to mean not necessarily related to any of the values or tables in the original select statement.
I want to know how to do this in Oracle, but hopefully there is a solution which uses standard SQL features so most databases will handle it.
EDIT: By NEW I don't mean the string literal 'NEW', but I mean the result of the new select statement that I want to "append".
If you want a new select statement, you can do that in two ways. One is a select within a select:
select col1, col2, col3,
(select 'NEW' from d limit 1) as col4
from d
The other is a cross join:
select d.col1, d.col2, d.col3, const.col4
from d cross join
(select 'NEW' as col4 from d limit 1) const
I am using a simple subquery just as an example. I assume your subquery is a bit more complicated.
this type of structure will work. note you will get a cross join when there are more than one row.
select a,b,c,d
from ( select a,b,c from dual )
, (select d from dual )
select
a, b, c,
(select smth from table2 limit 1) as col4 as col4
from d where a = 'id'
The second query should return exactly one row and one column