SQL query join- unrelated tables - sql

Can someone help me to join the two tables without any primary or secondary keys. Sample table is
TABLE 1
| ID | NAME |
| 1 | x |
| 2 | Y |
| 3 | z |
TABLE 2
| Num | NAME | DATE |
| 52 | X | 12-aug-17 |
| 53 | X | 11-apr-17 |
| 62 | X | 10-aug-11 |
| 12 | y | 2-jan-16 |
| 23 | Y | 3-apr-18 |
I want retrieve data from X
select *
from table2
where name = 'x';
| Num | NAME | DATE |
| 52 | X | 12-aug-17 |
| 53 | X | 11-apr-17 |
| 62 | X | 10-aug-11 |
Now I will get three data from table2. I'm little stuck after this step. I want to get top of data the from table 2 and combine with table one.
I want final output should be
| ID | NAME | Num | DATE |
| 1 | x | 52 | 12-aug-17 |
Can someone suggest me how can I join this table? Its easy to join when we have any primary key but here not the case
Thanks

You can use this:
SELECT TOP(1) table1.ID, table2.Num, table2.Name, table2.DATE
FROM table2 INNER JOIN table1 ON table1.NAME = table2.NAME
WHERE table2.NAME = 'x'
ORDER BY table2.DATE ASC
OR
SELECT table1.ID, table2.Num, table2.Name, table2.DATE
FROM table1 INNER JOIN
(SELECT TOP(1) * FROM table2 WHERE NAME = 'x' ORDER BY DATE ASC) table2
ON table1.NAME = table2.NAME

You need to get the maximum DATE using a subquery, as in:
select t1.id, t2.*
from table1 t1
join table2 t2 on t2.name = t1.name
where t2.date = (
select max(date) from table2 where name = 'x'
);

Related

How to find out if 2 values in the same row exist in another table

I want to find out if 2 values in the same row exist in another table.
Only return the row if both values exist at the same time.
I can probably do 2 joins but is there an efficient way to do this?
Is there something like below?
table_1
+---------+---------------+------+
| id | other_id | key |
+---------+---------------+------+
| 1 | 2 | A |
| 2 | 1 | B |
| 1 | 3 | C |
| 4 | 2 | D |
+---------+---------------+------+
table_2
+---------+
| id |
+---------+
| 2 |
| 3 |
| 4 |
+---------+
SELECT
*
from
table_1
where
(id, other_id) in (
SELECT
id
from
table_2
)
output_table
+---------+---------------+------+
| id | other_id | key |
+---------+---------------+------+
| 4 | 2 | D |
+---------+---------------+------+
You can try as
SELECT *
FROM table1 t1
WHERE exists (select 1 from table2 t2 where t1.id=t2.id)
and exists (select 1 from table2 t3 where t1.anotherid=t3.id) ;
select * from table_1
where table_1.id in (select table_2.id from table_2)
try this , hope this help you!
Use exists:
SELECT
*
from
table_1 t1
where exists
(
select id from table_2 t2
where t1.id = t2.id or t1.other_id = t2.id;
)

How to mass-check for duplicates in MS-Access and log changes?

I want to mass-compare a few hundred fields in MS Access between 2 tables with identical column structures. If there are any differences between the column values, replaces the row in table1 with the new row in table2. If table2 does no longer holds a row that exists in table1, that row should be dropped from table1. All changes to table1 should be logged in tableLOGS.
Take for example:
____table1___ _____table2____ __________tableLOGS__________
| pid | A | B | | pid | A | B | | id | pid | A | B | action |
| 1 | 0 | 0 | | 1 | 0 | 0 | | 1 | 1 | 0 | 0 | add |
| 2 | 0 | 0 | | 2 | 0 | 1 | | 2 | 2 | 0 | 0 | add |
| 3 | 0 | 0 |
After running the desired SQL query, the result should be:
____table1___ _____table2____ __________tableLOGS__________
| pid | A | B | | pid | A | B | | id | pid | A | B | action |
| 1 | 0 | 0 | | 1 | 0 | 0 | | 1 | 1 | 0 | 0 | add |
| 2 | 0 | 1 | | 2 | 0 | 1 | | 2 | 2 | 0 | 0 | add |
| 3 | 2 | 0 | 1 | edit |
| 4 | 3 | 0 | 0 | delete |
I expect this would have to be broken down into 2 separate queries?
Mass-compare rows and update changes Log the changes to tableLOGS This seems like a fairly common task so perhaps MS Access has an easy way of accomplishing this? Thanks for all the help! :)
P.S. I am also open to simply deleting rows from table1 that do not match table2, and INSERT INTO table1 from table2.
This is from memory I didn't actually run this so it may need some fixing. My apologies
Start with the logging for updates
INSERT INTO TableLogs
SELECT A, B
FROM (
SELECT A, B
FROM table2 t2
INNER JOIN table1 t1 ON t1.pid = t2.pid
AND (t1.A <> t2.a OR t1.B <> t2.B)
WHERE table1.A IS NOT NULL)
Then update table1 with the updated values
UPDATE table1
INNER JOIN(
SELECT *
FROM table2 t2
INNER JOIN table1 t1 ON t1.pid = t2.pid
AND (t1.A <> t2.a OR t1.B <> t2.B)
WHERE table1.A IS NOT NULL) t2
ON table1.pid = t2.pid
Log missing records in table 1
INSERT INTO tablelogs
SELECT A, B
FROM table2
INNER JOIN table1 t1 ON t1.pid = t2.pid AND (t1.A <> t2.a OR t1.B <> t2.B)
WHERE table1.A IS NOT NULL
Delete the missing rows from table1
DELETE table1
WHERE pid NOT IN
(SELECT pid FROM Table2)
You could also put a trigger on table1 to update table logs but its not really best practice.
Hope that helps, like I said I didn't run it yet.

