Merge two rows in SQL - sql

Assuming I have a table containing the following information:
FK | Field1 | Field2
=====================
3 | ABC | *NULL*
3 | *NULL* | DEF
is there a way I can perform a select on the table to get the following
FK | Field1 | Field2
=====================
3 | ABC | DEF
Thanks
Edit: Fix field2 name for clarity

Aggregate functions may help you out here. Aggregate functions ignore NULLs (at least that's true on SQL Server, Oracle, and Jet/Access), so you could use a query like this (tested on SQL Server Express 2008 R2):
SELECT
FK,
MAX(Field1) AS Field1,
MAX(Field2) AS Field2
FROM
table1
GROUP BY
FK;
I used MAX, but any aggregate which picks one value from among the GROUP BY rows should work.
Test data:
CREATE TABLE table1 (FK int, Field1 varchar(10), Field2 varchar(10));
INSERT INTO table1 VALUES (3, 'ABC', NULL);
INSERT INTO table1 VALUES (3, NULL, 'DEF');
INSERT INTO table1 VALUES (4, 'GHI', NULL);
INSERT INTO table1 VALUES (4, 'JKL', 'MNO');
INSERT INTO table1 VALUES (4, NULL, 'PQR');
Results:
FK Field1 Field2
-- ------ ------
3 ABC DEF
4 JKL PQR

There are a few ways depending on some data rules that you have not included, but here is one way using what you gave.
SELECT
t1.Field1,
t2.Field2
FROM Table1 t1
LEFT JOIN Table1 t2 ON t1.FK = t2.FK AND t2.Field1 IS NULL
Another way:
SELECT
t1.Field1,
(SELECT Field2 FROM Table2 t2 WHERE t2.FK = t1.FK AND Field1 IS NULL) AS Field2
FROM Table1 t1

There might be neater methods, but the following could be one approach:
SELECT t.fk,
(
SELECT t1.Field1
FROM `table` t1
WHERE t1.fk = t.fk AND t1.Field1 IS NOT NULL
LIMIT 1
) Field1,
(
SELECT t2.Field2
FROM `table` t2
WHERE t2.fk = t.fk AND t2.Field2 IS NOT NULL
LIMIT 1
) Field2
FROM `table` t
WHERE t.fk = 3
GROUP BY t.fk;
Test Case:
CREATE TABLE `table` (fk int, Field1 varchar(10), Field2 varchar(10));
INSERT INTO `table` VALUES (3, 'ABC', NULL);
INSERT INTO `table` VALUES (3, NULL, 'DEF');
INSERT INTO `table` VALUES (4, 'GHI', NULL);
INSERT INTO `table` VALUES (4, NULL, 'JKL');
INSERT INTO `table` VALUES (5, NULL, 'MNO');
Result:
+------+--------+--------+
| fk | Field1 | Field2 |
+------+--------+--------+
| 3 | ABC | DEF |
+------+--------+--------+
1 row in set (0.01 sec)
Running the same query without the WHERE t.fk = 3 clause, it would return the following result-set:
+------+--------+--------+
| fk | Field1 | Field2 |
+------+--------+--------+
| 3 | ABC | DEF |
| 4 | GHI | JKL |
| 5 | NULL | MNO |
+------+--------+--------+
3 rows in set (0.01 sec)

I had a similar problem. The difference was that I needed far more control over what I was returning so I ended up with an simple clear but rather long query. Here is a simplified version of it based on your example.
select main.id, Field1_Q.Field1, Field2_Q.Field2
from
(
select distinct id
from Table1
)as main
left outer join (
select id, max(Field1)
from Table1
where Field1 is not null
group by id
) as Field1_Q on main.id = Field1_Q.id
left outer join (
select id, max(Field2)
from Table1
where Field2 is not null
group by id
) as Field2_Q on main.id = Field2_Q.id
;
The trick here is that the first select 'main' selects the rows to display. Then you have one select per field. What is being joined on should be all of the same values returned by the 'main' query.
Be warned, those other queries need to return only one row per id or you will be ignoring data

if one row has value in field1 column and other rows have null value then this Query might work.
SELECT
FK,
MAX(Field1) as Field1,
MAX(Field2) as Field2
FROM
(
select FK,ISNULL(Field1,'') as Field1,ISNULL(Field2,'') as Field2 from table1
)
tbl
GROUP BY FK

My case is I have a table like this
---------------------------------------------
|company_name|company_ID|CA | WA |
---------------------------------------------
|Costco | 1 |NULL | 2 |
---------------------------------------------
|Costco | 1 |3 |Null |
---------------------------------------------
And I want it to be like below:
---------------------------------------------
|company_name|company_ID|CA | WA |
---------------------------------------------
|Costco | 1 |3 | 2 |
---------------------------------------------
Most code is almost the same:
SELECT
FK,
MAX(CA) AS CA,
MAX(WA) AS WA
FROM
table1
GROUP BY company_name,company_ID
The only difference is the group by, if you put two column names into it, you can group them in pairs.

SELECT Q.FK
,ISNULL(T1.Field1, T2.Field2) AS Field
FROM (SELECT FK FROM Table1
UNION
SELECT FK FROM Table2) AS Q
LEFT JOIN Table1 AS T1 ON T1.FK = Q.FK
LEFT JOIN Table2 AS T2 ON T2.FK = Q.FK
If there is one table, write Table1 instead of Table2

Related

SQL query returning all rows from Table2

I am trying to join 2 tables and return data if the Table1.codeId is presented on Table2 OR if Table1.codeId = 0. However, It retrieves the data from Table2.
Table1 {
name nvarchar,
codeId int
}
| name | codeId |
|--------|--------|
| Bob | 1 |
| Bob | 2 |
| Chris | 0 |
Table2 {
id int,
codeName nvarchar
}
| id | codeName |
|------|----------|
| 1 | Engineer |
| 2 | Doctor |
| 3 | Dentist |
| 4 | Pilot |
| 5 | Mechanic |
SELECT t1.name, t2.codeName
FROM dbo.Table1 t1, dbo.Table2 t2
WHERE (t1.codeId = t2.id OR t1.codeId = 0)
Expected result:
Bob, 1
John, 2
Chris, 0
You are not required to use Join at all for such condition.
You can use subquery as following, it return same result as your expectation
select name,codeid from table1 where codeid in (select id from table2)
or codeid=0
What if you do it in two separates queries ?
Looking at the outcome, the problem must come from the WHERE clause. The OR seem to always be triggered.
So maybe splitting could do it
SELECT t1.name, t2.codeName
FROM dbo.Table1 t1, dbo.Table2 t2
WHERE (t1.codeId = t2.id)
SELECT t1.name, t2.codeName
FROM dbo.Table1 t1, dbo.Table2 t2
WHERE (t1.codeId = 0)
You can use a left join. Use it to select where there is a code match in Table2 or the code_id is 0.
create table Table1
(
name nvarchar(50),
codeId int
)
create table Table2
(
id int,
codeName nvarchar(50)
)
insert into Table1
VALUES
('Bob', 1),
('John', 2),
('Chris', 0),
('Tom', -1)
-- This should be excluded .. since -1 code doesn't exist in Table2
insert into Table2
VALUES
(1, 'Engineer'),
(2, 'Doctor'),
(3, 'Dentist'),
(4, 'Pilot'),
(5, 'Mechanic')
SELECT t1.name, t1.codeId
FROM dbo.Table1 t1
LEFT JOIN dbo.Table2 t2 ON t1.codeId = t2.id
WHERE t2.id is not NULL or t1.codeId = 0
You have to use left outer join.
please find below query
Select codeid,name
FROM Table1
LEFT OUTER JOIN Table2
ON Table1.codeId=Table2.id;

Update multiple columns of table based on another table sql

I have two tables:
Table1:
column1|column2|column3|column4|column5
---------------------------------------
'test1'| null | 12 |'old1' | 'gr1'
'test1'| 123 | null |'old2' | 'gr2'
'test2'| 488 | null |'old3' | 'gr3'
'test3'| 488 | null |'old4' | 'gr4'
Table2: (it's a SELECT query)
column1|column2|column4|column5
-------------------------------
'test1'| 999 | 'new1'| 'gr2'
'test3'| 1355 | 'new4'| 'gr4'
I have created the second table as a query in order to update the values of the first, where the key of the first table is (column1, column5). So the table I am after is:
Table1:
column1|column2|column3|column4|column5
---------------------------------------
'test1'| null | 12 |'old1' | 'gr1'
'test1'| 999 | null |'new1' | 'gr2'
'test2'| 488 | null |'old3' | 'gr3'
'test3'| 1355 | null |'new4' | 'gr4'
How is this done?
The exakt SQL command will of course depend on the query which produces your second table. Assuming, this query would just be "SELECT * FROM yourtable2", you can do following update command to achieve your goal:
UPDATE yourtable
SET
column2 = x.column2,
column4 = x.column4
FROM (SELECT * FROM yourtable2) x
WHERE yourtable.column1 = x.column1
AND yourtable.column5 = x.column5
Here you see this is working (in case the table "yourtable2" provides the correct data): db<>fiddle
So, you can replace the "SELECT FROM yourtable2" by your query and it will work.
Can you try
UPDATE table1 t1 set (column2,column4) = (
SELECT column2,column4
FROM table2 t2
WHERE t1.column1 = t2.column1 and t1.column5 = t2.column5
)
If you have table2 as a query, you can use WITH
WITH table2 (column1,column2,column4,column5) AS (
<your select query>
),
UPDATE table1 t1 set (column2,column4) = (
SELECT column2,column4
FROM table2 t2
WHERE t1.column1 = t2.column1 and t1.column5 = t2.column5
)

Insert records from 1st table to 2nd table only when the record is not present in the 2nd table

I have 1 table with the same table structure as the second table, I just have to insert records from table1 to table2 with
insert into table2(select * from table1);
The table 2 has a primary key in one of the fields say(id), and some one inserted data corresponding to that primary key
table1 table2
id | name id | name
1 | new1 1 | old1
2 | new2 4 | new4
3 | new3 3 | old3
5 | new5 6 | old6
I have to insert only those records into table 2 for which the primary key is not populated.
After insertion table 2 should look like this
table 2
id | name
1 | old1
2 | new2
3 | old3
4 | new4
5 | new5
6 | old6
What is the easiest way to do this?
Use a NOT EXISTS condition to get only those rows from table1 that don't exists in table2:
insert into table2 (id, name)
select t1.id, t1.name
from table1 t1
where not exists (select *
from table2 t2
where t2.id = t1.id);
You could use MERGE statement with only INSERT WHEN NOT MATCHED:
MERGE INTO table2 t2
USING table1 t1
ON t1.id = t2.id
WHEN NOT MATCHED
THEN
INSERT INTO table2
(id, name)
VALUES
(t1.id, t1.name)

How to join two tables and show source?

How to join values from two tables ...
Table_1:
ID | Value
----------
10 | Dog
27 | Cat
Table_2:
ID | Value
----------
27 | Cat
My SQL... (Microsoft Access 2016)
SELECT ID, VALUE , "YES" AS Table_1, NULL AS Table_2
FROM Table_1
UNION
SELECT ID, VALUE, NULL AS Table_1, "YES" AS Table_2
FROM Table_2
...returns this result:
ID | Value | Table_1 | Table_2
------------------------------
10 | Dog | YES |
27 | Cat | YES |
27 | Cat | | YES
But I would like to get a result like this:
ID | Value | Table_1 | Table_2
------------------------------
10 | Dog | YES |
27 | Cat | YES | YES
You can use aggregation and union all:
select id, value, max(table_1) as table_1, max(table_2) as table_2
from (select ID, VALUE , "YES" AS Table_1, NULL AS Table_2
from Table_1
union
select ID, VALUE, NULL AS Table_1, "YES" AS Table_2
from Table_2
) t
group by id, value;
The alternative in SQL is a FULL JOIN, but MS Access does not support full joins.
You can make a list of table1 + table2 values and then check if the values exists in table2 or 2 using simple jeft join.
select
base.*,
iif(isnull(t.value), null, 'YES') table1,
iif(isnull(t2.value), null, 'YES') table2
from
(
Select value from Table_1 -- if you have duplicate values add groupby here
union
select value from Table_2
) base -- Make a collection of values from table1 and 2
left join Table_1 T on base.value = T.value
left join Table_2 T2 on base.value = T2.value;
Not sure if you can open above query in design view but the query should work in access. to be design view friendly, you need to make a query object for the base and then you can simply do left joins and iifs

SQL right join, force return only one value from right hand side

table 1
---
id , name
table2
---
id , activity, datefield
table1 'right join' table2 will return more than 1 results from right table (table2) . how to make it return only "1" result from table2 with the highest date
You write poor information about your problem, But I'll try to make an example to help you.
You have a table "A" and a table "B" and you need to fetch the "top" date of table "B" that is related with table "A"
Example tables:
Table A:
AID| NAME
----|-----
1 | Foo
2 | Bar
Table B:
BID | AID | DateField
----| ----| ----
1 | 1 | 2000-01-01
2 | 1 | 2000-01-02
3 | 2 | 2000-01-01
If you do this sql:
SELECT * FROM A RIGHT JOIN B ON B.ID = A.ID
You get all information of A and B that is related by ID (that in this theoretical case is the field that is common for both tables to link the relation)
A.AID | A.NAME | B.BID | B.AID | B.DateField
------|--------|-------|-------|--------------
1 | Foo | 1 | 1 | 2000-01-01
1 | Foo | 2 | 1 | 2000-01-02
2 | Bar | 3 | 2 | 2000-01-01
But you require only the last date for each element of the Table A (the top date of B)
Next if you need to get only the top DATE you need to group your query by the B.AID and fetch only the top date
SELECT
B.AID, First(A.NAME), MAX(B.DateField)
FROM
A RIGHT JOIN B ON B.ID = A.ID
GROUP BY
B.AID
And The result of this operation is:
B.AID | A.NAME | B.DateField
------|--------|--------------
1 | Foo | 2000-01-02
2 | Bar | 2000-01-01
In this result I removed some fields that are duplicated (like A.AID and B.AID that is the relationship between the two tables) or are not required.
Tip: this also works if you have more tables into the sql. The sql "makes" the query and next applies a grouping for using the B to limit the repetitions of B to the top date.
right join table2 on on table1.id to to select id, max = max(date) from table2
Analytics!
Test data:
create table t1
(id number primary key,
name varchar2(20) not null
);
create table t2
(id number not null,
activity varchar2(20) not null,
datefield date not null
);
insert into t1 values (1, 'foo');
insert into t1 values (2, 'bar');
insert into t1 values (3, 'baz');
insert into t2 values (1, 'foo activity 1', date '2009-01-01');
insert into t2 values (2, 'bar activity 1', date '2009-01-01');
insert into t2 values (2, 'bar activity 2', date '2010-01-01');
Query:
select id, name, activity, datefield
from (select t1.id, t1.name, t2.id as t2_id, t2.activity, t2.datefield,
max(datefield) over (partition by t1.id) as max_datefield
from t1
left join t2
on t1.id = t2.id
)
where ( (t2_id is null) or (datefield = maxdatefield) )
The outer where clause will filter out all but the maximum date from t2 tuples, but leave in the null row where there was no matching row in t2.
Results:
ID NAME ACTIVITY DATEFIELD
---------- -------- ------------------- -------------------
1 foo foo activity 1 2009-01-01 00:00:00
2 bar bar activity 2 2010-01-01 00:00:00
3 baz
To retrieve the Top N records from a query, you can use the following syntax:
SELECT *
FROM (your ordered by datefield desc query with join) alias_name
WHERE rownum <= 1
ORDER BY rownum;
PS: I am not familiar with PL/SQL so maybe I'm wrong
my solution is
select from table1 right join table2 on (table1.id= table2.id and table2.datefiled= (select max(datefield) from table2 where table2.id= table1.id) )