Top 10 results on rows obtained by UNION - sql

I am using MSSQL 2005 for a query, say:
SELECT * from Emp UNION ALL SELECT * from Emp2;
And I want to limit the final result to 10 rows.
IF I had only the Emp table, I would say
SELECT TOP 10 * from Emp;
But since I have 2 tables now, I can't say SELECT TOP * on any of them, neither I can use LIMIT 10 in the end.
Do you have any suggestion?

SELECT TOP 10 * FROM
(SELECT * from Emp UNION ALL SELECT * from Emp2) a
However, I would suggest maybe you order the results so that you don't just get top 10 results from first union result. So something like this maybe:
SELECT TOP 10 * FROM
(SELECT * from Emp UNION ALL SELECT * from Emp2) a
ORDER BY a.lastName

try this:
SELECT TOP 10 *
FROM (
SELECT *
FROM Emp
UNION ALL
SELECT *
FROM Emp2
) derivedTable

try this:
SELECT top 10 * from (
SELECT * from Emp UNION ALL SELECT * from Emp2) a

Make the UNIONed query a subquery, and SELECT the TOP 10 rows from that:
SELECT TOP 10 * FROM (
SELECT * FROM Emp
UNION ALL
SELECT * FROM Emp2
) unioned

Related

Order by clause with union in SQL select query

Is there a way to order the union of two select all statements based on table column values.
My sample code is:
SELECT * FROM emp WHERE mgr='7839'
UNION
SELECT * FROM emp WHERE NOT EXISTS (SELECT * FROM emp WHERE mgr='7839')
AND empno='7839'
order by ename;
This code is showing error as:invalid identifier 'ENAME'.
I am not using specific columns in select statement instead of * since there are more than 10 columns in the table and the code looks so big.
But ename is a column in emp.
will you consider small change in your query.
SELECT * FROM
(SELECT * FROM emp WHERE mgr='7839'
UNION
SELECT * FROM emp WHERE NOT EXISTS (SELECT * FROM emp WHERE mgr='7839')
AND empno='7839') AA
order by AA.ename;
Why would use use union for this? Just do:
SELECT e.*
FROM emp e
WHERE e.mgr = '7839' OR
(NOT EXISTS (SELECT 1 FROM emp e2 WHERE e2.mgr = '7839') AND
empno = '7839'
)
ORDER BY ename;

find difference using UNION and minus

I am bit out of my wits why the sql below would not produce any row. Clearly there is an id 1 which is not in b and I expected that to be the output. I know I am missing some fundamentals on how union works - may be due to the fact that there is not output in the second minus?
Redshift:
WITh a as
(select 1 id union all select 2
)
,b as (select 2 id)
select * from a
minus
select * from b
union all
select * from b
minus
select * from a
Oracle-
WITh a as
(select 1 id from dual union all select 2 from dual
)
,b as (select 2 id from dual)
select * from a
minus
select * from b
union all
select * from b
minus
select * from a
There is an order of operations issue with the way you wrote your query. If you wrap the two sides of the union as subqueries, and select from them, then you get the result you expect:
select * from
(select * from a
minus
select * from b ) t1
union all
select * from
(select * from b
minus
select * from a ) t2
What appears to be happening is that first the following is run, leaving us with id=1:
select * from a
minus
select * from b
Then, this result is being unioned with a query on b:
(select * from a
minus
select * from b)
union all
select * from b
At this point, the result set again has both 1 and 2 in it. But now, we take a minus operation against table a:
(select * from a
minus
select * from b
union all
select * from b)
minus
select * from a
This results in an empty set, since (1,2) minus (1,2) leaves us with nothing.

Odd requirement of SQL Query

I have a table with columns 'Id' and 'Status'.
I want to write a SQL statement to select top 50 rows from this table with 25 rows with Status 1 and 25 rows with Status 2 in one SQL query.
I want my result to have rows with alternate status.
Please suggest me how to write this Query.
If you use MSSQL you can do this:
SELECT TOP 25
*
FROM
Table1
WHERE
Table1.Status=1
UNION ALL
SELECT TOP 25
*
FROM
Table1
WHERE
Table1.Status=2
If you use MYSQL you have to use LIMIT. Like this:
(
SELECT
*
FROM
Table1
WHERE
Table1.Status=1
LIMIT 25
)
UNION ALL
(
SELECT
*
FROM
Table1
WHERE
Table1.Status=2
LIMIT 25
);
For SQL Server, use TOP:
SELECT TOP 25 * FROM TableName WHERE Status=1
UNION ALL
SELECT TOP 25 * FROM TableName WHERE Status=2
For alternative result:
SELECT * FROM
(
SELECT TOP 25 *,ROW_NUMBER() OVER(ORDER BY Status) as RN FROM TableName WHERE Status=1
UNION ALL
SELECT TOP 25 *,ROW_NUMBER() OVER(ORDER BY Status) as RN FROM TableName WHERE Status=2
) T
ORDER BY RN

