Using UNION withing ORDER in SQL Server - sql

I want to retrieve latest records of two tables using UNION, it returns data, but not latest records, even with ORDER BY. It's my query:
SELECT TOP(1) OwnerID,NewsTitle,NewsCreationDate,NewsTitle,NewsEnglishName
FROM TheaterNews
UNION
SELECT TOP(3) OwnerID,NewsTitle,NewsCreationDate,NewsTitle,NewsEnglishName
FROM MoviesNews
ORDER BY 3 DESC
This is query's output:
But the latest record of TheaterNews is newer:
SELECT OwnerID,NewsTitle,NewsCreationDate,NewsTitle,NewsEnglishName
FROM TheaterNews
ORDER BY NewsCreationDate DESC
How can I fix this? even with another method.

The order by applies to the entire result of the union, not the separate queries, so the top is applied before the result is sorted.
Use subqueries to order the separate results:
SELECT * FROM (
SELECT TOP(1) OwnerID,NewsTitle,NewsCreationDate,NewsTitle,NewsEnglishName
FROM TheaterNews
ORDER BY 3 DESC
) x
UNION
SELECT * FROM (
SELECT TOP(3) OwnerID,NewsTitle,NewsCreationDate,NewsTitle,NewsEnglishName
FROM MoviesNews
ORDER BY 3 DESC
) y

Because top clause is getting executed before order by clause. try this
Select * from (SELECT TOP(1) OwnerID,NewsTitle,NewsCreationDate,
NewsEnglishName
FROM TheaterNews ORDER BY 3 DESC) as tn
UNION
Select * From (SELECT TOP(3)
OwnerID,NewsTitle,NewsCreationDate,NewsEnglishName
FROM MoviesNews ORDER BY 3 DESC) as mn
ORDER BY 3 DESC
The outer order by will order the union result

This should work in your instance. Might be a rough solution but you will get your answers. you can replace the #tables with #tables.
SELECT TOP(1)
OwnerID,
NewsTitle,
NewsCreationDate,
NewsEnglishName
into
#Table1
FROM
TheaterNews
ORDER BY 3 DESC
SELECT TOP(3)
OwnerID,
NewsTitle,
NewsCreationDate,
NewsEnglishName
into
#Table2
FROM
MoviesNews
ORDER BY 3 DESC
select * from #Table1
union
select * from #Table2
drop table #Table1
drop table #Table2

Try this:
Select * From ( SELECT TOP(1) OwnerID,NewsTitle,NewsCreationDate,NewsTitle,NewsEnglishName
FROM TheaterNews ORDER BY NewsCreationDate DESC) as tempA
UNION
Select * From ( SELECT TOP(3) OwnerID,NewsTitle,NewsCreationDate,NewsTitle,NewsEnglishName
FROM MoviesNews ORDER BY NewsCreationDate DESC) as tempB

Related

Select rows with same ID/email but different value in other table

Select rows with same ID/email but different value in other table
I have two tables: person and email, now there are mail addresses that have the same value, and persons/ID with different values.
Can anyone tell how to write an SQL query for this? I have tried but I can't figure it out. I have found some answers but then it is always finding the match in the same table
Like this
Table_person. ​​Table_email
1​​​ email#persoon1
2​​​ email#persoon2
3​​​ email#persoon3
4​​​ email#persoon1
5​​​ email#persoon5
6​​​ email#persoon2
The output should be
Table_person​​ Table_email
1​​​ email#persoon1
4​​​ email#persoon1
2​​​ email#persoon2
6​​​ email#persoon2
Using a common table expression with row_number()
;with cte as (
select *
, rn = row_number() over (partition by email order by person_id)
from email e
)
select *
from cte
where exists (
select 1
from cte i
where i.email = cte.email
and rn > 1
)
or using exists()
select *
from email e
where exists (
select 1
from email i
where i.email = e.email
and i.person_id <> e.person_id
)
rextester demo: http://rextester.com/JHFEF82373
Hope it will helps you
;with cte(Table_person,​​Table_email)
AS
(
SELECT 1​​​,'email#persoon1' UNION ALL
SELECT 2​​​,'email#persoon2' UNION ALL
SELECT 3​​​,'email#persoon3' UNION ALL
SELECT 4​​​,'email#persoon1' UNION ALL
SELECT 5​​​,'email#persoon5' UNION ALL
SELECT 6​​​,'email#persoon2'
)
,Cte2
AS
(
SELECT Table_person,​​Table_email From
(
Select Table_person,​​Table_email,ROW_NUMBER()OVER(Partition by Table_email Order By Table_person )Seq
from cte
)dt WHERE dt.Seq>1
)
,Final
AS
(
SELECT Table_person,​​Table_email From
(
Select Table_person,​​Table_email,ROW_NUMBER()OVER(Partition by Table_email Order By Table_email )Seq2
from cte
)dt
where dt.Seq2>1
Union ALL
SELECT Table_person,​​Table_email From cte2
)
SELECt Table_person,​​Table_email from Final

