SQL Union displaying wrong result - sql

SELECT COUNT(id)
FROM table1
UNION
SELECT COUNT(id)
FROM table2
UNION
SELECT COUNT(id)
FROM table3
Result is
247811
58599
76
But actually
table1 has 247811 rows
table2 has 76 rows
table3 has 58599 rows

The union operator makes no gaurantees about the order. If you want to order the results in a particular way, you'd have to do so explicitly, with an order by clause. Note also that union removes duplicates, so you'd better use union all. E.g.:
SELECT cnt
FROM (SELECT 't1', COUNT(id) FROM table1
UNION ALL
SELECT 't2', COUNT(id) FROM table2
UNION ALL
SELECT 't3', COUNT(id) FROM table3) t
ORDER BY 1 ASC

if your problem depends on order by please order by your select after union, if you have a problem with count?(in your example there is a different count 79 and 76) it depends on that you use count(id) it is not same is count(*), count(id) ignores every null in Id column, count(*) it is count of your table rows

Related

SQL - Combining two queries into one query

I have 2 queries.
For table1,
SELECT codesTable.code_id,COUNT(*) FROM table1,codesTable
WHERE table1.codeid=CodeTable.code_id
AND table1.type_no IN (1,2,3,4,5,6,7,8,9,10)
AND table1.recoverd_value IN (0,1)
GROUP BY table1.code_id
For Table2
SELECT codesTable.code_id,COUNT(*) FROM table2,codesTable
WHERE table2.codeid=CodeTable.code_id
AND table2.type_no IN (1,2,3,4,5,6,7,8,9,10)
AND table2.recoverd_value IN (0,1)
GROUP BY table2.code_id
Need to combine this as one query.
Note:
Result for 1st query: code_id and count of Table1 and
Result for 2nd query: code_id, count of table2.
Current output like code_id,count of table(1,2)
SELECT code_id, SUM(counted)
FROM (
SELECT code_id,COUNT(*) AS counted
FROM table1,codesTable
WHERE table1.codeid=CodeTable.code_id
AND table1.type_no IN (1,2,3,4,5,6,7,8,9,10)
AND table1.recoverd_value IN (0,1)
GROUP BY table1.code_id
UNION ALL
SELECT code_id,COUNT(*) AS counted
FROM table2,codesTable
WHERE table2.codeid=CodeTable.code_id
AND table2.type_no IN (1,2,3,4,5,6,7,8,9,10)
AND table2.recoverd_value IN (0,1)
GROUP BY table2.code_id
) AS subq
GROUP BY code_id
;
Don't forget to use UNION ALL instead of UNION because UNION ALL saves duplicates from both tables.
You can just use union for this operation where two tables will be combined excluding the duplicates. Code is Shown below.
(SELECT code_id,COUNT(*) FROM table1,codesTable
WHERE table1.codeid=CodeTable.code_id
AND table1.type_no IN (1,2,3,4,5,6,7,8,9,10)
AND table1.recoverd_value IN (0,1)
GROUP BY table1.code_id)
UNION
(SELECT code_id,COUNT(*) FROM table2,codesTable
WHERE table2.codeid=CodeTable.code_id
AND table2.type_no IN (1,2,3,4,5,6,7,8,9,10)
AND table2.recoverd_value IN (0,1)
GROUP BY table2.code_id)
Hope this clarified your doubt.
You may union all the required results from table1 and table2 then join this unioned query to codesTable as the following:
SELECT D.codeid, COUNT(*) CN
FROM
(
SELECT codeid, type_no, recoverd_value
FROM table1
UNION ALL
SELECT codeid, type_no, recoverd_value
FROM table2
) D
JOIN codesTable T
ON D.codeid = T.code_id
WHERE D.type_no IN (1,2,3,4,5,6,7,8,9,10) AND D.recoverd_value IN (0,1)
GROUP BY D.codeid
ORDER BY D.codeid
See a demo.

Union all on the same table

