Unfortunately, I cannot be sure that the name of my question is correct here.
Example of initial data:
Table 1 Table 2 Table 3
| ID | Name | | ID | Info1 | | ID | Info2 |
|----|-------| |----|-------| |----|-------|
| 1 | Name1 | | 1 | text1 | | 1 | text1 |
| 2 | Name2 | | 1 | text1 | | 1 | text1 |
| 3 | Name3 | | 2 | text2 | | 1 | text1 |
| 2 | text2 | | 2 | text2 |
| 3 | text3 |
In my initial data I have relationship between 3 tables by field ID.
I need to join table2 and table3 to the first table, but if I do sequential join, like left join table2 and left join table3 by ID I will get additional records on second join, because there will be several records with one ID after first join.
I need to get records of table2 and table3 like a list in each column for ID of first table.
Here an example of expected result:
Table 3
| ID | Name |Info1(Table2)|Info2(Table3)|
|-------|-----------|-------------|-------------|
| 1 | Name1 | text1 | text1 |
| 1 | Name1 | text1 | text1 |
| 1 | Name1 | null | text1 |
| 2 | Name2 | text2 | text2 |
| 2 | Name2 | text2 | null |
| 3 | Name3 | null | text3 |
This is the method I would use, however, the table design you have could probably be improved on; why are Table2 and Table3 separate in the first place?
USE Sandbox;
GO
CREATE TABLE dbo.Table1 (ID int, [Name] varchar(5))
INSERT INTO dbo.Table1 (ID,
[Name])
VALUES(1,'Name1'),
(2,'Name1'),
(3,'Name3');
CREATE TABLE dbo.Table2 (Id int,Info1 varchar(5));
CREATE TABLE dbo.Table3 (Id int,Info2 varchar(5));
INSERT INTO dbo.Table2 (Id,
Info1)
VALUES(1,'text1'),
(1,'text1'),
(2,'text2'),
(2,'text2');
INSERT INTO dbo.Table3 (Id,
Info2)
VALUES(1,'text1'),
(1,'text1'),
(1,'text1'),
(2,'text2'),
(3,'text3');
WITH T2 AS(
SELECT ID,
Info1,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY (SELECT NULL)) AS RN --SELECT NULL as you have no other columns to actually create an order
FROM Table2),
T3 AS(
SELECT ID,
Info2,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY (SELECT NULL)) AS RN
FROM Table3),
Tally AS(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I --Assuming you have 10 or less matching items
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) N(N))
SELECT T1.ID,
T1.[Name],
T2.info1,
T3.info2
FROM Table1 T1
CROSS JOIN Tally T
LEFT JOIN T2 ON T1.ID = T2.ID AND T.I = T2.RN
LEFT JOIN T3 ON T1.ID = T3.ID AND T.I = T3.RN
WHERE T2.ID IS NOT NULL OR T3.ID IS NOT NULL
ORDER BY T1.ID, T.I;
GO
DROP TABLE dbo.Table1;
DROP TABLE dbo.Table2;
DROP TABLE dbo.Table3;
If you have more than 10 rows, then you could build a "proper" tally table on the fly, or create a physical one. One on the fly is probably going to be a better idea though, as I doubt you're going to have 100's of matching rows.
Related
So, to me comes Table2 (PK Text) filled with elements FIRST, SECOND, THIRD, FORTH.
I need to insert this element to TABLE1 where these elements are missing.
TABLE1
+----+--------+
| ID | Text |
+----+--------+
| A | FIRST |
| A | SECOND |
| A | THIRD |
| B | FIRST |
| B | THIRD |
| C | FIRST |
+----+--------+
So ID A misses FORTH
| A | FORTH |
Should be inserted
B misses SECOND and FORTH and so on
Answer should be something like that
+----+--------+
| ID | Text |
+----+--------+
| A | FIRST |
| A | SECOND |
| A | THIRD |
| A | FORTH |
| B | FIRST |
| B | SECOND |
| B | THIRD |
| B | FORTH |
| C | FIRST |
| C | SECOND |
| C | THIRD |
| C | FORTH |
+----+--------+
You can cross join the texts from table2 with the distinct ids availabel in table1 and filter on the missing tuples with a not exists condition, like so:
insert into table1(id, text)
select t1.id, t2.text
from table2 t2
cross join (select distinct id from table1) t1
where not exists (
select 1
from table1 t11
where t11.id = t1.id and t11.text = t2.text
)
Cross join the distinct IDs with the distinct Texts and left join the table to get the unmatched rows of the table:
INSERT INTO TABLE1 (ID, Text)
SELECT i.ID, d.Text
FROM (SELECT DISTINCT ID FROM TABLE1) i
CROSS JOIN (SELECT DISTINCT Text FROM TABLE1) d
LEFT JOIN TABLE1 t ON t.ID = i.ID AND t.Text = d.Text
WHERE t.ID IS NULL
See the demo.
If there is a case that any of the values 'FIRST', 'SECOND', 'THIRD' or 'FOURTH' is missing from the table then use this:
INSERT INTO TABLE1 (ID, Text)
SELECT i.ID, d.Text
FROM (SELECT DISTINCT ID FROM TABLE1) i
CROSS JOIN (
SELECT 'FIRST' Text UNION ALL SELECT 'SECOND'
UNION ALL SELECT 'THIRD' UNION ALL SELECT 'FOURTH'
) d
LEFT JOIN TABLE1 t ON t.ID = i.ID AND t.Text = d.Text
WHERE t.ID IS NULL
See the demo.
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;
)
Given table t1 with columns Id ( text, primary key ) and place (text) like below.
+-------+-----------+
| Id | place |
+-------+-----------+
| abcde | Santori |
| bcdef | Krypt |
| cdefg | Bali |
| defgh | Bangkok |
| abcde | Colombo |
+-------+-----------+
I need to find out the records for Ids having more than one distinct place. In the above example the output shall be
+-------+-----------+
| Id | place |
+-------+-----------+
| abcde | Santori |
| abcde | Colombo |
+-------+-----------+
I would use exists :
select t.*
from table t
where exists (select 1 from table t1 where t1.id = t.id and t1.place <> t.place);
I think it is OK for you:
SELECT ID, PLACE FROM T1 as A
WHERE A.ID IN
(SELECT ID FROM T1 AS B
GROUP BY ID
HAVING count(*) > 1
)
In a subquery, you need to get count of distinct place and get the ID. And then use an outer query to fetch all records.
Fiddle Example
select * From T1
where T1.ID in
(select ID from T1
group by ID
having count(distinct PLACE) > 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)
I have the following two tables:
table 1 table 2
+-------------+------+ +-------------+------+
| ssn | id | | ssn | id |
+-------------+------+ +-------------+------+
| 123456789 | 123 | | 123456789 | k12 |
| 123456789 | 456 | | 999999999 | k11 |
| 123456789 | 789 | +-------------+------+
| 123456789 | k12 |
| 999999999 | 799 |
+-------------+------+
What I want to do is to merge the data in table 2 with the data in table 1 if there is no matching id. So 123456789 should be ignored as the member already shows with the id k12. Record 999999999 k11 should be added to table 1.
A few ways to do this. Here's one using NOT EXISTS:
INSERT INTO Table1
SELECT T2.ssn, T2.id
FROM Table2 T2
WHERE NOT EXISTS (
SELECT 1
FROM Table1 T1
WHERE T1.id = T2.id)
Or you could use NOT IN:
INSERT INTO Table1
SELECT ssn, id
FROM Table2
WHERE id NOT IN (SELECT id FROM Table1)
INSERT INTO #Table1
( ssn, id)
SELECT t2.ssn, t2.id
FROM #table2 as t2
LEFT JOIN #table1 as t1
ON t1.id = t2.id or t1.ssn = t2.ssn
WHERE t1.id IS NULL;
if you are worried about duplicates in either id OR ssn, this will only insert when both are unique
If this is something you need to do often on large tables, this LEFT JOIN approach may perform a bit faster.
INSERT INTO Table1
SELECT T2.ssn, T2.id
FROM Table2 T2
LEFT JOIN Table1 t1 ON t1.id = t2.id
WHERE t1.id IS NULL