SQL query for join table and multiple values - sql

So I have three tables that are involved in my problem, 2 regular tables and a join table for a has many and belongs to many relationship. They look like this:
table1
--id
--data
table2
--id
--data
table1_table2
--table1_id
--table2_id
So, my question is how I would query (using a join) for something that would have one or more values in the table1_table2 for one item in table1. For instance:
Table 1
+----------+
|id | data |
+----------+
|1 | none |
+----------+
|4 | match|
+----------+
Table 2
+----------+
|id | data |
+----------+
|1 | one |
+----------+
|2 | two |
+----------+
table1_table2
+----------------------+
|table1_id | table2_id |
+----------------------+
|1 | 1 |
+----------------------+
|4 | 1 |
+----------------------+
|4 | 2 |
+----------------------+
I need a query that would match Table 1 row id 4 because it has a link via the join to both row 1 and 2 from table 2. If this is confusing please ask anything.
Maybe I was a bit unclear, I am using table1_table2 as a join not as a from. I need to make sure it matches 1 and 2 both from table 2.
Here is my query so far...
SELECT DISTINCT table1.id,
table2.data
FROM table1
LEFT JOIN table1_table2 ON table1.id = table1_table2.table1_id
LEFT JOIN table2 ON table2.id = table1_table2.table2_id
I need a where that will make that for an entry in table 1 it matches both 1 and 2 from table 2.
The output I am looking for would be:
+---------------------+
|table1.id|table2.data|
+---------------------+
|4 |one |
+---------------------+
|4 |two |
+---------------------+