There has to be a better way of doing this any one have an idea. there is one table and i have 8 columns i need select all of the columns one on top of each other and for each selected colum i need to count the number of items that are the same
SELECT Col1, count(*) 'Selected'
FROM [Table]
group by temp_id,Col1
UNION ALL
SELECT Col2,count(*)
FROM [Table]
group by temp_id,Col2
having len(ltrim(rtrim(Col2)))<>0
UNION ALL
SELECT Col3,count(*)
FROM [Table]
group by temp_id,Col3
having len(ltrim(rtrim(Col3)))<>0
union all
SELECT Col4,count(*)
FROM [Table]
group by temp_id,Col4
union all
SELECT Col5,count(*)
FROM [Table]
group by temp_id,Col5
having len(ltrim(rtrim(Col5)))<>0
union all
SELECT Col6,count(*)
FROM [Table]
group by temp_id,Col6
having len(ltrim(rtrim(Col6)))<>0
union all
SELECT Col7,count(*)
FROM [Table]
group by temp_id,Col7
having len(ltrim(rtrim(Col7)))<>0
union all
SELECT Col8,count(*)
FROM [Table]
group by temp_id,Col8
having len(ltrim(rtrim(Col8)))<>0
There is. It is called grouping sets (and it is documented here). In your case, you can do something like this (example for first three columns):
select coalesce(col1, col2, col3), count(*) as Selected
from [table]
group by grouping sets ((temp_id, col1), (temp_id, col2), (temp_id, col3));
Your condition using length() and trim() on each column -- you should probably handle that using a having clause.

Case on union of multiple unions and issue with alias