Using different order by with union

I want to write a query like
select top 10 * from A
order by price
union
select top 3 * from A
order by price
or sth like that
select top 10 * from A
where name like '%smt%'
order by price
union
select top 3 * from A
where name not like '%smt%'
order by price
Can you please help me?
This should work:
SELECT *
FROM (SELECT TOP 10 A.*, 0 AS Ordinal
FROM A
ORDER BY [Price]) AS A1
UNION ALL
SELECT *
FROM (SELECT TOP 3 A.*, 1 AS Ordinal
FROM A
ORDER BY [Name]) AS A2
ORDER BY Ordinal
From MSDN:
In a query that uses UNION, EXCEPT, or INTERSECT operators, ORDER BY
is allowed only at the end of the statement. This restriction applies
only to when you specify UNION, EXCEPT and INTERSECT in a top-level
query and not in a subquery.
Edited: to force the order you need to apply an ORDER BY to the outer query. I've added a constant value column to both queries.
This is a real hacky way to do this. You probably want these as separate queries in reality, but this should give you the result you want...
select *
from (
select top 10 *, 1 as 'ord', price as 'ordprice' from A
union
select top 3 *, 2 as 'ord', 0 as 'ordprice' from A
) a
order by ord, ordprice, name
UNION doesn't like ORDER by clauses in the UNIONed expressions.
Try this:
SELECT * FROM
(SELECT TOP 10 * FROM A ORDER BY Price) SetA
UNION
SELECT * FROM
(SELECT TOP 3 * FROM a ORDER BY name) Setb
[ORDER BY something]
This spoofs the UNION operator into ignoring the ORDER BYs, which still operate correctly on the TOP operator.
You can apply a final ORDER BY to order the UNIONed set, if you like.
[No longer applies exactly to your question now that it's edited!]
select top 10 *,0 as RS from A
union
select top 3 *,1 as RS from A
order by
RS,
CASE WHEN RS=0 THEN price END, --Don't affect RS 1
name
cmd.CommandText = "SELECT 0 AS Employee_ID, 'No Employees' as Employee_FullName , 'id1' Orderkey
UNION ALL
SELECT Employee_ID, Employee_FullName, 'id2' Orderkey
FROM tblEmployee
ORDER BY Orderkey, Employee_FullName"
ds = dbconn.SelectQuery(cmd)
ds.Tables(0).Columns.Remove(ds.Tables(0).Columns("Orderkey"))

Join two sql queries side by side with no column common

I need to join the results of two queries horizontally.
Consider a query below which will return two rows:
Select *
from Salary
where sal > 10000
The result of the query above should be joined side by side with the result of the query below which will again return two rows.Or I need to just concatenate the two result sets:
Select 'xyz' from dual
union
Select 'abc' from dual
Please suggest how this can be done as I tried to do this with the query below but it returns a cartesian product:
Select *
from (Select *
from salary
where sal > 10000) TEMP1,
(Select 'xyz' from dual
union
Select 'abc' from dual) TEMP2
You can do that by joining on rownum like this:
SELECT *
FROM
(SELECT view_name, rownum AS r FROM all_views WHERE rownum <=10)
FULL OUTER JOIN (SELECT table_name, rownum AS r FROM all_tables WHERE rownum <=10) USING (r)
In your case this would look like (untested):
Select * from
(Select salary.*, rownum AS r from salary where sal>10000) TEMP1
FULL OUTER JOIN
(SELECT temp2.*, rownum r FROM
(Select 'xyz' from dual
union
Select 'abc' from dual) TEMP2)
USING (r)
you can introduce an artificial join column:
SELECT *
FROM (SELECT s.*, ROWNUM ID FROM Salary s WHERE sal > 10000) q1
JOIN (SELECT 'xyz' col1, 1 ID
FROM dual
UNION
SELECT 'abc' col1, 2 ID FROM dual) q2 ON q1.id = q2.id
Thank you very much for your help.
But what I need is a bit complicated. I have updated the previous query to be somewhat like below instead of simple query that I posted before (SELECT * FROM Salary WHERE sal > 10000):
SELECT name, sal, address
FROM (SELECT e1.name, s1.sal, s1.grade, s2.address FROM Emp e1, salary s1,
(Select empcode, address FROM Address WHERE empcode LIKE 'NY%') s2
WHERE e1.hiredate =201001
AND s1.sal>10000)
I know the above query does not make much of a relevance. However, this is similar to what I need actually. I am not posting the original one as that is very complicated but if this can be done for this query, then I will be able to replicate the same on the original one as well.
Thank you,
Sharon