In SQL Server, is it possible to, in a single query regardless of how complex, combine two table in the manner below?
Using a 'full join' I'll have to choose the .name from both tables resulting in duplicate columns, and using a 'union all' I'll get duplicates rows.
Table 1:
+---------+--------+
| name | value1 |
+---------+--------+
| Abel | a |
| Baker | b |
+---------+--------+
Table 2:
+---------+--------+
| name | value2 |
+---------+--------+
| Baker | x |
| Charlie | y |
+---------+--------+
Query output:
+---------+--------+--------+
| name | value1 | value2 |
+---------+--------+--------+
| Abel | a | NULL |
| Baker | b | x |
| Charlie | NULL | y |
+---------+--------+--------+
Using FULL OUTER JOIN you can achieve your expectation.
CREATE TABLE #table1 (name varchar (200), value1 VARCHAR(200))
INSERT INTO #table1
SELECT 'Abel', 'a' UNION
SELECT 'Baker', 'b'
GO
CREATE TABLE #table2 (name varchar (200), value2 VARCHAR(200))
INSERT INTO #table2
SELECT 'Baker', 'x' UNION
SELECT 'Charlie', 'y'
GO
SELECT ISNULL(t1.name, t2.name) AS name, t1.value1, t2.value2
FROM #table1 t1
FULL OUTER JOIN #table2 t2 ON t2.name = t1.name
DROP TABLE #table1
DROP TABLE #table2
Related
Edit: Trying to query a XML Path list that has been narrowed down by a case statement. Column 'displayname' contains over 700 unique values throughout the database. However, based on other criteria including the AccountID and if RenderedValue is = '', the remaining results will most likely be less than 5. The variables in my query is I cannot explicitly declare an Account Id or DisplayName.
I have a successful CASE statement on it's own. But trying to also have the XML PATH statement pulls all the data from the table and comma separates it instead of just the results from the previous CASE statement. Can't figure out how to nest them together. Besides the GUID in column 1, values are nvarchar.
Query w/o CASE
select tb1.AccountID,
tb3.DisplayName,
tb4.RenderedValue
from Accounts tb1
join Display tb2 on tb2.AccountID = tb1.AccountID
inner join ExtractDetail tb3 on tb3.ExtractID = tb2.ExtractID
left join ExtractDetailData tb4 on tb4.ExtractDetailID = tb3.ExtractDetailID
result:
+-----------+---------------+-----------------------+
| AccountID | DisplayName | RenderedValue |
+-----------+---------------+-----------------------+
| E8175 | FirstName | John |
| E8175 | LastName | Smith |
| E8175 | StreetAddress | 123 Washington Street |
| E8175 | City | |
| E8175 | State | NY |
| E8175 | ZipCode | |
| E8175 | PhoneNumber | 555-555-5555 |
| E8175 | Email | JohnSmith#aol.com |
+-----------+---------------+-----------------------+
Query w/ CASE
select tb1.AccountID,
CASE When tb4.RenderedValue = ''
Then tb3.DisplayName
Else ''
End As MissingField
from Accounts tb1
join Display tb2 on tb2.AccountID = tb1.AccountID
inner join ExtractDetail tb3 on tb3.ExtractID = tb2.ExtractID
left join ExtractDetailData tb4 on tb4.ExtractDetailID = tb3.ExtractDetailID
Where tb4.RenderedValue =''
Result:
+-----------+--------------+
| AccountID | MissingField |
+-----------+--------------+
| E8175 | City |
| E8175 | ZipCode |
+-----------+--------------+
Expected Output:
+-----------+--------------+
| AccountID | MissingField |
+-----------+--------------+
| E8175 | City,ZipCode |
+-----------+--------------+
i think this code will help you
create table #temp (AccountID varchar(20),DisplayName varchar(20),RenderedValue varchar(255))
insert into #temp (AccountID,DisplayName,RenderedValue) values
('E8175','FirstName','John')
insert into #temp (AccountID,DisplayName,RenderedValue) values
('E8175','LastName','Smith')
insert into #temp (AccountID,DisplayName,RenderedValue) values
('E8175','StreetAddress','123 Washington Street')
insert into #temp (AccountID,DisplayName,RenderedValue) values ('E8175','City','')
insert into #temp (AccountID,DisplayName,RenderedValue) values
('E8175','State','NY')
insert into #temp (AccountID,DisplayName,RenderedValue) values
('E8175','ZipCode','')
insert into #temp (AccountID,DisplayName,RenderedValue) values
('E8175','PhoneNumber','555-555-5555 ')
insert into #temp (AccountID,DisplayName,RenderedValue) values
('E8175','Email','JohnSmith#aol.com')
SELECT distinct
P.AccountID,
STUFF
(
(
SELECT ',' + case when RenderedValue = '' Then DisplayName Else '' End
FROM #temp M
FOR XML PATH(''), type
).value('.', 'varchar(max)'), 1, 1, ''
) AS Temp
FROM
#temp P
Drop table #temp
I'm currently trying to track the changes of a few columns (let's call them col1 & col2) in a SQL Server table. The table is not being "updated/inserted/deleted" over time; new records are just being added to it (please see below 10/01 vs 11/01).
My end-goal would be to run a SQL query or stored procedure that would highlight the changes overtime using primary keys following the framework:
PrimaryKey | ColumnName | BeforeValue | AfterValue | Date
e.g.
Original table:
+-------+--------+--------+--------+
| PK1 | Col1 | Col2 | Date |
+-------+--------+--------+--------+
| 1 | a | e | 10/01 |
| 1 | b | e | 11/01 |
| 2 | c | e | 10/01 |
| 2 | d | f | 11/01 |
+-------+--------+--------+--------+
Output:
+--------------+--------------+---------------+--------------+--------+
| PrimaryKey | ColumnName | BeforeValue | AfterValue | Date |
+--------------+--------------+---------------+--------------+--------+
| 1 | Col1 | a | b | 11/01 |
| 2 | Col1 | c | d | 11/01 |
| 2 | Col2 | e | f | 11/01 |
+--------------+--------------+---------------+--------------+--------+
Any help appreciated.
Here is some code which is a bit clunky, but seems to work, Basically for each row I try and find an earlier row with a different value. This is done twice, once for Col1 and once for Col2.
To make it work I had to add a unique PK field, which I don't know whether you have or not, you can easily add as an identify field, either to your real table, or to the table used for the calculations.
declare #TestTable table (PK int, PK1 int, Col1 varchar(1), Col2 varchar(1), [Date] date)
insert into #TestTable (PK, PK1, Col1, Col2, [Date])
select 1, 1, 'a', 'e', '10 Jan 2018'
union all select 2, 1, 'b', 'e', '11 Jan 2018'
union all select 3, 2, 'c', 'e', '10 Jan 2018'
union all select 4, 2, 'd', 'f', '11 Jan 2018'
select T1.[Date], T1.PK1, 'Col1', T2.Col1, T1.Col1
from #TestTable T1
inner join #TestTable T2 on T2.PK = (
select top 1 PK
from #TestTable T21
where T21.PK1 = T1.PK1 and T21.Col1 != T1.Col1 and T21.[Date] < T1.[Date]
order by T21.[Date] desc
)
union all
select T1.[Date], T1.PK1, 'Col2', T3.Col2, T1.Col2
from #TestTable T1
inner join #TestTable T3 on T3.PK = (
select top 1 PK
from #TestTable T31
where T31.PK1 = T1.PK1 and T31.Col2 != T1.Col2 and T31.[Date] < T1.[Date]
order by T31.[Date] desc
)
order by [Date], PK1
I am new in Oracle SQL and I am trying to make an update of a table with the next context:
I have a table A:
+---------+---------+---------+----------+
| ColumnA | name | ColumnC | Column H |
+---------+---------+---------+----------+
| 1 | Harry | null | null |
| 2 | Harry | null | null |
| 3 | Harry | null | null |
+---------+---------+---------+----------+
And a table B:
+---------+---------+---------+
| name | ColumnE | ColumnF |
+---------+---------+---------+
| Harry | a | d |
| Ron | b | e |
| Hermione| c | f |
+---------+---------+---------+
And I want to update the table A so that the result will be the next:
+---------+---------+---------+----------+
| ColumnA | name | ColumnC | Column H |
+---------+---------+---------+----------+
| 1 | Harry | a | d |
| 2 | Harry | a | d |
| 3 | Harry | a | d |
+---------+---------+---------+----------+
How could I do it?
merge into tableA a
using tableB b
on (a.name=b.name)
when matched then update set
columnC = b.columnE,
columnH = b.columnF
create table tableA (columnC varchar2(20), columnH varchar2(20), name varchar2(20), columnA number);
create table tableB (columnE varchar2(20), columnF varchar2(20), name varchar2(20));
insert into tableA values (null, null,'Harry',1);
insert into tableA values (null, null,'Harry',3);
insert into tableA values (null, null,'Harry',3);
insert into tableB values ('a', 'd','Harry');
insert into tableB values ('b', 'e','Ron');
insert into tableB values ('c', 'f','Hermione');
select * from tableA;
merge into tableA a
using tableB b
on (a.name=b.name)
when matched then update set
columnC = b.columnE,
columnH = b.columnF;
select * from tableA;
I got no error
UPDATE tableA t1
SET (ColumnC, ColumnH) = (SELECT t2.ColumnE, t2.ColumnF
FROM table2 t2
WHERE t1.name = t2.name)
WHERE EXISTS (
SELECT 1
FROM table2 t2
WHERE t1.name = t2.name)
This should work. You can refer to this answer for more info:
Oracle SQL: Update a table with data from another table
I think you can use below query and update your table A.
Update all rows with 'a' and 'd';
update table A
set (columnC , columnh ) = (SELECT COLUMNE,COLUMNF
FROM TABLE B
where b.name =a.name);
Alternatively you can also use:
UPDATE (SELECT T2.COLUMNE COLE,
T2.COLUMNF COLF,
T1.COLUMNC COLC,
T1.COLUMNH COLH
FROM tableB T2,
tableA T1
WHERE T1.NAME = T2.NAME)
SET COLC = COLE,
COLH = COLF ;
and Output is :
+---------+---------+---------+----------+
| ColumnA | name | ColumnC | Column H |
+---------+---------+---------+----------+
| 1 | Harry | a | d |
| 2 | Harry | a | d |
| 3 | Harry | a | d |
+---------+---------+---------+----------+
I have a table with three columns with double values, but no double rows. Now I want to split this table in two table with unique values and a link table. I think the Problem gets clearer when I Show you example tables:
Original:
| ID | Column_1 | Column_2 | Column_3 |
|----|----------|----------|----------|
| 1 | A | 123 | A1 |
| 2 | A | 123 | A2 |
| 3 | B | 234 | A2 |
| 4 | C | 456 | A1 |
Table_1
| ID | Column_1 | Column_2 |
|----|----------|----------|
| 1 | A | 123 |
| 2 | B | 234 |
| 3 | C | 456 |
Table_2
| ID | Column_3 |
|----|----------|
| 1 | A1 |
| 2 | A2 |
Link-Table
| ID | fk1 | fk2 |
|----|-----|-----|
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 2 |
| 4 | 3 | 1 |
Table_1 I created like this:
INSERT INTO Table_1(Column_1, Column_2)
SELECT DISTINCT Column_1, Column_2 FROM Original
WHERE Original.Column_1 NOT IN (SELECT Column_1 FROM Table_1)
Table_2 I created in the same way.
The question now is, how to create the Link-Table?
The original table does grow continuesly, so only new entries should be added.
Do I have to use a Cursor, or is there a better way?
SOLUTION:
MERGE Link_Table AS LT
USING (SELECT DISTINCT T1.ID AS T1ID, T2.ID AS T2ID FROM Original AS O
INNER JOIN Table_1 AS T1 ON T1.Column_1 = O.Column_1
INNER JOIN Table_2 AS T2 ON T2.Column_3 = O.Column_3) AS U
ON LT.fk1 = U.T1ID
WHEN NOT MATCHED THEN
INSERT (fk1, fk2)
VALUES (U.T1ID, U.T2ID);
You can JOIN all 3 tables to get proper data for link table:
--INSERT INTO [Link-Table]
SELECT t1.ID,
t2.ID
FROM Original o
INNER JOIN Table_1 t1
ON t1.Column_1 = o.Column_1
INNER JOIN Table_2 t2
ON t2.Column_3 = o.Column_3
If your original table will grow, then you need to use MERGE to update/insert new data.
You have to inner join your Original,Table_1 and Table_2 to get the desired result.
Try like this, Its similar to gofr1 post.
DECLARE #orginal TABLE (
ID INT
,Column_1 VARCHAR(10)
,Column_2 INT
,Column_3 VARCHAR(10)
)
DECLARE #Table_1 TABLE (
ID INT
,Column_1 VARCHAR(10)
,Column_2 INT
)
DECLARE #Table_2 TABLE (
ID INT
,Column_3 VARCHAR(10)
)
Insert into #orginal values
(1,'A',123,'A1')
,(2,'A',123,'A2')
,(3,'B',234,'A2')
,(4,'C',456,'A1')
Insert into #Table_1 values
(1,'A',123)
,(2,'B',234)
,(3,'C',456)
Insert into #Table_2 values
(1,'A1')
,(2,'A2')
SELECT O.ID
,T1.ID
,T2.ID
FROM #orginal O
INNER JOIN #Table_1 T1 ON T1.Column_1 = O.Column_1
INNER JOIN #Table_2 T2 ON T2.Column_3 = O.Column_3
I have 2 tables with details as follows
Table 1
Name | City | Employee_Id
-----------------
Raj | CA | A2345
Diya | IL | A1234
Max | PL | A2321
Anna | TX | A1222
Luke | DC | A5643
Table 2
Name | City | Employee_Id | Phone | Age
---------------------------------------
Raj | CA | A2345 | 4094 | 25
Diya | IL | A1234 | 4055 | 19
Max | PL | A2321 | 4076 | 23
As you can see, Employee_Id is the common column in both the columns. I want to update all the entries present in table 1 into table 2.
Raj, Divya and Max are already present in Table 2. So it should not create a duplicate entry in table 2 and skip those 3 entries whereas Anna and Luke are not present in table 2. so this should be added as a new row.
The SQL should be able to merge these 2 columns and ignore the rows which are already present. The final table 2 must be similar to this.
Table 2
Name | City | Employee_Id | Phone | Age
---------------------------------------
Raj | CA | A2345 | 4094 | 25
Diya | IL | A1234 | 4055 | 19
Max | PL | A2321 | 4076 | 23
Anna | TX | A1222 | |
Luke | DC | A5643 | |
Is there a way I could achieve this? I am pretty new to SQL, so any inputs would be of great help. I read about merge and update feature but I guess merge is in Transact-SQL. Also read about joins but could not find a way to crack this.
Demo Setup
CREATE TABLE Table1
([Name] varchar(4), [City] varchar(2), [Employee_Id] varchar(5));
INSERT INTO Table1
([Name], [City], [Employee_Id])
VALUES
('Raj', 'FL', 'A2345'),
('Diya', 'IL', 'A1234'),
('Max', 'PL', 'A2321'),
('Anna', 'TX', 'A1222'),
('Luke', 'DC', 'A5643');
CREATE TABLE Table2
([Name] varchar(4), [City] varchar(2), [Employee_Id] varchar(5), [Phone] int, [Age] int);
INSERT INTO Table2
([Name], [City], [Employee_Id], [Phone], [Age])
VALUES
('Raj', 'CA', 'A2345', 4094, 25),
('Diya', 'IL', 'A1234', 4055, 19),
('Max', 'PL', 'A2321', 4076, 23);
MERGE QUERY
MERGE Table2 AS target
USING Table1 AS source
ON (target.[Employee_Id] = source.[Employee_Id])
WHEN MATCHED THEN
UPDATE SET [Name] = source.[Name],
[City] = source.[City]
WHEN NOT MATCHED THEN
INSERT ([Name], [City], [Employee_Id], [Phone], [Age])
VALUES (source.[Name], source.[City], source.[Employee_Id], NULL, NULL);
SELECT *
FROM Table2