How to update one table based on aggregate query form another table - sql

Say I have two tables.
Table A
id
A_status
parent_id_B
Table B
id
B_status
So for each id in B can have many records in A.
Now my question is, I need to set B_status to 1 when all child entries in Table A with same parent_id_B has A_status =1, else set B_status = 2
Ex:
Table A:
id A_status parent_id_B
1 1 1
2 1 1
3 1 2
4 1 3
5 1 3
Table B:
id B_status
1 0
2 0
3 0
Expected result:
Table B:
id B_status
1 1
2 1
3 1
Now consider another scenario
Table A:
id A_status parent_id_B
1 1 1
2 1 1
3 2 2
4 2 3
5 1 3
Table B:
id B_status
1 0
2 0
3 0
Expected result:
Table B:
id B_status
1 1
2 2
3 2
I need this to work only on sqlite. Thanks

I believe this can be done like so:
UPDATE TableB
SET B_Status =
(SELECT MAX(A_Status) FROM TableA WHERE TableA.Parent_ID_B = TableB.ID);
SqlFiddle with your second case here
In a more general case (without relying on direct mapping of A's status, you can also use a CASE ... WHEN in the mapping:
UPDATE TableB
SET B_Status =
CASE WHEN (SELECT MAX(A_Status)
FROM TableA
WHERE TableA.Parent_ID_B = TableB.ID) = 1
THEN 1
ELSE 2
END;
Edit (in the case where there are more than the original number of states):
I believe you'll need to determine 2 facts about each row, e.g.
Whether there is are any rows in table A with a status other than 1 for each B
And there must at least be one row for the same B
Or, whether the count of rows of A in state 1 = the count of all rows in A for the B.
Here's the first option:
UPDATE TableB
SET B_Status =
CASE WHEN
EXISTS
(SELECT 1
FROM TableA
WHERE TableA.Parent_ID_B = TableB.ID
AND TableA.A_Status <> 1)
OR NOT EXISTS(SELECT 1
FROM TableA
WHERE TableA.Parent_ID_B = TableB.ID)
THEN 2
ELSE 1
END;
Updated Fiddle

Related

How to use a new column as a flag to show Null row?

I have table A:
id
1
2
3
4
5
and table B:
id
2
3
4
I left join A and B:
id id
1 NULL
2 2
3 3
4 4
5 NULL
And how can I get a new column like this:
id id flag
1 NULL 0
2 2 1
3 3 1
4 4 1
5 NULL 0
Generally speaking, I want all rows in A but not in B to be flaged as 0 and want all rows in both tables to be flaged as 1. How can I achieve that? Better not use CTE.
This is just a CASE expression:
CASE WHEN B.id IS NULL THEN 0 ELSE 1 END AS flag
Alternatively, you could use an IIF (which is shorthand CASE expression):
IIF(b.id IS NULL, 0,1)
I would recommend using exists:
select a.*,
(case when exists (select 1 from b where b.id = a.id
then 1 else 0
end) as flag
from a;
The purpose of using exists instead of left join is that you are guaranteed to not get duplicate rows -- even if ids are duplicated in b. That is a nice guarantee.
From a performance perspective, the two should be similar, but it is possible that the case is an iota faster.

To update a column by checking the value from another column in a different table

I am trying to update flag in my main table based on the flag in another common table.Both are related with the Foreign Key relationship. But the problem is the flag in another common table is either 0 or 1. So, it should update the flag in the main table as 1 only if all the values for a particular FK is 1.
Suppose that there are 2 tables listed below. XYZ and ABC. Both are related to each other through Foreign Key.
XYZ:
XYZID Posted
1 0
2 0
3 0
4 0
ABC:
ABCID XYZID IsPosted
1 1 1
2 1 1
3 2 0
4 2 0
5 2 0
6 3 1
7 3 0
8 4 0
9 4 0
10 4 1
If you see for XYZID in ABC table the Isposted value is 1 for both. I want that value to be updated in the Posted as 1 of XYZ main table for XYZID 1. But if you look at XYZID value 3 in ABC table for IsPosted then it is 0 and 1. So for XYZID value 3 the Posted value should not be updated in the XYZ table as 1. In general, if all the foreign key value has the IsPosted as 1 then only it should be updated as 1 in the Posted column of XYZ table. If it is 0 or 1 then it should not update in the XYZ table.
I thought of using group by or cursor. But don't know how to start on this.
If anyone can help me in this then would be helpful. It is pretty simple but I am not getting the idea to start on this. Any help would be appreciated.
Update the table by joining a subquery that groups by xyzid the table abc and sets the condition in the having clause:
update t
set posted = 1
from xyz t inner join (
select xyzid from abc
group by xyzid
having sum(case when isposted = 0 then 1 else 0 end) = 0
) a on a.xyzid = t.xyzid
The condition in the having clause could also be written:
having sum(abs(isposted - 1)) = 0
See the demo.
Results:
> XYZID | Posted
> ----: | -----:
> 1 | 1
> 2 | 0
> 3 | 0
> 4 | 0
Assuming there can only be 0 or 1, one way is to use a correlated subquery getting the minimum isposted for an xyzid.
UPDATE main_table
SET posted = (SELECT min(another_common_table.isposted)
FROM another_common_table
WHERE another_common_table.xyzid = main_table.xyzid);
If there is a 0 the minimum will be 0. If there's only 1s it'll be 1.
Try the following:
UPDATE [a]
SET a.[Posted] = [b].[IsPosted]
FROM [a]
INNER JOIN (SELECT [xyzid],
[IsPosted] = MIN(Cast([IsPosted] AS INT))
FROM
[b]
GROUP BY
[xyzid]
HAVING
MIN(Cast([IsPosted] AS INT)) = 1) [b]
ON [a].[xyzid] = [b].[xyzid]
Essentially, the inner query returns only those entries from table B with all 1 values and then updates the A table based on the FK join.
There may be more efficient queries AND this will re-update previously updated A.Posted values and will NOT un-update A.Posted if anything in table B is marked as IsPosted = 0.

Update table column that is used for ordering according to alphabetical order on a second table

So I have two tables (A and B) that have a relation of n-n.
So there is a third table (C) that is used to connect both tables.
Table A and B both have an Id and a name.
Table C has IDA, IDB and an Order, the number that is used to sort and that is user given.
My issue is that I need to migrate table C since I just added that order column and so I need to give every line an ordering number, according to the B name.
So if table A has:
Id Name
1 A
2 B
3 C
And Table B has:
Id Name
1 J
2 L
3 M
And table C has:
IdA IdB Order
1 2 0
1 1 0
1 3 0
2 1 0
2 3 0
I need a query that updates table C to be more like:
IdA IdB Order
1 2 2
1 1 1
1 3 3
2 1 1
2 3 2
I have a query that can basically do what i want but it leaves me with "gaps"
reading my results above i get:
IdA IdB Order
1 2 2
1 1 1
1 3 3
2 1 1
2 3 3
I think this should work for what you need:
With ToUpdate As
(
Select C.*,
Row_Number() Over (Partition By C.IdA Order By B.Name) As NewOrder
From C
Join B On B.Id = C.IdB
)
Update C
Set "Order" = U.NewOrder
From ToUpdate U
Where U.IdA = C.IdA
And U.IdB = C.IdB
(In full disclosure, I'm not terribly familiar with postgres, but I think this should be valid).

Formatting the results of a query

Let's say I have the following table:
first second
A 1
A 1
A 2
B 1
B 2
C 1
C 1
If I run the following query:
select first, second, count(second) from tbl group by first, second
It will produce a table with the following information:
first second count(second)
A 1 2
A 2 1
B 1 1
B 2 1
C 1 2
How can I write the query so that I am given the information with the options from the second column as columns and the values for those columns being the count like this:
first 1 2
A 2 1
B 1 1
C 2 0
You can use CASE:
SELECT "first",
SUM(CASE WHEN "second" = 1 THEN 1 ELSE 0 END) AS "1",
SUM(CASE WHEN "second" = 2 THEN 1 ELSE 0 END) AS "2"
FROM tbl
GROUP BY "first"

PLSQL UPDATE BASED ON ROWS FROM OTHER TABLE

I have following tables in APEX A and B.
A has columns:
ID_A;
VALUE;
B has columns:
ID_C_FK;
ID_A_FK
I want to update the VALUE column in table A in rows where ID_A equals ID_A_FK in selected rows from table B where ID_C_FK equal x
For example: A has rows (
ID_A value
------------
1 1
2 1
3 0
4 0
5 0
Table B has rows
ID_C_FK ID_A_FK
------------------
8 4
9 4
9 5
I want to update VALUE in table A only for those rows that have ID_A in rows selected from B and condition to select rows from B is that ID_C_FK equals x = 9; and as a result, table A should end up having rows:
ID_A value
------------
1 1
2 1
3 0
4 1
5 1
How to write such update in PL/SQL?
Thank you for considering my request.
I think this is what you want:
update a
set value = 1
where exists (select 1
from b
where b.id_a_fk = a.id_a and b.id_c_fk = 9
);