TSQL - Merge two tables - sql-server

I have a following task: I have two single column tables in a procedure and both of them have the same amount of rows. I'd like to "merge" them so I get a resulting table with 2 columns. I there some easy way for this?
In worst case I could try to add primary key and use INSERT INTO ... SELECT with JOIN but it requires quite big changes in the code I already have so I decided to ask you guys.
Just to explain my answer below, here's the example. I have following tables:
tableA
col1
----
1
2
3
4
tableB
col2
----
a
b
c
d
Resulting table:
col1 | col2
1 | a
2 | b
3 | c
4 | d

You can do this:
SELECT t1.col1, t2.col1 AS col2
INTO NewTable
FROM
(
SELECT col1, ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS RN
FROM table1
) AS t1
INNER JOIN
(
SELECT col1, ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS RN
FROM table2
) AS t2 ON t1.rn = t2.rn
This will create a brand new table NewTable with the two columns from the two tables:
| COL1 | COL2 |
---------------
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | d |
See it in action here:
SQL Fiddle Demo.

Related

sql - match two of the same values in different column positions

I am looking to join two different tables on the id, and need to extract unique names out of each table; if one table has a certain name but the other doesn't, there should be one value and one null. This should be vice versa as well.
With joins, the current output looks like this:
id name_1 name_2
1 max steph
1 max john
1 john chris
1 john chris
1 chris steph
1 chris null
1 null max
1 null null
1 tony john
1 tony max
expected output:
id name_1 name_2
1 max max
1 john john
1 chris chris
1 null steph
1 tony null
current sql:
select
table1.id,
table1.name as name_1,
table2.name as name_2
from table1
left join table2
on table1.id = table2.id
(snowflake)
SELECT
NVL(d1.id, d2.id) as id,
d1.name as name_1,
d2.name as name_2
FROM (
SELECT DISTINCT id,name FROM table1
) AS d1
FULL OUTER JOIN (
SELECT DISTINCT id,name FROM table2
) AS d2
ON d1.id = d2.id AND d1.name = d2.name
ORDER BY 1, (d1.name,d2.name)
This takes the distinct id,name pairs from both table, then full outer joins those sets of values. Thus if the id,name are in both they match. And if they don't match they are still keep.
So with these CTE's providing the fake data:
WITH table1(id,name) AS (
select * from values (1,'aa'),(1,'ab'),(2,'ba')
), table2(id,name) AS (
select * from values (1,'aa'),(1,'ac'),(2,'ba'),(2,'bb')
)
ID
NAME_1
NAME_2
1
aa
aa
1
ab
null
1
null
ac
2
ba
ba
2
null
bb
Following can be used for this -
with cte as
(
select distinct t1.id,name_1 from t1)
select distinct ifnull(t2.id,cte.id) id,
cte.name_1,
t2.name_2
from t2 full outer join cte
ON cte.id=t2.id
and cte.name_1 = t2.name_2
order by cte.name_1;
+----+--------+--------+
| ID | NAME_1 | NAME_2 |
|----+--------+--------|
| 1 | chris | chris |
| 1 | john | john |
| 1 | max | max |
| 1 | tony | NULL |
| 1 | NULL | steph |
+----+--------+--------+
Add a WHERE clause.
select
table1.id,
table1.name as name_1,
table2.name as name_2
from table1
left join table2
WHERE table1.name = table2.name
OR table1.name is null
OR table2.name is null
on table1.id = table2.id
If you just need a list of unique names
select distinct name from table1
union
select distinct name from table2
Simeons answer is the way to go since snowflake supports full outer joins. But for those of you that use a relational database that lacks support for full outer joins, and have the same issue, this approach can be an alternative:
select id,
if(instr(group_concat(tb), 1), name, NULL) name_1,
if(instr(group_concat(tb), 2), name, NULL) name_2
from(
select id, name, 1 tb from table1
union
select id, name, 2 tb from table2
) a
group by id, name
order by name
The result:
| id | name_1 | name_2 |
| --- | ------ | ------ |
| 1 | chris | chris |
| 1 | john | john |
| 1 | max | max |
| 1 | null | steph |
| 1 | tony | null |
Fake data:
CREATE TABLE table1 (
id int(11),
name varchar(50)
);
CREATE TABLE table2 (
id int(11),
name varchar(50)
);
INSERT INTO table1 VALUES
(1, 'max'),
(1, 'john'),
(1, 'chris'),
(1, 'tony');
INSERT INTO table2 VALUES
(1, 'steph'),
(1, 'john'),
(1, 'chris'),
(1, 'max');
And a dbfiddle: https://www.db-fiddle.com/f/gQ4U7hu2S2EyFEtZrapqdu/6