Need to join 3 select queries that refers to same table

I am using SQL Server Express 2014 and I need to pull out the last record for few (3 for now) tags with different IDs from one table.
So far I made it but not at all. I am using
SELECT TOP 1 [TagItemId], [TagValue]
FROM [DB].[dbo].[Table]
where [TagItemId] like 'Random.Int1'
order by [TagTimestamp] desc
SELECT TOP 1 [TagItemId], [TagValue]
FROM [DB].[dbo].[Table]
where [TagItemId] like 'Random.Int2'
order by [TagTimestamp] desc
SELECT TOP 1 [TagItemId], [TagValue]
FROM [DB].[dbo].[Table]
where [TagItemId] like 'Random.Int3'
order by [TagTimestamp] desc
and the result is what I need, but not exactly. I need to get the three results in single table like:
TagItemId TagValue
Random.Int1 55
Random.Int2 75
Random.Int3 23`
and not like:
TagItemId TagValue
Random.Int1 55
TagItemId TagValue
Random.Int2 75
TagItemId TagValue
Random.Int3 23`
The reason is that I need to use the data for a chart.
Best regards and thanks!
You could do this using Row_Number
SELECT [TagItemId],
[TagValue]
FROM
(
SELECT [TagItemId],
[TagValue],
ROW_NUMBER() OVER (PARTITION BY [TagItemId] ORDER BY [TagTimestamp] DESC) Rn
FROM [DB].[dbo].[Table]
WHERE [TagItemId] IN ('Random.Int1','Random.Int2','Random.Int3')
) t
WHERE Rn = 1
There are several ways to accomplish this:
SELECT
MT.TagItemID,
MT.TagValue
FROM
My_Table MT
INNER JOIN
(
SELECT TagItemID, MAX(TagTimestamp)
FROM My_Table
WHERE
MT.TagItemID IN ('Random.Int1', 'Random.Int2', 'Random.Int3')
GROUP BY TagItemID) SQ ON SQ.TagItemID = MT.TagItemID
WHERE
MT.TagItemID IN ('Random.Int1', 'Random.Int2', 'Random.Int3')
Or:
SELECT
MT.TagItemID,
MT.TagValue
FROM
My_Table MT
WHERE
MT.TagItemID IN ('Random.Int1', 'Random.Int2', 'Random.Int3') AND
NOT EXISTS (SELECT * FROM My_Table MT2 WHERE MT2.TagItemID = MT.TagItemID AND MT2.Timestamp > MT.Timestamp)
Or:
;WITH CTE_WithRowNums AS
(
SELECT
MT.TagItemID,
MT.TagValue,
ROW_NUMBER() OVER(PARTITION BY TagItemID ORDER BY Timestamp DESC) AS row_num
FROM
My_Table MT
)
SELECT
TagItemID,
TagValue
FROM
CTE_WithRowNums
WHERE
row_num = 1
Could you not just do a simple UNION ALL
select * from
(SELECT TOP 1 [TagItemId], [TagValue]
FROM [DB].[dbo].[Table]
where [TagItemId] like 'Random.Int1'
order by [TagTimestamp] desc )
UNION ALL
select * from
(SELECT TOP 1 [TagItemId], [TagValue]
FROM [DB].[dbo].[Table]
where [TagItemId] like 'Random.Int2'
order by [TagTimestamp] desc )
UNION ALL
select * from
(SELECT TOP 1 [TagItemId], [TagValue]
FROM [DB].[dbo].[Table]
where [TagItemId] like 'Random.Int3'
order by [TagTimestamp] desc )
Probably crashed because each select TOP had an order by, so I "wrapped" the queries into select * so each subquery could retain its own ORDER BY clause

SQL Server need top 1 record for one column and all other records

I need to have one query for to select all records of KitchenBlinkSound='Y' plus top 1 of KitchenBlinkSound='N', here is my table structure.
And my requested result will be OrderNo 225,226,227. Basically it contains all KitchenBlinkSound='Y' records plus top 1 of KitchenBlinkSound='N' record.
SELECT * FROM TABLE WHERE KitchenBlinkSound='Y'
UNION ALL
SELECT TOP 1 * FROM TABLE WHERE KitchenBlinkSound='N'
ORDER BY ORDERNO
UPDATE
SELECT TOP 3 * FROM
(
SELECT * FROM #TABLE1 WHERE KitchenBlinkSound='Y'
UNION ALL
SELECT ORDERNO,KITCHENSTATUS,KitchenBlinkSound FROM
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY KitchenBlinkSound ORDER BY ORDERNO ASC) RNO
FROM #TABLE1 WHERE KitchenBlinkSound='N'
)TAB
WHERE TAB.RNO=1
)MAIN
As sub-queries doesn't allow ORDER BY, ROW_NUMBER() is added in order to make sure that you are selecting the TOP 1 ORDERNO in ascending order. If you want to take in descending order change ASC to DESC.
Select * from [your table name] where KitchenBlickSound = 'Y'
UNION
Select TOP 1 * from [your table name] where KitchenBlickSound = 'N'

