Updating FK by Child Table Field Value - sql

Given the following records in table B, in that:
B.Id | B.CId | B.Name
1 | 1 | "apple"
2 | 2 | "apple"
3 | 1 | "banana"
4 | 2 | "banana"
In table A, I have values:
A.Id | A.BId | A.CId
1 | 1 | 2
2 | 4 | 1
which actually needs to be updated to:
A.Id | A.BId | A.CId
1 | 2 | 2
2 | 3 | 1
based on the fact that A.CId needs to use A.BId where B.CId matches, and B.Name matches the A.BId's .Name.

Try the following:
SET bid = b.id --setting the value for bid to the id value in table b
FROM b b JOIN a a on a.cid = b.cid --where the cid cols in each table match
WHERE b.id IN
(SELECT b1.id from b b1 join a a1 on a1.bid = b1.id WHERE b1.name = b.name)
--and table b's ID is for row with a name value matching when joined on the
--foreign key instead of cid
Here's a reference to sql update statements involving multiple tables:
https://social.msdn.microsoft.com/Forums/sqlserver/en-US/1022bbce-3d99-49d1-83a1-75bafa49ac25/tsql-update-statement-with-join

Sounds like a job for update ... from ..., see UPDATE (Transact-SQL).
update
A
set
BId = B.Id
from
B
where
A.CId = B.CId
And here's a SQLFiddle as full example.

Related

Delete rows from table using JOIN - SQL Server

I have a table_A -
id | name | is_active |
----+---------+------------+
1 | jon | 1 |
2 | ham | 0 |
3 | gary | null |
I have a table_B -
id | name |
----+---------+
1 | jon |
2 | ham |
I want to remove rows from table B that have is_active value as 0 OR null in table A. So I'm thinking about an INNER JOIN on id column and applying a WHERE clause.
DELETE ROWS from table_B B
INNER JOIN table_A A ON B.id = A.id
WHERE A.is_active = 0 OR A.is_active IS NULL
I don't want any additional columns or changes in table B after the above query. Is this the right way to do it?
Instead of JOIN, use exists:
DELETE FROM table_B
WHERE EXISTS (SELECT 1
FROM table_A A
WHERE A.id = table_B.id AND
(A.is_active = 0 OR A.is_active is null)
);
You need to say which table you want to delete from, use the alias if you have one:
DELETE B
FROM table_B B
INNER JOIN table_A A ON B.id = A.id
WHERE (A.is_active = 0 OR A.is_active IS NULL);

Trying to write an inner join to filter out some conditions