The following approach works if you can guarantee there are no duplicates in the Table1_Table2 table. Maybe you can start here and finesse it a bit. Note how the JOIN condition works -- putting the IN in the join condition works differently than if you put the IN condition in the WHERE clause.
I've used hash marks for values that you would need to have your code insert into the SQL.
SELECT Table1.id, COUNT(Table1_Table2.Table2_id)
FROM Table1
JOIN Table1_Table2 ON (Table1_Table2.Table1_id = Table1.id
AND Table1_Table2.Table2_id IN (#somelist#))
GROUP BY Table1.id
HAVING COUNT(Table1_Table2.Table2_id) = (#length of somelist#)
Oops -- you've changed your question in the way I suggested and I've ignored your edit. But this should get you started, as it returns all the Table1 id's that you are interested in.

Here's my solution. It's not very generalized. You should post a comment if this solution doesn't work because it is too specific to your situation.
SELECT DISTINCT Table1.id
FROM Table1
INNER JOIN table1_table2 a ON (table1.id = table1_table2.table1_id
AND table2.id = 1)
INNER JOIN table1_table2 b ON (table1.id = table1_table2.table1_id
AND table2.id = 2)

If I were doing this in SQL Server I would put the values you want to check into a temp table (or table variable) and then use a variation of what #ChrisCunningham said.
CREATE TABLE #temp (Id INT)
INSERT INTO #temp
VALUES (1, 3, 7)
SELECT a.id AS table1ID, table2.data
FROM
(
SELECT Table1.id, Table1_Table2.table2_id
FROM Table1 JOIN Table1_Table2
ON (Table1_Table2.Table1_id = Table1.id
AND Table1_Table2.Table2_id IN (SELECT Id FROM #temp))
GROUP BY Table1.id
HAVING COUNT(Table1_Table2.Table2_id) = (SELECT count (*) FROM #temp)
) a
JOIN Table2 ON Table2.id = a.Table2_id
Of course I'm not sure what mechanisms Postgre has for temp tables, but you would even make it a stored proc where you use some sort of split function to create the values for the temp table rather that the way I did it. But at least this might give you an idea.

I think you should be able to select this:
select table1_id, count(*) as count from table1_table2 group by table1_id having count > 2;
group by, count and having are your friends!

Related

Getting 4 rows instead of 2 in a simple inner join in sql developer

I am a new learner to the sql language. My instructor gave me a task to comprehend the output of an inner join of two tables containing only one column named id and the number 1 inserted in both the tables twice.
The tables are named T1 and T2 and are visible in the db as shown below.
T1 \ T2
|ID | | ID |
|---| |----|
|1 | | 1 |
|1 | | 1 |
when i perform an inner join on these tables with the following code:
SELECT * FROM T1 INNER JOIN T2 ON T1.ID = T2.ID
I am getting the query result as:
|ID | ID_1 |
|---|------|
|1 | 1 |
|1 | 1 |
|1 | 1 |
|1 | 1 |
From my understanding the inner join retrieves distinct, non duplicate rows from both the tables, and should have just 2 rows in the output. why am i getting 4 rows? Please help me understand.
My apologies if this question is too basic and not upto the site's standards.
From my understanding the inner join retrieves distinct, non duplicate rows from both the tables
Simple. Your understanding is wrong.
JOIN has no relationship to "distinct" or "non-duplicate" rows. It simply produces all combinations of rows from the two tables that match the ON conditions (plus additional rows for an outer join).
Perhaps you are confusing JOIN with UNION -- which does remove duplicates. That said, I strongly recommend UNION ALL in most circumstances, because that does not incur the overhead of removing duplicates.
Maybe something like this is what you need:
select distinct T.rn, T.id, T2.id
from (select distinct ROW_NUMBER() OVER (ORDER BY T1.id) rn, T1.id from T1) T
join T2 on T.id = T2.id
order by T.rn;

Update a table based on a condition

I have a column Table1.Tradedate and another column Table2.SettlementDate.
Based on the comparison between these 2, I want to update a column in table 2
IF (Table1.TradeDate <= Table2.SettlementDate)
BEGIN
UPDATE Table2 SET Status='Y'
END
This is what I have tried but I know its wrong, since the table will obviously contain more than 1 records. So, I believe what I should do is
use a join on 2 tables based on some #id to pick a particular record
check the IF condition for that particular record
update the Status column in table2.
I hope my approach is correct but I am writing it incorrectly.
Table1:
SKacc | Name | TradeDate | Othercolumns....
1 | xxx | 01/07/2019 |
2 | xxx | 01/06/2019 |
Table2:
SKAcc | Name | SettlementDate | Status |Other Columns....
1 | xxx | 01/08/2019 | NULL |
2 | xxx | 01/08/2019 | NULL |
Try below
update t2 set Status = 'Y'
from table2 t2
join table1 t1 on t1.id = t2.id
where t1.tradeDate <= t2.settlementDate
Try joining the two tables with the related column and then update the table you want to update with the value. Using inner join in the example but can change depending on the usecase
UPDATE Table2
SET Status = 'Y'
FROM Table2
INNER JOIN Table1 ON Table1.id = Table2.table1_id
WHERE Table1.TradeDate <= Table2.SettlementDate
I would not recommend a JOIN for this purpose. Instead:
update table2
set Status = 'Y'
where exists (select 1
from table1 t1
where t1.id = t2.id and
t1.tradeDate <= t2.settlementDate
);
The reason I recommend this version is because you have not specified that id is unique in table1. In general, you only want to use JOIN in UPDATE when you can guarantee that there is only one matching row.

What is the correct way from performance perspective to match(replace) every value in every row in temp table using SQL Server 2016 or 2017?

I am wondering what should I use in SQL Server 2016 or 2017 (CTE, LOOP, JOINS, CURSOR, REPLACE, etc) to match (replace) every value in every row in temp table? What is the best solution from performance perspective?
Source Table
|id |id2|
| 1 | 2 |
| 2 | 1 |
| 1 | 1 |
| 2 | 2 |
Mapping Table
|id |newid|
| 1 | 3 |
| 2 | 4 |
Expected result
|id |id2|
| 3 | 4 |
| 4 | 3 |
| 3 | 3 |
| 4 | 4 |
You may join the second table to the first table twice:
WITH cte AS (
SELECT
t1.id AS id_old,
t1.id2 AS id2_old,
t2a.newid AS id_new,
t2b.newid AS id2_new
FROM table1 t1
LEFT JOIN table2 t2a
ON t1.id = t2a.id
LEFT JOIN table2 t2b
ON t1.id2 = t2b.id
)
UPDATE cte
SET
id_old = id_new,
id2_old = id2_new;
Demo
Not sure if you want just a select here, or maybe an update, or an insert into another table. In any case, the core logic I gave above should work for all these cases.
You'd need to apply joins on update query. Something like this:
Update tblA set column1 = 'something', column2 = 'something'
from actualName tblA
inner join MappingTable tblB
on tblA.ID = tblB.ID
this query will compare eachrow with ids and if matched then it will update/replace the value of the column as you desire. :)
Do the self join only
SELECT t1.id2 as id, t2.id2
FROM table1 t
INNER JOIN table2 t1 on t1.id = t.id
INNER JOIN table2 t2 on t2.id = t.id2
This may have best performance from solutions posted here if you have indexes set appropriately:
select (select [newid] from MappingTable where id = [ST].[id]) [id],
(select [newid] from MappingTable where id = [ST].[id2]) [id2]
from SourecTable [ST]

SQL Select colmn from other table only if data exist

I have two tables and I'm selecting data from the first table. If the condition is meet(Alias type = 2) and the data in second table for the id from the first table exist the I want to select the column from the second table. Here is data to explain more:
Table 1
id | Name | Location
---+--------------+---------
34 |John Smith |NewYork
36 |Mike Smith |London
45 |Bob Smith |Los Angeles
Table 2
id | Alias | Alias type
---+-------------------+-------
36 |Warren Johnson |1
36 |William Williams |2
Wanted results if alias type = 2
id |Name | Location
---+-------------------+---------
34 |John Smith |NewYork
36 |William Williams |London
45 |Bob Smith |Los Angeles
Can you help me write query to get the wanted results? Tell me if I need to explain more. I'm using a SQL Server database.
You can use a left outer join onto Table2, and then COALESCE the Alias and Name results like this:
SELECT Table1.ID, COALESCE(Table2.Alias, Table1.Name) AS Name,
Table1.Location
FROM Table1
LEFT OUTER JOIN Table2 ON Table1.ID = Table2.ID AND Table2.AliasType = 2
COALESCE works by finding the first non-null value in the supplied values.
Try something like this -- you just need to use CASE:
SELECT T1.Id,
CASE WHEN T2.Alias IS NOT NULL THEN T2.Alias ELSE T1.Name END as Name,
t1.Location
FROM Table1 T1
LEFT JOIN Table2 T2 ON T1.Id = T2.Id AND T2.AliasType = 2
Here is the SQL Fiddle.
Good luck.
The COALESCE function will let you have a fall-back expression so that the name from table 2 is used if it exists, and the name from table 1 is used otherwise. The LEFT outer join only joins table 2 when the rows exist, and t2.name is null if no record was joined.
SELECT t1.id, COALESCE(t2.name, t1.name), t1.location FROM [Table 1] as t1 LEFT JOIN [Table 2] as t2 on t1.id=t2.id and t2.[alias type]=2

SQL Delete Rows Based on Another Table

This is probably very easy, but it's Monday morning. I have two tables:
Table1:
Field | Type | Null | Key | Default | Extra
id | int(32) unsigned | NO | PRI | NULL | auto_increment
group | int(32) | NO | | 0 |
Table2:
Field | Type | Null | Key | Default | Extra
group | int(32) | NO | | 0 |
Ignoring other fields...I would like a single SQL DELETE statement that will delete all rows in Table1 for which there exists a Table2.group equal to Table1.group. Thus, if a row of Table1 has group=69, that row should be deleted if and only if there exists a row in Table2 with group=69.
Thank you for any help.
I think this is what you want:
DELETE FROM `table1`
WHERE `group` in (SELECT DISTINCT `group` FROM `table2`)
I think this way is faster:
DELETE FROM t1 USING table1 t1 INNER JOIN table2 t2 ON ( t1.group = t2.group );
The nice solution is just writing the SQL as you say it yourself already:
DELETE FROM Table1
WHERE
EXISTS(SELECT 1 FROM Table2 WHERE Table2.Group = Table1.Group)
Regards,
Arno Brinkman
Something like this
delete from table1 where group in (select group from table2)
Off the top of my head:
delete from Table1 where id in (select id from table1 inner join table2 on Table1.group = Table2.group)
I did this a little differently than other posters -- I think if there is a large number of rows on Table2 this might be better. Can someone please set me straight on that?
you can delete either table rows by using its alias in a simple join query like
delete a from table1 a,table2 b where a.uid=b.id and b.id=57;
here, you might specify either a or b to delete the corresponding table rows