How can I get the n-th row in the Query results?

How can I get the n-th row of a TSQL query results?
Let's say, I want to get the 2nd row of this SELECT:
SELECT * FROM table
ORDER BY 2 ASC
What version of SQL Server are you targeting? If 2005 or greater, you can use ROW_NUMBER to generate a row number and select using that number. http://msdn.microsoft.com/en-us/library/ms186734.aspx
WITH orderedtable AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY <your order here>) AS 'RowNumber'
FROM table
)
SELECT *
FROM orderedtable
WHERE RowNumber = 2;
You can use a trick combining TOP with ORDER BY ASC/DESC to achieve an effect similar to MySQL's LIMIT:
SELECT TOP 2 * INTO #temptable FROM table
ORDER BY 2 ASC
SELECT TOP 1 * FROM #temptable
ORDER BY 2 DESC
or without temptable, but nested statements:
SELECT TOP 1 * FROM
(
SELECT TOP 2 * FROM table
ORDER BY 2 ASC
) sub
ORDER BY 2 DESC
The first time you select all rows up to the one you want to actually have, and in the second query you select only the first of the remaining when ordering them reversely, which is exactly the one you want.
Source: http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=850&lngWId=5
One way;
;with T(rownumber, col1, colN) as (
select
row_number() over (order by ACOLUMN) as rownumber,
col1,
colN
from
atable
)
select * from T where rownumber = 2

Select top and bottom rows

I'm using SQL Server 2005 and I'm trying to achieve something like this:
I want to get the first x rows and the last x rows in the same select statement.
SELECT TOP(5) BOTTOM(5)
Of course BOTTOM does not exist, so I need another solution. I believe there is an easy and elegant solution that I'm not getting. Doing the select again with GROUP BY DESC is not an option.
Using a union is the only thing I can think of to accomplish this
select * from (select top(5) * from logins order by USERNAME ASC) a
union
select * from (select top(5) * from logins order by USERNAME DESC) b
Check the link
SQL SERVER – How to Retrieve TOP and BOTTOM Rows Together using T-SQL
Did you try to using rownumber?
SELECT *
FROM
(SELECT *, ROW_NUMBER() OVER (Order BY columnName) as TopFive
,ROW_NUMBER() OVER (Order BY columnName Desc) as BottomFive
FROM Table
)
WHERE TopFive <=5 or BottomFive <=5
http://www.sqlservercurry.com/2009/02/select-top-n-and-bottom-n-rows-using.html
I think you've two main options:
SELECT TOP 5 ...
FROM ...
ORDER BY ... ASC
UNION
SELECT TOP 5 ...
FROM ...
ORDER BY ... DESC
Or, if you know how many items there are in the table:
SELECT ...
FROM (
SELECT ..., ROW_NUMBER() OVER (ORDER BY ... ASC) AS intRow
FROM ...
) AS T
WHERE intRow BETWEEN 1 AND 5 OR intRow BETWEEN #Number - 5 AND #Number
Is it an option for you to use a union?
E.g.
select top 5 ... order by {specify columns asc}
union
select top 5 ... order by {specify columns desc}
i guess you have to do it using subquery only
select * from table where id in (
(SELECT id ORDER BY columnName LIMIT 5) OR
(SELECT id ORDER BY columnName DESC LIMIT 5)
)
select * from table where id in (
(SELECT TOP(5) id ORDER BY columnName) OR
(SELECT TOP(5) id ORDER BY columnName DESC)
)
EDITED
select * from table where id in (
(SELECT TOP 5 id ORDER BY columnName) OR
(SELECT TOP 5 id ORDER BY columnName DESC)
)
No real difference between this and the union that I'm aware of, but technically it is a single query.
select t.*
from table t
where t.id in (select top 5 t2.id from table t2 order by MyColumn)
or
t.id in (select top 5 t2.id from table t2 order by MyColumn desc);
SELECT *
FROM (
SELECT x, rank() over (order by x asc) as rown
FROM table
) temp
where temp.rown = 1
or temp.rown = (select count(x) from table)
Then you are out - doing the select again IS the only option, unless you want to pull in the complete result set and then throwing away everything in between.
ANY sql I cna think of is the same way - for the bottom you need to know first either how many items you have (materialize everything or use count(*)) or a reverse sort order.
Sorry if that does not suit you, but at the end.... reality does not care, and I do not see any other way to do that.
I had to do this recently for a very large stored procedure; if your query is quite large, and you want to minimize the amount of queries you could declare a #tempTable, insert into that #tempTable then query from that #tempTable,
DECLARE #tempTable TABLE ( columns.. )
INSERT INTO #tempTable
VALUES ( SELECT.. your query here ..)
SELECT TOP(5) columns FROM #tempTable ORDER BY column ASC -- returns first to last
SELECT TOP(5) columns FROM #tempTable ORDER BY column DESC -- returns last to first