I'm currently struggling with carrying out some joins and hoping someone can shed some light on this.
I have three tables: A,B,C
Table C lists names of individuals
Table A lists the food they like to eat
Table B is the link to show what food in A a person likes from C (Our
system was built without foreign keys! I know, it's a pain!)
What I'm trying to write is a query that will return a list of values from Table C which shows the individuals that don't like a specific food...say PFC
I have the following:
select * from table_c c
inner join table_b b
on c.name = b.bValue
inner join table_a a
on b.aValue = a.number
where a.value not in('PFC')
I'm assuming the joins are working but as table A has multiple values, the two extra rows are being returned. Is it possible to not show this client if one of the joins shows a food I don't want to see?
Table A
|---------------------|------------------|
| Number | Value |
|---------------------|------------------|
| 1 | McDs |
|---------------------|------------------|
| 1 | KFC |
|---------------------|------------------|
| 1 | PFC |
|---------------------|------------------|
Table B
|---------------------|------------------|
| bValue | aValue |
|---------------------|------------------|
| John | 1 |
|---------------------|------------------|
Table C
|---------------------|
| Name |
|---------------------|
| John |
|---------------------|
I'm also using SQL Server 2013 if that makes a difference!
With NOT EXISTS:
select * from table_c c
where not exists (
select 1 from table_b b inner join table_a a
on b.aValue = a.number
where b.bValue = c.name and a.value = 'PFC'
)
One option is to aggregate by name:
SELECT
c.Name
FROM table_c c
INNER JOIN table_b b
ON c.Name = b.bValue
INNER JOIN table_a a
ON b.aValue = a.Number
GROUP BY
c.Name
HAVING
COUNT(CASE WHEN a.Value = 'PFC' THEN 1 END) = 0;
We could also try expressing this using an exists query:
SELECT
c.Name
FROM table_c c
WHERE NOT EXISTS (SELECT 1 FROM table_b b
INNER JOIN table_a a
ON b.aValue = a.Number
WHERE c.Name = b.bValue AND
a.Value = 'PFC');

Simple SQL Questions with join

i have some problems with join tables:
Table A -> ID,Col1,Col2,Col3
Table B -> Rank , ColX , A_ID (Relationship with A.ID)
I want to take higher Rank (each A_ID , like group by A_ID) of B table
my results must be something like A.ID , Col1 , Col2 , Col3 , ""ColX"" , how can i do that ?
and i want my result count equals to A.ID count.
TableA
+--------------------+
| ID|Col1|Col2|Col3| |
+--------------------+
| 1 | C1 | C2 | C3 |
| 2 | C1 | C2 | C3 |
+--------------------+
TABLE_B
+-----------------------------+
| ID| COL_X |RANK |A_ID| |
+-----------------------------+
| 1 | SomeValue | 1 | 1 |
| 2 | some22222 | 2 | 1 |
| 3 | SOMEXXXX | 3 | 1 |
| 4 | SOMEVAL | 1 | 2 |
| 5 | VALUE | 2 | 2 |
+-----------------------------+
Expected Output:
+--------------------------------------------------------------------+
| ID| Col1| Col2 | Col3| COLX |
+--------------------------------------------------------------------+
| 1 | C1 | C2 | C3 | SOMEXXXX (Higher Rank of TableB-> A_ID = 1) |
| 2 | C1 | C2 | C3 | VALUE (Higher Rank of TableB-> A_ID = 2) |
+--------------------------------------------------------------------+
You could easily do this using a subquery by first finding the max for each A_ID and then joining to tableA and TableB to get your desired rows:
SELECT a.ID,
a.col1,
a.Col2,
a.Col3,
b1.Col_X
FROM (
SELECT a_id
,max(rank) AS MaxRank
FROM tableb
GROUP BY a_id
) b
INNER JOIN tablea a ON a.id = b.a_id
INNER JOIN tableb b1 ON b.a_id = b1.a_id AND b1.rank = b.MaxRank
ORDER BY a.ID;
SQL Fiddle Demo
I'm thinking you want to take the max rank from your table b for each row in table a?
There's lots of different ways of approaching this. Here's one simple one:
with maxCTE as
(select
a_id,
max(rank) as MaxRank
from
tableb
group by
a_id
)
select
*
from
tablea a
inner join tableb b
on a.id = b.a_id
inner join maxcte c
on b.a_id = c.a_id
and b.rank = c.MaxRank
SQLFiddle
Basically, the CTE identifies the max rank for each a_id, then we join that back to tableb to get the details about that row.
with x as
(select a_id, max(rank) as mxrnk
from tableB
group by a_id)
select a.id, a.col1, a.col2, a.col3, b.col_x
from tableA a join x
on a.id = x.a_id
join tableB b
on x.mxrnk = b.rank
You can select max rank per a_id in the cte and use it to select the corresponding columns.
One is to INNER JOIN Table B onto Table A by ID's. You will have 3 records returned from Table B. If you ORDER those records by the COLX
SELECT
,a.ID
,a.Col1
,a.Col2
,a.Col3
,b.COLX
FROM TableA AS a
INNER JOIN TABLE_B AS b on b.A_ID = a.id
ORDER BY b.COLX DESC
Then another way is joining a sub query of Table B that also has a sub query that filters Table B records to only the records with the highest RANK.
That way you can bring in COLX values from the highest RANK records from Table B that match the records of Table A.
I think at least...
SELECT
a.ID
,a.Col1
,a.Col2
,a.Col3
,b.COLX
FROM TableA a
INNER JOIN (
SELECT
a.A_ID
,a.RANK
,a.COLX
FROM TABLE_B a
INNER JOIN (
SELECT
A_ID,
,MAX(RANK) AS [RANK] -- Highest Rank
FROM TABLE_B
GROUP BY A_ID
) AS b ON b.A_ID = a.A_ID AND b.RANK = a.RANK
) AS b on b.A_ID = a.id
ORDER BY a.ID ASC
Select A.*,D.Col_X
from
(Select C.COL_X,B.A_ID
from
(Select A_ID,MAX(rank) as MAX_rank
from TABLE_B
group by A_ID) B ----- gets the highest rank and ID of the highest rank
inner join TABLE_B c
on
concat(C.A_ID,C.RANK)= concat(B.A_ID,B.MAX_rank)) D ---- Gets the highest rank name
inner join TABLE_A A
on D.A_ID=A.ID
OUTPUT:
ID Col1 Col2 Col3 Col_X
1 c1 c2 c3 SOMEXXXX
2 c1 c2 c3 VALUE

Joining two tables with condition

I have tables like this
TABLE A
id | name
1 | a
2 | b
3 | c
TABLE B
id | ida | prp | prpval
1 | 1 | visible | true
2 | 1 | active | true
3 | 2 | visible | false
4 | 2 | active | true
5 | 3 | visible | true
6 | 3 | active | true
Table A and Table B are connected by id-ida.
I want to display all names(name) from Table A that have property visible(prp) from TABLE B set to 'true' (prpval). Without any duplicates. So in this example i want to display 'a' and 'b'. How to do it?
select a.name
from a
join b on a.id = b.aid
group by a.name
having sum(case when prp = 'visible' and prpvalue = 'true' then 1 else 0 end) > 0
A simple answer would be:
SELECT A.name
FROM A
INNER JOIN B
ON A.id = B.ida
WHERE B.prp = 'visible'
AND B.prpval = 'true'
SELECT DISTINCT a.name
FROM A a join B b on a.id = b.ida
WHERE b.prp = 'visible' and b.prpval = 'true'
Because you don't want duplicates, I would approach this using an exists clause:
select *
from tableA a
where exists (select 1
from tableB b
where b.ida = a.id and b.prp = 'visitor' and b.prpval = 'true'
);
For performance, create an index on tableB(ida, prp, prpval).
select a.name
from A as a
join B as b on a.id=b.ida
and b.prpval='True' and b.prp='visible'

SQL Join to Get Row with Maximum Value from Right table

I am having problem with sql join (oracle/ms sql)
I have two tables
A
ID | B_ID
---|------
1 | 1
1 | 4
2 | 3
2 | 2
----------
B
B_ID | B_VA| B_VB
-------|--------|-------
1 | 1 | a
2 | 2 | b
3 | 5 | c
4 | 2 | d
-----------------------
From these two tables I need A.ID, B.B_ID, B.B_VA (MAX), B.B_VB (with max B.B_VA)
So result table would be like
ID | B_ID | B_VA| B_VB
-------|--------|--------|-------
1 | 4 | 2 | d
2 | 3 | 5 | c
I tried some joins without success. Can anyone help me with query to get the result I want.
Thank you
Your logic as described doesn't quite correspond to the data. For instance, b_va is numeric, but the column in the output is a string.
Perhaps you want this. The data in a to be aggregated to get the maximum b_id value. Then each column to be joined to get the corresponding b_vb column. That, at least, conforms to your desired output:
select a.id, a.b_id, b1.b_vb as b_va, b2.b_vb
from (select id, max(b_id) as b_id
from a
group by id
) a join
b b1
on a.id = b1.b_id join
b b2
on a.b_id = b2.b_id;
EDIT:
For the corrected data, I think this is what you want:
select a.id, a.b_id, max(b1.b_va) as b_va, b2.b_vb
from (select id, max(b_id) as b_id
from a
group by id
) a join
b b1
on a.id = b1.b_id join
b b2
on a.b_id = b2.b_id
group by a.id, a.b_id, b2.b_vb;
Try this
SELECT X.ID, Y.B_ID, X.B_VA, Y.B_VB
FROM (SELECT A.ID, MAX(B_VA) AS B_VA
FROM A INNER JOIN B ON A.B_ID = B.B_ID
GROUP BY A.ID) AS X INNER JOIN
A AS Z ON X.ID = Z.ID INNER JOIN
B AS Y ON Z.B_ID=Y.B_ID AND X.B_VA=Y.B_VA