UNION two tables with conditions from the first - sql

I have a union on the same table [MyTable] so I can select certain values as the top 5, the logic of which I'm excluding here to simplify the question (I hope):
The first table I alias as tbl1 - can I reference this alias somehow after the UNION statement so that I can exclude the results from it?
I tried like so but it doesn't recognise tbl1
SELECT top 5 tbl1.Id, tbl1.Description, 'first'
FROM (
-- query [MyTable] joined with others to get particular result set
) as tbl1
UNION
SELECT tbl2.Id, tbl2.Description, 'second'
FROM [MyTable] as tbl2 WHERE tbl2.Id NOT IN
(SELECT Id FROM tbl1)
Or do I just have to redo the first query in the 2nd half in order to get those Id's to exclude?
I'm using SQL Server 2012 for this.

You can also use a temp table for the same purpose based on your requirement. See the difference here.
SELECT TOP 5 tbl1.Id, tbl1.Description, 'first' INTO #tbl1
FROM (
-- query [MyTable] joined with others to get particular result set
)
SELECT * FROM #tbl1
UNION ALL
SELECT tbl2.Id, tbl2.Description, 'second'
FROM [MyTable] AS tbl2
WHERE tbl2.Id NOT IN (SELECT Id FROM #tbl1)

Use a CTE:
WITH cte AS (
SELECT top 5 tbl1.Id, tbl1.Description, 'first'
FROM (
-- query [MyTable] joined with others to get particular result set
) as tbl1
)
SELECT * FROM cte
UNION ALL
SELECT tbl2.Id, tbl2.Description, 'second'
FROM [MyTable] as tbl2 WHERE tbl2.Id NOT IN (SELECT Id FROM cte)

Related

SQL Union displaying wrong result

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

SQL Having count logic

i need help on HAVING COUNT , i have a result set of data below:
CREATE TABLE #tmpTest1 (Code VARCHAR(50), Name VARCHAR(100))
INSERT INTO [#tmpTest1]
(
[Code],
[Name]
)
SELECT '160215-039','ROBIN'
UNION ALL SELECT '160215-039','ROBIN'
UNION ALL SELECT '160215-046','SENGAROB'
UNION ALL SELECT '160215-046','BABYPANGET'
UNION ALL SELECT '160215-045','JONG'
UNION ALL SELECT '160215-045','JAPZ'
UNION ALL SELECT '160215-044','AGNES'
UNION ALL SELECT '160215-044','AGNES'
UNION ALL SELECT '160215-041','BABYTOT'
UNION ALL SELECT '160215-041','BABYTOT'
UNION ALL SELECT '160215-041','BABYTOT'
i want to show only the rows that have the same code but different name , so in this case my expected result is below since those are have the same code but different name:
160215-045 JAPZ
160215-045 JONG
160215-046 BABYPANGET
160215-046 SENGAROB
but when i try to group the two columns then use the having count, below is my query:
SELECT [Code], [Name] FROM [#tmpTest1]
GROUP BY [Code], [Name] HAVING COUNT([Code]) > 1
It gives me wrong result below which have the rows that have the same code and name, it is the opposite of what i want.
160215-044 AGNES
160215-041 BABYTOT
160215-039 ROBIN
How can i get my expected output ?
Thanks in advance, any help would much appreciated.
I believe this query will give you the result you want, although your original question is a bit unclear.
SELECT t1.[Code], t1.[Name]
FROM [#tmpTest1] t1
INNER JOIN
(
SELECT [Code]
FROM [#tmpTest1]
GROUP BY [Code]
HAVING COUNT(DISTINCT [Name]) > 1
) t2
ON t1.[Code] = t2.[Code]
Follow the link below for a running demo:
SQLFiddle
If you want rows with the same code and name, then use window functions:
select t.*
from (select t.*, count(*) over (partition by code, name) as cnt
from #temptest1 t
) t
where cnt >= 2;
From your comment
if there is 1 different name for the codes , i want to show those
records for me to know that there is one differs to others..
This sounds like an exists query because you want to check if another row with the same code but different name exists.
select * from [#tmpTest1] t1
where exists (
select 1 from [#tmpTest] t2
where t2.code = t1.code
and t2.name <> t1.name
)

How to avoid Sorting in Union ALL

MY question is simple, How do you avoid the automatic sorting which the UNION ALL query does?
This is my query
SELECT * INTO #TEMP1 FROM Final
SELECT * INTO #TEMP2 FROM #TEMP1 WHERE MomentId = #MomentId
SELECT * INTO #TEMP3 FROM #TEMP1 WHERE RowNum BETWEEN #StartRow AND #EndRow
SELECT * INTO #TEMP4 FROM (SELECT *FROM #TEMP3 UNION ALL SELECT *FROM #TEMP2) as tmp
SELECT DISTINCT * FROM #TEMP4
I'm using SQL Server 2008. I need the Union ALL to perform like a simple Concatenate, which it isn't! Appreciate your help in this.
I think you're mistaken on which operation is actually causing the sort. Check the code below, UNION ALL will not cause a sort. You may be looking at the DISTINCT operation, which uses a sort (it sorts all items and the eliminates duplicates)
CREATE TABLE #Temp1
(
i int
)
CREATE TABLE #temp2
(
i int
)
INSERT INTO #Temp1
SELECT 3 UNION ALL
SELECT 1 UNION ALL
SELECT 8 UNION ALL
SELECT 2
INSERT INTO #Temp2
SELECT 7 UNION ALL
SELECT 1 UNION ALL
SELECT 5 UNION ALL
SELECT 6
SELECT * INTO #TEMP3
FROM (SELECT * FROM #Temp1 UNION ALL SELECT * FROM #temp2) X
UNION ALL adds all the records where as UNION adds only new/distinct records.
Since you are using UNION ALL and using DISTINCT soon after, I think you are looking for UNION
SELECT * INTO #TEMP4 FROM
(
SELECT * FROM #TEMP3
UNION --JUST UNION
SELECT * FROM #TEMP2
) AnotherTemp
Or you can simplify it as
SELECT * INTO #TEMP4 FROM
SELECT DISTINCT *
FROM Final
WHERE MomentId = #MomentId OR RowNum BETWEEN #StartRow AND #EndRow
I'm not familiar with SQL-Server, but you might get my idea
select *, 'A' tid, rownumber() tno from tableA
union all
select *, 'B', rownumber() from tableB
order by tid, tno;
This should get you all records of tableA in their specific order, followed by all records of tableB in their specific order.

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

SQL Query - Using Order By in UNION

How can one programmatically sort a union query when pulling data from two tables? For example,
SELECT table1.field1 FROM table1 ORDER BY table1.field1
UNION
SELECT table2.field1 FROM table2 ORDER BY table2.field1
Throws an exception
Note: this is being attempted on MS Access Jet database engine
Sometimes you need to have the ORDER BY in each of the sections that need to be combined with UNION.
In this case
SELECT * FROM
(
SELECT table1.field1 FROM table1 ORDER BY table1.field1
) DUMMY_ALIAS1
UNION ALL
SELECT * FROM
(
SELECT table2.field1 FROM table2 ORDER BY table2.field1
) DUMMY_ALIAS2
SELECT field1 FROM table1
UNION
SELECT field1 FROM table2
ORDER BY field1
I think this does a good job of explaining.
The following is a UNION query that uses an ORDER BY clause:
select supplier_id, supplier_name
from suppliers
where supplier_id > 2000
UNION
select company_id, company_name
from companies
where company_id > 1000
ORDER BY 2;
Since the column names are different between the two "select" statements, it is more advantageous to reference the columns in the ORDER BY clause by their position in the result set.
In this example, we've sorted the results by supplier_name / company_name in ascending order, as denoted by the "ORDER BY 2".
The supplier_name / company_name fields are in position #2 in the
result set.
Taken from here: http://www.techonthenet.com/sql/union.php
Using a concrete example:
SELECT name FROM Folders ORDER BY name
UNION
SELECT name FROM Files ORDER BY name
Files:
name
=============================
RTS.exe
thiny1.etl
thing2.elt
f.txt
tcpdump_trial_license (1).zip
Folders:
name
============================
Contacts
Desktop
Downloads
Links
Favorites
My Documents
Desired Output: (results of first select first, i.e. folders first)
Contacts
Desktop
Downloads
Favorites
Links
My Documents
f.txt
RTMS.exe
tcpdump_trial_license (1).zip
thiny1.etl
thing2.elt
SQL to achieve the desired results:
SELECT name
FROM (
SELECT 1 AS rank, name FROM Folders
UNION
SELECT 2 AS rank, name FROM Files) dt
ORDER BY rank, name
Here's an example from Northwind 2007:
SELECT [Product ID], [Order Date], [Company Name], [Transaction], [Quantity]
FROM [Product Orders]
UNION SELECT [Product ID], [Creation Date], [Company Name], [Transaction], [Quantity]
FROM [Product Purchases]
ORDER BY [Order Date] DESC;
The ORDER BY clause just needs to be the last statement, after you've done all your unioning. You can union several sets together, then put an ORDER BY clause after the last set.
(SELECT table1.field1 FROM table1
UNION
SELECT table2.field1 FROM table2) ORDER BY field1
Work? Remember think sets. Get the set you want using a union and then perform your operations on it.
SELECT table1Column1 as col1,table1Column2 as col2
FROM table1
UNION
( SELECT table2Column1 as col1, table1Column2 as col2
FROM table2
)
ORDER BY col1 ASC
SELECT field1
FROM ( SELECT field1 FROM table1
UNION
SELECT field1 FROM table2
) AS TBL
ORDER BY TBL.field1
(use ALIAS)
This is the stupidest thing I've ever seen, but it works, and you can't argue with results.
SELECT *
FROM (
SELECT table1.field1 FROM table1 ORDER BY table1.field1
UNION
SELECT table2.field1 FROM table2 ORDER BY table2.field1
) derivedTable
The interior of the derived table will not execute on its own, but as a derived table works perfectly fine. I've tried this on SS 2000, SS 2005, SS 2008 R2, and all three work.
This is how it is done
select * from
(select top 100 percent pointx, pointy from point
where pointtype = 1
order by pointy) A
union all
select * from
(select top 100 percent pointx, pointy from point
where pointtype = 2
order by pointy desc) B
Browsing this comment section I came accross two different patterns answering the question. Sadly for SQL 2012, the second pattern doesn't work, so here's my "work around"
Order By on a Common Column
This is the easiest case you can encounter. Like many user pointed out, all you really need to do is add an Order By at the end of the query
SELECT a FROM table1
UNION
SELECT a FROM table2
ORDER BY field1
or
SELECT a FROM table1 ORDER BY field1
UNION
SELECT a FROM table2 ORDER BY field1
Order By on Different Columns
Here's where it actually gets tricky. Using SQL 2012, I tried the top post and it doesn't work.
SELECT * FROM
(
SELECT table1.field1 FROM table1 ORDER BY table1.field1
) DUMMY_ALIAS1
UNION ALL
SELECT * FROM
(
SELECT table2.field1 FROM table2 ORDER BY table2.field1
) DUMMY_ALIAS2
Following the recommandation in the comment I tried this
SELECT * FROM
(
SELECT TOP 100 PERCENT table1.field1 FROM table1 ORDER BY table1.field1
) DUMMY_ALIAS1
UNION ALL
SELECT * FROM
(
SELECT TOP 100 PERCENT table2.field1 FROM table2 ORDER BY table2.field1
) DUMMY_ALIAS2
This code did compile but the DUMMY_ALIAS1 and DUMMY_ALIAS2 override the Order By established in the Select statement which makes this unusable.
The only solution that I could think of, that worked for me was not using a union and instead making the queries run individually and then dealing with them. So basically, not using a Union when you want to Order By
By using order separately each subset gets order, but not the whole set, which is what you would want uniting two tables.
You should use something like this to have one ordered set:
SELECT TOP (100) PERCENT field1, field2, field3, field4, field5 FROM
(SELECT table1.field1, table1.field2, table1.field3, table1.field4, table1.field5 FROM table1
UNION ALL
SELECT table2.field1, table2.field2, table2.field3, table2.field4, table2.field5 FROM table2)
AS unitedTables ORDER BY field5 DESC
The second table cannot include the table name in the ORDER BY clause.
So...
SELECT table1.field1 FROM table1 ORDER BY table1.field1
UNION
SELECT table2.field1 FROM table2 ORDER BY field1
Does not throw an exception
If necessary to keep the inner sorting:
SELECT 1 as type, field1 FROM table1
UNION
SELECT 2 as type, field1 FROM table2
ORDER BY type, field1
(SELECT FIELD1 AS NEWFIELD FROM TABLE1 ORDER BY FIELD1)
UNION
(SELECT FIELD2 FROM TABLE2 ORDER BY FIELD2)
UNION
(SELECT FIELD3 FROM TABLE3 ORDER BY FIELD3) ORDER BY NEWFIELD
Try this. It worked for me.
For Sql Server 2014/2012/Others(Not Checked) :
SELECT * FROM
(
SELECT table1.field1 FROM table1 ORDER BY table1.field1
)
as DUMMY_ALIAS1
UNION ALL
SELECT * FROM
(
SELECT table2.field1 FROM table2 ORDER BY table2.field1
)
as DUMMY_ALIAS2