SQL Query to sum multiple count union queries - sql

I have a statement with following structure, and I'm trying to sum all the count results.
I have tried using the SUM function outside of the nested count queries combined using the same variable declaration for each of the union, but error says that I must give them separate aliases. However, if I do that, won't I need to refer to these separately within the SUM function?
My SQL Code returning 2 rows:
SELECT COUNT(col_x) FROM tablea
UNION
SELECT COUNT(col_y) FROM tableb;
OUTPUT
64
10
Now when I try to SUM the answers I run into trouble:
WITH total as(
SELECT COUNT(col_x) FROM tablea as rowtotal
UNION
SELECT COUNT(col_y) FROM tableb as rowtotal
) SELECT SUM(rowtotal) from total;
The error is around using the variable 'rowtotal' twice. Surely there's an easier way to this?
I simply want a sum of both values as:
OUTPUT
74

You don't need window functions for that
select sum(cnt) as total
from
(
SELECT COUNT(col_x) as cnt FROM tablea
UNION
SELECT COUNT(col_y) FROM tableb
) tmp

You can use +:
SELECT ( (SELECT COUNT(col_x) FROM tablea) +
(SELECT COUNT(col_y) FROM tableb)
)
Or a cross join:
SELECT a_cnt + b_cnt
FROM (SELECT COUNT(col_x) as a_cnt FROM tablea) a CROSS JOIN
(SELECT COUNT(col_y) as b_cnt FROM tableb) b;
Do not use UNION! It removes duplicates, so your sum may be off. You can use UNION ALL, but you have alternatives.

Try this
WITH total as(
SELECT COUNT(col_x) as rowtotal FROM tablea
UNION
SELECT COUNT(col_y) FROM tableb
) SELECT SUM(rowtotal) from total

You don;t need to give alias on table, instead it is actually saying to provide alias for column name.
WITH total as(
SELECT COUNT(col_x) as total FROM tablea --- it is necessary over here
UNION
SELECT COUNT(col_y) as total FROM tableb --- it is not mandatory to give alias on second statement of UNION
) SELECT SUM(rowtotal) as total from total;

Related

Union of multiple queries using the count function

I'm working on learning more about how the UNION function works in SQL Server.
I've got a query that is directed at a single table:
SELECT Category, COUNT(*) AS Number
FROM Table1
GROUP BY Category;
This returns the number of entries for each distinct line in the Category column.
I have multiple tables that are organized by this Category column and I'd like to be able to have the results for every table returned by one query.
It seems like UNION will accomplish what I want it to do but the way I've tried implementing the query doesn't work with COUNT(*).
SELECT *
FROM (SELECT Table1.Category
Table1.COUNT(*) AS Number
FROM dbo.Table1
UNION
SELECT Table2.Category
Table2.COUNT(*) AS Number
FROM dbo.Table2) AS a
GROUP BY a.Category
I'm sure there's an obvious reason why this doesn't work but can anyone point out what that is and how I could accomplish what I'm trying to do?
You cannot write a common Group by clause for two different select's. You need to use Group by clause for each select
SELECT TABLE1.Category, --missing comma here
COUNT(*) as Number -- Remove TABLE1. alias name
FROM dbo.TABLE1
GROUP BY Category
UNION ALL --UNION
SELECT TABLE2.Category, --missing comma here
COUNT(*) as Number -- Remove TABLE1. alias name
FROM dbo.TABLE2
GROUP BY Category
If you really want to remove duplicates in result then change UNION ALL to UNION
COUNT as any associated aggregation function has to have GROUP BY specified. You have to use group by for each sub query separately:
SELECT * FROM (
SELECT TABLE1.Category,
COUNT(*) as Number
FROM dbo.TABLE1
GROUP BY TABLE1.Category
UNION ALL
SELECT TABLE2.Category,
COUNT(*) as Number
FROM dbo.TABLE2
GROUP BY TABLE2.Category
) as a
It is better to use UNION ALL vs UNION - UNION eliminates duplicates from result sets, since - let say - you want to merge both results as they are it is safer to use UNION ALL

