Count rows in more than one table with tSQL - sql

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

Related

Is there a SQL function to expand table?

I vaguely remember there being a function that does this, but I think I may be going crazy.
Say I have a datatable, call it table1. It has three columns: column1, column2, column3. The query
SELECT * FROM table1
returns all rows/columns from table1. Isn't there some type of EXPAND function that allows me to duplicate that result? For example, if I want to duplicate everything from the SELECT * FROM table1 query three times, I can do something like EXPAND(3) ?
In BigQuery, I would recommend a CROSS JOIN:
SELECT t1.*
FROM table1 CROSS JOIN
(SELECT 1 as n UNION ALL SELECT 2 UNION ALL SELECT 3) n;
This can get cumbersome for lots of copies, but you can simplify this by generating the numbers:
SELECT t1.*
FROM table1 CROSS JOIN
UNNEST(GENERATE_ARRAY(1, 3)) n
This creates an array with three elements and unnests it into rows.
In both these cases, you can include n in the SELECT to distinguish the copies.
Below is for BigQuery Standard SQL
I think below is close enough to what "got you crazy" o)
#standardSQL
SELECT copy.*
FROM `project.dataset.tabel1` t, UNNEST(FN.EXPAND(t, 3)) copy
To be able to do so, you can leverage recently announced support for persistent standard SQL UDFs, namely - you need to create FN.EXPAND() function as in below example (note: you need to have FN dataset in your project - or use existing dataset in which case you should use YOUR_DATASET.EXPAND() reference
#standardSQL
CREATE FUNCTION FN.EXPAND(s ANY TYPE, dups INT64) AS (
ARRAY (
SELECT s FROM UNNEST(GENERATE_ARRAY(1, dups))
)
);
Finally, if you don't want to create persistent UDF - you can use temp UDF as in below example
#standardSQL
CREATE TEMP FUNCTION EXPAND(s ANY TYPE, dups INT64) AS ( ARRAY(
SELECT s FROM UNNEST(GENERATE_ARRAY(1, dups))
));
SELECT copy.*
FROM `project.dataset.tabel1` t, UNNEST(EXPAND(t, 3)) copy
if you want a cartesian product (all the combination on a row ) you could use
SELECT a.*, b.*, c.*
FROM table1 a
CROSS JOIN table1 b
CROSS JOIN table1 c
if you want the same rows repeated you can use UNION ALL
SELECT *
FROM table1
UNION ALL
SELECT *
FROM table1
UNION ALL
SELECT *
FROM table1
Use union all
Select * from table1
Union all
Select * from table1
Union all
Select * from table1
Union all
Select * from table1
For reuse purposes can embed this code in a procedure like
Create Procedure
expandTable(tablename
varchar2(50))
As
Select * from table1
Union all
Select * from table1
Union all
Select * from table1
Union all
Select * from table1
End
/

Choose which query will be used / Conditional query in Oracle

I have two queries, query1 and query2. What I would like to do is, if returned rows of query1 is empty, return query2 instead. Is that possible using basic SQL query alone? They have same returning columns btw, but different table sources.
eg:
query1:
SELECT name, message
FROM table1
query2:
SELECT name, message
FROM table 2
If query1 is empty, return name, message from query2.
This will select from table1 if not empty, otherwise select from table2:
SELECT * FROM table1
WHERE EXISTS (select * from table1)
UNION ALL
SELECT * FROM table2
WHERE NOT EXISTS (select * from table1)
This checks if table1 has no rows:
EXISTS (SELECT * FROM TABLE)
Found an answer here: https://stackoverflow.com/a/25122516/3747493
Basically:
SELECT *
FROM table1
UNION ALL
SELECT *
FROM table2
WHERE (SELECT COUNT(*) FROM table1) = 0
Thanks guys!

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

On SQL request by column

I have different simple SQL request that return only one value. Example
SELECT COUNT(*) FROM Person
OR
SELECT COUNT(*) FROM Category
I would to get all these infos in a unique request, with a column by request...
I tried something like that but it doesn't work :
SELECT COUNT(C.CategoryId) As nbPeople, COUNT(P.PersonID) As nbCategories FROM Category C, Person P
This works but I get only one column, and a row by request
SELECT COUNT(*) FROM Person UNION SELECT COUNT(*) FROM Category
How Can I simply do that ?
Thanks
When using SQL Server, you can try this:
SELECT ( select COUNT(C.CategoryId)
from Category C
) As nbPeople
, ( select COUNT(P.PersonID)
from Person P
) As nbCategories
In Oracle for example, you need to add this at the bottom
FROM dual
You can use UNION ALL like following:
SELECT '' AS [StatisticName], 1 AS [StatisticCount]
WHERE 1=0
UNION ALL
SELECT 'PersonCount', COUNT(*) FROM [Person]
UNION ALL
SELECT 'CathegoryCount', COUNT(*) FROM [Category]
First select with WHERE 1=0 is for create column header names only and is not necessary.
Try this.
select * from
(select count(*) cnt1
from Table1) t1
join
(select count(*) as cnt2
from Table2) t2 on 1=1

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