How to return starting and end point of a path in a hierarchical structure

I have a table that looks like that
---------------------------
| id1 | id2 | col1 | col2 |
+-----+-----+------+------+
| 1 | 1 | a | b |
|-----+-----+------+------|
| 1 | 2 | b | c |
|-----+-----+------+------|
| 5 | 1 | d | f |
---------------------------
The idea is that the table stores paths: a->b->c and d->f. What I want is a query that will return a->c and d->f.
You need a recursive query:
with recursive find_path (col1, col2, depth) as (
select col1, col2, 1
from my_table t
where not exists (
select 1
from my_table
where col2 = t.col1)
union all
select p.col1, t.col2, depth+ 1
from my_table t
join find_path p on p.col2 = t.col1
)
select distinct on (col1) format('%s -> %s', col1, col2) as path
from find_path
order by col1, depth desc;
path
--------
a -> c
d -> f
(2 rows)
The question is not quite clear. If your aim is to get the paths in partitions by id1 in order by id2, you can use the window functions:
select distinct on (id1)
id1, first_value(col1) over w, last_value(col2) over w
from my_table
window
w as (partition by id1 order by id2)
order by id1, id2 desc;
id1 | first_value | last_value
-----+-------------+------------
1 | a | c
5 | d | f
(2 rows)
I think you might mean
select a, b, c from whateveryourtablenameis;
and include whatever columns you want in addition to a, b, and c.
This would return just columns a, b, and c. I know of no way to ask SQL for a range of columns other than *.

While numbering the record of a difference only in the SQL server, you want to get

In SQL server, I want to realize that such following manner,
I want to have only resolve SQL
Someone, please tell me.
Table A
col1
---------
AAAAA
BBBBB
CCCCC
DDDDD
EEEEE
Table B
id | col1 | insertDate
------------------
1 | AAAAA | 2015/4/1
2 | BBBBB | 2015/4/1
3 | CCCCC | 2015/4/1
The expected table
(SQL execution: 2015/4/2)
id | col1 | insertDate
------------------
1 | AAAAA | 2015/4/1
2 | BBBBB | 2015/4/1
3 | CCCCC | 2015/4/1
4 | DDDDD | 2015/4/2
5 | EEEEE | 2015/4/2
I want to create a SQL that you can get a table as described above
SQL to extract the record is not in the table A was able to
select
ROW_NUMBER() over(order by col1) as id,
col1,
SYSDATETIME() as insertDate
from A
where
not exists(
select col1
from B
where B.col1 = A.col1
)
Use LEFT JOIN to get all the rows from TableA but only the matching rows from TableB. Then just check if TableB.insertDate IS NULL.
SELECT ROW_NUMBER() OVER (ORDER BY col1) AS id
, col1
, ISNULL(TableB.insertDate, SYSDATETIME()) AS insertDate
FROM TableA
LEFT JOIN TableB
ON TableA.col1 = TableB.col1
Try with this
SELECT ROW_NUMBER() OVER (ORDER BY tablea.col1) AS id
,tablea.col1
,ISNULL(TableB.insertDate, SYSDATETIME()) AS insertDate
FROM TableA
LEFT JOIN TableB
ON TableA.col1 = TableB.col1
(OR)
SELECT ROW_NUMBER() OVER (ORDER BY tablea.col1) AS id
,tablea.col1
,ISNULL(TableB.insertDate, dateadd(day,-1,SYSDATETIME()) )AS insertDate
FROM TableA
LEFT JOIN TableB
ON TableA.col1 = TableB.col1
Hope this will help you.