Get a defined row instead of empty result set: SQL Server

I need a query that return rows even if they have no matching data in table. I know that an empty result set will be returned, but as my project necessity, I need to get a row in result set. It is acceptable though that the values are null. Below is my query:
select Demographic_Id, Total from school.Demographic_Profile where Demographic_Id=2
There is no data with Demographic_Id equal to 2. Still I need to get a result like this:
Demographic_Id | Total
2 | NULL
Any suggestions would help a lot!
If you would get exactly one row or zero rows, then a trick is to use aggregation:
select 2 as Demographic_Id, max(Total) as Total
from school.Demographic_Profile
where Demographic_Id = 2;
You could also use an outer join
select v.did As Demographic_Id,
Total
from (values(2)) v(did)
LEFT JOIN school.Demographic_Profile ON Demographic_Id=v.did
You might use a CTE. The CTE will create a derived table. The UNION ALL will append one row, but only in case the query did not return any rows. Otherwise the query will return just as expected:
WITH CTE AS
(
SELECT object_id
,name
FROM sys.objects
WHERE name='non-existent'
)
SELECT * FROM CTE
UNION ALL
SELECT 2,NULL WHERE (SELECT COUNT(*) FROM CTE)=0
For your case try this:
DECLARE #id INT=2
WITH CTE AS
(
select Demographic_Id, Total
from school.Demographic_Profile
where Demographic_Id=#id
)
SELECT * FROM CTE
UNION ALL
SELECT #id,NULL WHERE (SELECT COUNT(*) FROM CTE)=0
select Demographic_Id, Total from
(SELECT 1 as did
UNION ALL
SELECT 2 as did
UNION ALL
SELECT 3 as did) as innerQuery
left outer join school.Demographic_Profile on did = Demographic_Id

How to return unique records between two tables without using distinct and union?

I need to return the unique records between two tables. Ideally, an UNION would solve my problem but both tables contain an object field which gives me an error(cannot ORDER objects without MAP or ORDER method) when I do UNION/distinct.
So, I was wondering if I can do a UNION ALL(to avoid the error) to get all the records first then do something to return only the unique records from there. I tried analytic function combined with the UNION ALL query but no luck so far.
Select * from Table1
union all
Select * from table2
Any help? Note:I need to return all fields.
I actually solved the problem using analytic function+row_num. The query will choose the first record for each set of duplicates hence returning only the unique records.
select * from
(
select ua.*,row_number() over (partition by p_id order by p_id ) row_num from
(
select * from table1
union all
select * from table2
)ua
) inner
where inner.row_num=1
How about this :
SELECT DISTINCT A.* FROM
(
Select * from Table1
union all
Select * from table2
) A;
(or)
SELECT col1,col2,col3...coln FROM
(
Select col1,col2,col3...coln from Table1
union all
Select col1,col2,col3...coln from table2
) A
GROUP BY A.col1,col2,col3...coln;
UNION ALL will give duplicate values as well .. instead use UNION and see if you are facing the error

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 ;

Count rows in more than one table with tSQL

I need to count rows in more than one table in SQL Server 2008. I do this:
select count(*) from (select * from tbl1 union all select * from tbl2)
But it gives me an error of incorrect syntax near ). Why?
PS. The actual number of tables can be more than 2.
In case you have different number of columns in your tables try this way
SELECT count(*)
FROM (
SELECT NULL as columnName
FROM tbl1
UNION ALL
SELECT NULL
FROM tbl2
) T
try this:
You have to give a name to your derived table
select count(*) from
(select * from tbl1 union all select * from tbl2)a
I think you have to alias the SELECT in the FROM clause:
select count(*)
from
(
select * from tbl1
union all
select * from tbl2
) AS SUB
You also need to ensure that the * in both tables tbl1 and tbl2 return exactly the same number of columns and they have to be matched in their type.
I don't like doing the union before doing the count. It gives the SQL optimizer an opportunithy to choose to do more work.
AlexK's (deleted) solution is fine. You could also do:
select (select count(*) from tbl1) + (select count(*) from tbl2) as cnt