SQL: Merge two result set without any conditions - sql

I have two tables like this:
Table1 with column N
N
---
1
2
3
4
5
And Table2 with column M:
M
---
5
9
1
8
1
Finally, I want to combine these two data sets with the same count of rows and also, save source order like this result:
N M
------
1 5
2 9
3 1
4 8
5 1
Can anyone help me?

Assuming you want to view this output we can use a ROW_NUMBER() trick here:
WITH cte1 AS (
SELECT N, ROW_NUMBER() OVER (ORDER BY N) rn
FROM Table1
),
cte2 AS (
SELECT M, ROW_NUMBER() OVER (ORDER BY M DESC) rn
FROM Table2
)
SELECT t1.N, t2.M
FROM cte1 t1
INNER JOIN cte2 t2
ON t2.rn = t1.rn
ORDER BY t1.rn;

According to Tim's answer. Also, this SO answers I could achieve my requirement and save source tables orders.
Like this:
WITH cte1 AS (
SELECT n, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) rn
FROM #TempTable
),
cte2 AS (
SELECT m, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) rn
FROM #TempTable2
)
SELECT t1.n, t2.m
FROM cte1 t1
INNER JOIN cte2 t2
ON t2.rn = t1.rn
ORDER BY t1.rn
Point:
There is no need to worry about specifying constant in the ORDER BY
expression.
Sources:
ROW_NUMBER Without ORDER BY
Tim's answer

Related

SQL Server - Sum of difference between rows in a table

I have a table in the format :
SomeID SomeData
1 3
2 7
3 9
4 10
5 14
6 16
. .
. .
I want to find sum of difference between rows in this table. i.e ( (7-3) + (10-9) + (16-14) + ....)
Which is the best way to do this
Using a self join along with the modulus:
SELECT SUM(t1.SomeData - t2.SomeData) AS total_diff
FROM yourTable t1
INNER JOIN yourTable t2
ON t1.SomeID = t2.SomeID + 1
WHERE t1.SomeID % 2 = 0;
Demo
This answer assumes that the SomeID sequence in fact starts with 1 and increments by 1 with each subsequent row. If not, then we might be able to first apply ROW_NUMBER over SomeID and generate a 1 to N sequence.
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY SomeID) rn
FROM yourTable
)
SELECT SUM(t1.SomeData - t2.SomeData) AS total_diff
FROM cte t1
INNER JOIN cte t2
ON t1.SomeID = t2.SomeID + 1
WHERE t1.rn % 2 = 0;
You can try to use ROW_NUMBER window function to make a serial number then MOD by 2 to get your expected group then use condition aggregate function.
Query 1:
SELECT SUM(CASE WHEN rn = 0 THEN SomeData END) - SUM(CASE WHEN rn = 1 THEN SomeData END)
FROM (
SELECT SomeData,ROW_NUMBER() over(order by SomeID) % 2 rn
FROM t t1
) t1
Results:
| |
|---|
| 7 |

Need Full Outer Join without having Cross Join

Need to join two table without having cross join between them.
The join condition need to be made on Tabl.month = Tab2.month
Input
Table1 Table2
Month ID Month ID
1 a 1 a
1 b 1 b
1 c 2 g
2 d 3 i
2 e 3 j
3 f 3 k
Output:
Month_Tab1 ID_Tab1 Month_Tab2 ID_Tab2
1 a 1 a
1 b 1 b
1 c Null Null
2 d 2 g
2 e Null Null
3 f 3 i
Null Null 3 j
Null Null 3 k
The above o/p is required, without cross join, have tried full outer but cross join is happening as the ID is duplicate in both Tables. Left/Right join also cannt be applicable as either of the table might have larger set of ID's.
You want a full join, but with row_number() to identify the matches:
select t1.month month_tab1, t1.id id_tab1, t2.month month_tab2, t2.id id_tab2
from (
select t.*, row_number() over(partition by month order by id) rn from table1 t
) t1
full join (
select t.*, row_number() over(partition by month order by id) rn from table2 t) t2
on t2.month = t1.month and t2.rn = t1.rn
You can use a full outer join:
select
a.month,
a.id,
b.month,
b.id
from (
select month, id,
row_number() over(partition by month order by id) as n
from table1
) a
full outer join (
select month, id,
row_number() over(partition by month order by id) as n
from table2
) b on b.month = a.month and b.n = a.n
order by coalesce(a.month, b.month), coalesce(a.n, b.n)

Microsoft SQL server to select Top N group