How to select last occurrence of duplicating record in oracle

I am having a problem with Oracle query where the basic goal is to get the last row of every re-occurring rows, but there's a complication that you'll understand from the data:
Suppose I have a table that looks like this:
ID | COL1 | COL2 | COL3 | UPDATED_DATE
------|------|------|------|-------------
001 | a | b | c | 14/05/2013
002 | a | b | c | 16/05/2013
003 | a | b | c | 12/05/2013
You should be able to guess that since columns 1 to 3 have the same values for all 3 rows they are re-occurring data. The problem is, I want to get the latest updated row, which means row #2.
I have an existing query that works if the table is without ID column, but I still need that column, so if anybody could help me point out what I'm doing wrong, that'd be great.
select col1,
col2,
col3,
max(updated_date)
from tbl
order by col1, col2, col3;
The above query returns me row #2, which is correct, but I still need the ID.
Note: I know that I could have encapsulate the above query with another query that selects the ID column based on the 4 columns, but since I'm dealing with millions of records, the re-query will make the app very ineffective.
Try
WITH qry AS
(
SELECT ID, COL1, COL2, COL3, updated_date,
ROW_NUMBER() OVER (PARTITION BY COL1, COL2, COL3 ORDER BY updated_date DESC) rank
FROM tbl
)
SELECT ID, COL1, COL2, COL3, updated_date
FROM qry
WHERE rank = 1
or
SELECT t1.ID, t2.COL1, t2.COL2, t2.COL3, t2.updated_date
FROM tbl t1 JOIN
(
SELECT COL1, COL2, COL3, MAX(updated_date) updated_date
FROM tbl
GROUP BY COL1, COL2, COL3
) t2 ON t1.COL1 = t2.COL1
AND t1.COL2 = t2.COL2
AND t1.COL3 = t2.COL3
AND t1.updated_date = t2.updated_date
Output in both cases:
| ID | COL1 | COL2 | COL3 | UPDATED_DATE |
--------------------------------------------------------
| 2 | a | b | c | May, 16 2013 00:00:00+0000 |
Here is SQLFiddle demo for both queries.

Sort/Merge without cursor

Without using a cursor, I am trying to come up with T-SQL code that would accomplish the following:
On the following table,
SourceData
that has two columns, [ColA] and [ColB], where both are nvarchar(255), with the following example data:
ColA | ColB
==================
AAA | TripleA
TripleA | AAA
AAA | ThreeAs
ThreeAs | AAA
BBB | TripleB
TripleB | BBB
BBB | ThreeBs
ThreeBs | BBB
etc.,
extract the row data into TWO tables,
TableA_Root, and TableB_Children
Where TableA_Root has these columns: [ROID identity], [Root]
and TableB_Children has these columns: [COID identity],[fKey_ROID],[Child]
Such that the resulting table has the example data as such:
TableA_Root
==============
1 | AAA
2 | BBB
TableB_Children
===============
1 | 1 | TripleA
2 | 1 | ThreeAs
3 | 2 | TripleB
4 | 2 | ThreeBs
At first, I thought I would use a Cursor. But, that is not the optimal approach, I am sure. Obviously, this is a sort and merge, which I could do outside of SQL. Some of the ideas I have tried with subqueries using "IN" or "EXISTS" but my attempts are falling short. I could use a fresh perspective.
Assuming there is a primary key on SourceData where you can't have duplicates of the same row then this would get you what you want...
With cte1 As
(
Select Row_Number() Over (Order By ph) As ph,
ColA,
ColB
From (Select 1 As ph,
ColA,
ColB
From SourceData) As n
)
Insert TableA_Root (ROID, Root)
Select Row_Number() Over (Order By c.ph) As ROID,
ColA
From cte1 c
Where Not Exists (Select 1
From cte1 c2
Where c.ColA = c2.ColB
And c.ph > c2.ph);
Insert TableB_Children (COID, ROID, Child)
Select Row_Number() Over (Order By ta.ROID),
ta.ROID,
tb.Colb
From TableA_Root ta
Join SourceData tb
On ta.Root = tb.ColA;

Resources