SQL Query to Bring Back where Row Count is Greater than 1

I have two tables.They have the same data but from different sources. I would like to find all columns from both tables that where id in table 2 occurs more than once in table 1. Another way to look at it is if table2.id occurs only once in table1.id dont bring it back.
I have been thinking it would be some combination of group by and order by clause that can get this done but its not getting the right results. How would you express this in a SQL query?
Table1
| id | info | state | date |
| 1 | 123 | TX | 12-DEC-09 |
| 1 | 123 | NM | 12-DEC-09 |
| 2 | 789 | NY | 14-DEC-09 |
Table2
| id | info | state | date |
| 1 | 789 | TX | 14-DEC-09 |
| 2 | 789 | NY | 14-DEC-09 |
Output
|table2.id| table2.info | table2.state| table2.date|table1.id|table1.info|table1.state|table1.date|
| 1 | 789 | TX | 14-DEC-09 | 1 | 123 | TX | 12-DEC-09 |
| 1 | 789 | TX | 14-DEC-09 || 1 | 123 | NM | 12-DEC-09 |
If you using MSSQL try using a Common Table Expression
WITH cte AS (SELECT T1.ID, COUNT(*) as Num FROM Table1 T1
INNER JOIN Table2 T2 ON T1.ID = T2.ID
GROUP BY T1.ID
HAVING COUNT(*) > 1)
SELECT * FROM cte
INNER JOIN Table1 T1 ON cte.ID = T1.ID
INNER JOIN Table2 T2 ON cte.ID = T2.ID
First, I would suggest adding an auto-incrementing column to your tables to make queries like this much easier to write (you still keep your ID as you have it now for relational-mapping). For example:
Table 1:
TableID int
ID int
Info int
State varchar
Date date
Table 2:
TableID int
ID int
Info int
State varchar
Date date
Then your query would be really easy, no need to group, use CTEs, or row_over partitioning:
SELECT *
FROM Table2 T2
JOIN Table1 T1
ON T2.ID = T1.ID
JOIN Table1 T1Duplicate
ON T2.ID = ID
AND T1.TableID <> T1Duplicate.TableID
It's a lot easier to read. Furthermore, there are lots of scenarios where an auto-incrementing ID field is benefitial.
I find this a much simpler way to do it:
select TableA.*,TableB.*
from TableA
inner join TableB
on TableA.id=TableB.id
where TableA.id in
(select distinct id
from TableA
group by id
having count(*) > 1)

Can't update main table with joined tables using DISTINCT - Access: This recordset is not updatable