I have 2 series of unions which I wish to join by another union. In the first one, I have 3 Selects and in the second one I have 2 different Selects.
Select id, min(value)
from table1 t1
join (Select id, value
Union
Select id, value
Union
Select id, value) as foo
on foo.id=t1.id
Group by id
Select id, max(value)
from table1 t1
join (Select id, value
Union
Select id, value) as bar
on bar.id=t1.id
Group by id
I tried to do a union between these two, but it made things pretty complicated. My biggest issue is with my alias. My second is with the case linked to my value columns, which I wish to name value.
Select (alias).id,
Case
When foo.value= 0 or bar.value=1 THEN 1
Else 0
End as value
from table1 t1
Join (Select id, min(value)
from table1 t1
join (Select id, value
Union
Select id, value
Union
Select id, value) as foo
on foo.id=t1.id
Group by id
UNION
Select id, max(value)
from table1 t1
join (Select id, value
Union
Select id, value) as bar
on bar.id=t1.id
Group by id) as (alias)
on ??.id=??.id
I wrote my case the way I think it should be written, but normally, when there are more than one column with the same name, SQL states it as ambiguous. I am still unsure if I should use UNION or INTERSECT, but I assume either of them would be done the same way. How should I deal with this?
I'm reading this right, you probably want something like this
SELECT ...
FROM ( ... union #1 ) AS u1
JOIN (... union #2 ) AS u2 ON u1.id = u2.id

multiple select in one query [Teradata]

I'm trying to do multiple select from diff tables and just have a result in one column.
SELECT COUNT(*) FROM tb1 union
SELECT COUNT(*) FROM tb2 union
SELECT COUNT(*) FROM tb3;
output should be like:
593643
18103600
0
Problem with this is that the result is being arranged on desc order.
Like below:
0
593643
18103600
I would want the result to be as I put the select statement.
Please advise. Btw, I'm using teradata.
Thank you.
SQL result sets are inherently unordered, unless you explicitly specify an order by clause. You can do this with a subquery:
select cnt
from ((SELECT COUNT(*) as cnt, 1 as ord FROM tb1)
union all
(SELECT COUNT(*), 2 FROM tb2)
union all
(SELECT COUNT(*), 3 FROM tb3)
) t
order by ord
If you want specific order, add ORDER BY clause. It would also be good to use UNION ALL so you always get 3 rows, even with duplicate results (two tables having the same number of rows):
SELECT 'tbl1' AS tablename, COUNT(*) AS cnt, 1 AS ord FROM tb1 UNION ALL
SELECT 'tbl2', COUNT(*), 2 FROM tb2 UNION ALL
SELECT 'tbl3', COUNT(*), 3 FROM tb3
ORDER BY ord ;

How to use order by with union all in sql?

I tried the sql query given below:
SELECT * FROM (SELECT *
FROM TABLE_A ORDER BY COLUMN_1)DUMMY_TABLE
UNION ALL
SELECT * FROM TABLE_B
It results in the following error:
The ORDER BY clause is invalid in views, inline functions, derived
tables, subqueries, and common table expressions, unless TOP or FOR
XML is also specified.
I need to use order by in union all. How do I accomplish this?
SELECT *
FROM
(
SELECT * FROM TABLE_A
UNION ALL
SELECT * FROM TABLE_B
) dum
-- ORDER BY .....
but if you want to have all records from Table_A on the top of the result list, the you can add user define value which you can use for ordering,
SELECT *
FROM
(
SELECT *, 1 sortby FROM TABLE_A
UNION ALL
SELECT *, 2 sortby FROM TABLE_B
) dum
ORDER BY sortby
You don't really need to have parenthesis. You can sort directly:
SELECT *, 1 AS RN FROM TABLE_A
UNION ALL
SELECT *, 2 AS RN FROM TABLE_B
ORDER BY RN, COLUMN_1
Not an OP direct response, but I thought I would jimmy in here responding to the the OP's ERROR messsage, which may point you in another direction entirely!
All these answers are referring to an overall ORDER BY once the record set has been retrieved and you sort the lot.
What if you want to ORDER BY each portion of the UNION independantly, and still have them "joined" in the same SELECT?
SELECT pass1.* FROM
(SELECT TOP 1000 tblA.ID, tblA.CustomerName
FROM TABLE_A AS tblA ORDER BY 2) AS pass1
UNION ALL
SELECT pass2.* FROM
(SELECT TOP 1000 tblB.ID, tblB.CustomerName
FROM TABLE_B AS tblB ORDER BY 2) AS pass2
Note the TOP 1000 is an arbitary number. Use a big enough number to capture all of the data you require.
There will be times when you need to do something like this :
Pull top 5 from table 1 based on a sort
and bottom 5 from table 2 based on another sort
and union these together.
solution
select * from (
-- top 5 records
select top 5 col1, col2, col3
from table1
group by col1, col2
order by col3 desc ) z
union all
select * from (
-- bottom 5 records
select top 5 col1, col2, col3
from table2
group by col1, col2
order by col3 ) z
this was the only way i was able to get around the error and worked fine for me.
SELECT * FROM (SELECT *
FROM TABLE_A ORDER BY COLUMN_1)DUMMY_TABLE
UNION ALL
SELECT * FROM TABLE_B
ORDER BY 2;
2 is column number here .. In Oracle SQL you can use the column number by which you want to sort the data
This solved my SELECT statement:
SELECT * FROM
(SELECT id,name FROM TABLE_A
UNION ALL
SELECT id,name FROM TABLE_B ) dum
order by dum.id , dum.name
where id and name columns available in tables and you can use your columns .
Simply use that , no need parenthesis or anything else
SELECT *, id as TABLE_A_ID FROM TABLE_A
UNION ALL
SELECT *, id as TABLE_B_ID FROM TABLE_B
ORDER BY TABLE_A_ID, TABLE_B_ID
ORDER BY after the last UNION should apply to both datasets joined by union.
The solution shown below:
SELECT *,id AS sameColumn1 FROM Locations
UNION ALL
SELECT *,id AS sameColumn2 FROM Cities
ORDER BY sameColumn1,sameColumn2
select CONCAT(Name, '(',substr(occupation, 1, 1), ')') AS f1
from OCCUPATIONS
union
select temp.str AS f1 from
(select count(occupation) AS counts, occupation, concat('There are a total of ' ,count(occupation) ,' ', lower(occupation),'s.') As str from OCCUPATIONS group by occupation order by counts ASC, occupation ASC
) As temp
order by f1