There are a lot of answers about how to select n rows from each group.
But what I am looking for is to select every row from top N group, for example I have the data below:
id group
1 a
2 a
3 b
4 c
5 c
6 d
7 d
.......
If I want to select Top 3 Group, my intended results as below:
1 a
2 a
3 b
4 c
5 c
How can I achieve this with Microsoft SQL server 2008?
One option is to use a subquery which selects the top N groups:
SELECT t1.id, t1.group
FROM yourTable t1
INNER JOIN
(
SELECT DISTINCT TOP(N) group
FROM yourTable
ORDER BY group
) t2
ON t1.group = t2.group
You could rank your rows by the group and then take only the top three:
SELECT [id], [group]
FROM (SELECT [id], [group], RANK() OVER (ORDER BY [group] ASC) rk
FROM mytable) t
WHERE rk <= 3
#Tim: I just modified your query.
SELECT t1.id, t1.group
FROM yourTable t1
INNER JOIN
(
SELECT TOP N group
FROM yourTable
GROUP BY group
--ORDER BY group USE IT IF YOU WANT
) t2
ON t1.group = t2.group

How to set row number()

I have a table like this -
C1 C2 C3
A 20130101 10
A 20130102 10
A 20130103 20
A 20130104 10
I want to set row no like this -
C1 C2 C3 RowNo
A 20130101 10 1
A 20130102 10 2
A 20130103 20 1
A 20130104 10 1
How can I make by query?
or there is only way to loop this table?
Thanks..
I am updated answer with recursive CTE. It build hierarchy tree starting with records with new C3's value and display level as RowNo.
with t as
(select t.*, row_number () over (order by c2) rn from table1 t)
,temp (c2,c3,rn,lvl) AS
(SELECT c2,c3,rn,1 lvl from t t1
where not exists(
select 1 from t t0
where t1.rn=t0.rn+1
and t1.c3=t0.c3
)
UNION ALL
select t1.c2,t1.c3,t1.rn,lvl + 1 AS lvl FROM t t1
join temp t2 on t1.rn=t2.rn+1 and t1.c3=t2.c3)
SELECT c2, c3, lvl rowno FROM temp order by rn;
http://sqlfiddle.com/#!3/4adbd/1
ROW_NUMBER() function can help you to set numbers of rows:
SELECT ROW_NUMBER() over(order by [some field]), *
FROM [your table]
SELECT ROW_NUMBER() over(PARTITION BY [C3] order by [C2]), *
FROM table name

How do I remove duplicates in paging

table1 & table2:
table1 & table2 http://aftabfarda.parsfile.com/1.png
SELECT *
FROM (SELECT DISTINCT dbo.tb1.ID, dbo.tb1.name, ROW_NUMBER() OVER (ORDER BY tb1.id DESC) AS row
FROM dbo.tb1 INNER JOIN
dbo.tb2 ON dbo.tb1.ID = dbo.tb2.id_tb1) AS a
WHERE row BETWEEN 1 AND 7
ORDER BY id DESC
Result:
Result... http://aftabfarda.parsfile.com/3.png
(id 11 Repeated 3 times)
How can I have this output:
ID name row
-- ------ ---
11 user11 1
10 user10 2
9 user9 3
8 user8 4
7 user7 5
6 user6 6
5 user5 7
You could apply distinct before row_number using a subquery:
select *
from (
select row_number() over (order by tbl.id desc) as row
, *
from (
select distinct t1.ID
, tb1.name
from dbo.tb1 as t1
join dbo.tb2 as t2
on t1.ID = t2.id_tb1
) as sub_dist
) as sub_with_rn
where row between 1 and 7
Alternatively to #Andomar's suggestion, you could use DENSE_RANK instead of ROW_NUMBER and rank the rows first (in the subquery), then apply DISTINCT (in the outer query):
SELECT DISTINCT
ID,
name,
row
FROM (
SELECT
t1.ID,
t1.name,
DENSE_RANK() OVER (ORDER BY t1.ID DESC) AS row
FROM dbo.tb1 t1
INNER JOIN dbo.tb2 t2 ON t1.ID = t2.id_tb1
) AS a
WHERE row BETWEEN 1 AND 7
ORDER BY ID DESC
Similar, but not quite the same, although both might boil down to the same query plan, I'm just not sure. Worth testing, I think.
And, of course, you could also try a semi-join instead of a proper join, in the form of either IN or EXISTS, to prevent duplicates in the first place:
SELECT
ID,
name,
row
FROM (
SELECT
ID,
name,
ROW_NUMBER() OVER (ORDER BY ID DESC) AS row
FROM dbo.tb1
WHERE ID IN (SELECT id_tb1 FROM dbo.tb2)
/* Or:
WHERE EXISTS (
SELECT *
FROM dbo.tb2
WHERE id_tb1 = dbo.tb1.ID
)
*/
) AS a
WHERE row BETWEEN 1 AND 7
ORDER BY ID DESC