gurus!
I'm using SQL Server linked tables in Access Forms. In MainTable I need to update and insert records, but Access won't let it, for update it says "This Recordset is not updateable". I know, it's couse DISTINCT, but it's necessary for TableType records - I need only one related name_ds from TableTypes (even first by npr) and in result just thees 7 MainTable records not 16 (without DISTINCT).
Any workarounds?
Simple structure -
MainTable: id, npr, name, type, datasource_fk.
TableDS: id, name_ds, something.
TableType: id, npr, name_type, something_type.
Data -
MainTable:
1;12;"Olie";"percentage";1
2;15;"Tol";"count";2
3;13;"Opp";"percentage";1
4;12;"Hypq";"count";3
5;14;"Gete";"count";1
6;;"Mour";"count";2
7;;"Ellt";"percentage";3
TableDS:
1;"City1";"q"
2;"City2";"a"
3;"State1";"z"
4;"State2";"x"
TableType:
1;12;"City1";"w"
2;15;"City1";"s"
3;13;"City1";"x"
4;14;"City2";"w"
5;14;"City1";"s"
6;13;"City3";"p"
7;12;"City1";"t"
8;12;"City1";"n"
9;12;"State1";"r"
10;15;"State1";"r"
SQL, result -
SELECT DISTINCT t3.npr AS npr_type, t1.npr, t1.id, t1.name, t2.name_ds, t1.datasource_fk, t1.types
FROM (MainTable AS t1 LEFT JOIN TableDS AS t2 ON t1.datasource_fk = t2.id) LEFT JOIN TableType AS t3 ON t1.npr = t3.npr;
---------------------------------------------------------------------------------------------------------------------------------------------
| npr_type | npr | id | name | name_ds | datasource_fk | types |
---------------------------------------------------------------------------------------------------------------------------------------------
| | | 6 | Mour | City2 | 2 | count |
---------------------------------------------------------------------------------------------------------------------------------------------
| | | 7 | Ellt | State1 | 3 | percentage |
---------------------------------------------------------------------------------------------------------------------------------------------
| 12 | 12 | 1 | Olie | City1 | 1 | percentage |
---------------------------------------------------------------------------------------------------------------------------------------------
| 12 | 12 | 4 | Hypq | State1 | 3 | count |
---------------------------------------------------------------------------------------------------------------------------------------------
| 13 | 13 | 3 | Opp | City1 | 1 | percentage |
---------------------------------------------------------------------------------------------------------------------------------------------
| 14 | 14 | 5 | Gete | City1 | 1 | count |
---------------------------------------------------------------------------------------------------------------------------------------------
| 15 | 15 | 2 | Tol | City2 | 2 | count |
---------------------------------------------------------------------------------------------------------------------------------------------
You are getting 16 matches on your joins because MainTable npr column matches multiple times with TableType npr column.
1;12;"Olie";"percentage";1
Matches to
7;12;"City1";"t"
8;12;"City1";"n"
9;12;"State1";"r"
1;12;"City1";"w"
Your best bet is to use a where clause for column TableType.somethingtype. You can try LEFT JOIN on TableDS and TableType using multiple columns but really, you may need to adjust your data. In other words, inactivate some rows. The following query will show you what you're up against:
SELECT t3.npr AS npr_type,
t1.npr,
t1.id,
t1.name,
t2.name_ds,
t1.datasource_fk,
t1.type,
t3.something_type
FROM #MainTable t1
LEFT JOIN #TableDS AS t2
ON t1.datasource_fk = t2.id
LEFT JOIN #TableType AS t3
ON t1.npr = t3.npr
ORDER BY t3.npr,
t1.npr,
t1.id,
t1.name,
t2.name_ds,
t1.datasource_fk,
t1.type,
t3.something_type
So, after you figure out your data. Then you may be able to do something like:
SELECT t3.npr AS npr_type,
t1.npr,
t1.id,
t1.name,
t2.name_ds,
t1.datasource_fk,
t1.type,
t3.something_type
FROM #MainTable t1
LEFT JOIN #TableDS AS t2
ON t1.datasource_fk = t2.id
LEFT JOIN #TableType AS t3
ON t1.npr = t3.npr
WHERE
(t1.npr = 12 AND t3.something_type = 'n')
OR
(t1.npr = 14 AND t3.something_type = 's')
OR
(t1.npr = 13 AND t3.something_type = 'p')
OR
(t1.npr = 15 AND t3.something_type = 's')
OR
(t1.npr IS NULL)

How can I write a select statement for this use case?

Please help me compose a SELECT statement. I have these two tables:
Table1 Table2
---------------- ------------------------------------------------
ID | PName | | ID | NameID | DateActive | HoursActive |
---------------- ------------------------------------------------
1 | Neil | | 1 | 1 | 8/2/2013 | 3 |
2 | Mark | | 2 | 1 | 8/3/2013 | 4 |
3 | Onin | | 3 | 2 | 8/2/2013 | 2 |
---------------- | 4 | 2 | 8/6/2013 | 5 |
| 5 | 3 | 8/7/2013 | 1 |
| 6 | 3 | 8/8/2013 | 10 |
------------------------------------------------
And I just want to retrieve the earliest DateActive but no duplicate PName. Like this:
PName | DateActive | HoursActive |
----------------------------------------
Neil | 8/2/2013 | 3 |
Mark | 8/2/2013 | 2 |
Onin | 8/7/2013 | 1 |
----------------------------------------
Something like this might do it. You need to find the min date for each NameID first, then join back to the table to get the hours.
SELECT
PName, MaxDate as DataActive, HoursActive
From
Table1 t1
inner Join Table2 t2 on t1.ID = t2.NameID
Inner Join (Select min(DateActive) as mindate, NameID from Table2 Group by NameID) as t3 on t3.mindate = t2.ActiveDate and t3.NameID = t2.NameId
This should be a pretty standard solution:
select t.pname,
t2.dateactive,
t2.hoursac
from table1 t
join table2 t2 on t.id = t2.nameid
join (
select nameid, min(dateactive) mindateactive
from table2
group by nameid
) t3 on t2.nameid = t3.name
and t3.mindateactive = t2.dateactive
If you are using an RDBMS that supports partition by statements, then this would be more efficient:
select pname, dateactive, HoursActive
from (
select t.pname,
t2.dateactive,
t2.hoursactive,
rank() over (partition by t.id order by t2.dateactive) rownum
from table1 t
join table2 t2 on t.id = t2.nameid
) t
where rownum = 1