SQL Update involving two tables with multiple column conditioning - sql

I have two tables:
and
I would like to update Table Second according to the contents of columns A,B and C in Table First. The colours in the diagram are to clarify how the update should occur.
I have obviously simplified the real problem, but I tried this:
Update Second
set Group = (select distinct Group
from First
where First.A =Second.A
and First.B = Second.B
and First.C = Second.C)
but I was getting an error
Cannot insert the value NULL into column 'Group'
when in fact both tables don't have NULL values. I presume because there are several rows on both tables it is maybe more complicated than I think?

In Standard SQL, you can express this basically as (well, group is not an allowed name):
Update Second
set Group = (select max(f.Group)
from First f
where f.A = Second.A and
f.B = Second.B and
f.C = Second.C
)
where exists (select 1
from First f
where f.A = Second.A and
f.B = Second.B and
f.C = Second.C and
f.Group is not null
);
There may be alternative syntax available in specific databases.
Note the change to the subquery to guarantee that it returns exactly one row.

You need an extra where at the bottom so it doesn't try to update the wrong rows:
where second.a in (select a from first where First.A =Second.A
and First.B = Second.B
and First.C = Second.C)
and second.b in (select b from first where First.A =Second.A
and First.B = Second.B
and First.C = Second.C)
and second.c in (select c from first where First.A =Second.A
and First.B = Second.B
and First.C = Second.C)
Otherwise, and this is not recommended unless you are sure there is a single group for each row AND no blanks:
Update Second
set Group = (select top 1 Group
from First
where First.A =Second.A
and First.B = Second.B
and First.C = Second.C
order by group desc)
So yeah, option 1 if it works is best in my opinion, I have done option 2 before in certain scenarios too.

Related

Trying to update a field conditionally in SQL Stored Procedure

I have a procedure that populates two sets of application information into the same fields. First the fields are filled out with applicable accounts from group "A" and then the same process happens for group "B" accounts.
Most of the group B fields are filled in by a insert/select statement. However, the query to select "account number" is a little more complex and that is in an UPDATE statement. I will paste the code below but I cannot get it to properly update the rows (for group B) with account numbers, despite the fact the query works on its own outside the procedure (essentially, the account numbers do exist).
Any idea why? I tried adding a case statement to single out group B rows (the where clause is hardcoded for group B... e.g. clfcode = 3) but that didn't work. Let me know if you need more information. I haven't much experience with update statements in stored procedures.
update src
set account_key = case when src.clfcode = 3 and src.branch_key = 12 then a.account_key else src.account_key end
from #src_table src
inner join SDFDW_Landing.cu.FICS_ms_Investor_Loan l
on l.loan_id = src.application_number
left join dm.dim_product p
on p.product_key = src.product_key
left join (
Select Distinct t.PARENTACCOUNT, t.USERCHAR1 as loan_id
from SDFDW_Landing.dbo.tracking t
where t.TYPE = 1
and t.ProcessDate = #v_max_last_processed_date
and t.USERCHAR1 is not null
) t on t.loan_id = l.loan_id
left join dm.dim_account a
on t.PARENTACCOUNT = a.account_nkey
WHERE p.bdw_report_category = 'Mortgage'
and l.processdate = #v_max_last_processed_date
The join on a subquery might cause the issue. You could try to replace it with an apply and see if that helps.
update
src
set
account_key =
case
when
src.clfcode = 3
and src.branch_key = 12
then
a.account_key
else
src.account_key
end
from
#src_table src
inner join
SDFDW_Landing.cu.FICS_ms_Investor_Loan l
on l.loan_id = src.application_number
left join
dm.dim_product p
on p.product_key = src.product_key
outer apply (
Select
acc.*
from
dm.dim_account acc
inner join
SDFDW_Landing.dbo.tracking t
on acc.account_nkey = t.parentaccount
where
t.TYPE = 1
and t.ProcessDate = #v_max_last_processed_date
and t.USERCHAR1 is not null
and t.loan_id = l.loan_id
) a
WHERE
p.bdw_report_category = 'Mortgage'
and l.processdate = #v_max_last_processed_date
alternatively since you are already within a stored procedure, I'd populate a temp table with the data from your subquery and simply join on that temp table from your update statement.

update multiple rows with joins

I have this query in postgresql:
select *
from A s
join B m on (s.id=m.id)
where m.key=4 and s.ran=some_input_from_user
This gives me all the rows that I need to update.
I want to set A.value to be 90 for all these rows.
It doesn't look like a standart update query
if I do...
Update A set value=90 where.....
then I can't do the join.
any ideas how to do it?
This is the basic update syntax for PostgreSQL where you are updating based on a join to another table:
update A s
set
value = 90
from B m
where
s.id = m.id and
m.key = 4 and
s.ran = some_input_from_user
The trick is you never use the alias in the lvalue for the set commands. In other words, value = 90 is not s.value = 90. It seems minor, but I'm pretty sure it will prevent your query from working. The rationale is if you are updating table A (alias s) then any fields you are updating are, de-facto, from table A -- no need to alias them, and to allow aliases would almost imply you could update something other than A with this statement, which you cannot.
You can definitely use them in the rvalues, so this would certainly be okay (if it were your desire to update A based on B):
update A s
set
value = m.salary * s.commission
from B m
where
s.id = m.id and
(s.value is null or
s.value != m.salary * s.commission)
Here is the query:
update a set value = 90
where exists (
select 1 from b
where a.id = b.id and b.key=4
and a.ran=some_input_from_user);
The above query will eliminate the requirement of reading table a twice.
Also you can use this query:
update a set value = 90
where a.id in
(select b.id from b
where a.id = b.id and b.key = 4
and a.ran=some_input_from_user);
TRY THIS
UPDATE A
SET A.VALUE = 90
from A
join B m on (A.id=m.id)
where m.key=4 and s.ran=some_input_from_user

update rows from joined tables in oracle

I'm trying to migrate some tables into an existing table, I need to perform the updates only where DET_ATTACHMENT_ID equals DET_ATTACHMENT.ID, here's the query I have so far.
UPDATE DET_ATTACHMENT
SET attachment_type = 'LAB', -- being added by the query, to replace the table difference
payer_criteria_id = (
SELECT PAYER_CRITERIA_ID
FROM DET_LAB_ATTACHMENT
WHERE DET_LAB_ATTACHMENT.DET_ATTACHMENT_ID = DET_ATTACHMENT.ID)
WHERE exists(
SELECT DET_ATTACHMENT_ID
FROM DET_ATTACHMENT
JOIN DET_LAB_ATTACHMENT ON (ID = DET_ATTACHMENT_ID)
WHERE DET_ATTACHMENT_ID = DET_ATTACHMENT.ID
the problem with the existing query is that it's setting every row to have an attachment_type of "LAB", and nulling out the payer_criteria_id where it didn't match. What am I doing wrong?
The problem might be that your exists(...) predicate always evaluates to true, thus making the update run for all rows of det_attachment. Try it this way:
UPDATE DET_ATTACHMENT X
SET X.attachment_type = 'LAB',
X.payer_criteria_id = (
SELECT C.PAYER_CRITERIA_ID
FROM DET_LAB_ATTACHMENT C
WHERE C.DET_ATTACHMENT_ID = X.ID
)
WHERE
exists(
SELECT 1
FROM DET_ATTACHMENT A
JOIN DET_LAB_ATTACHMENT B
ON B.DET_ATTACHMENT_ID = A.ID
where B.det_attachment_id = X.id
)
;

Selective update in SQL Server

I've created a junction table like this one:
http://imageshack.us/scaled/landing/822/kantotype.png
I was trying to figure out a query that could able to select some rows - based on the PokémonID - and then updating only the first or second row after the major "filtering".
For example:
Let's suppose that I would like to change the value of the TypeID from the second row containing PokémonID = 2. I cannot simply use UPDATE KantoType SET TypeID = x WHERE PokémonID = 2, because it will change both rows!
I've already tried to use subqueries containing IN,EXISTS and LIMIT, but with no success.
Its unclear what are your trying to do. However, you can UPDATE with JOIN like so:
UPDATE
SET k1.TypeID = 'somethng' -- or some value from k2
FROM KantoType k1
INNER JOIN
(
Some filtering and selecting
) k2 ON k1.PokémonID = k2.PokémonID
WHERE k1.PokémonID = 2;
Or: if you want to UPDATE only the two rows that have PokémonID = 2 you can do this:
WITH CTE
AS
(
SELECT *,
ROW_NUMBER() OVER(ORDER BY TypeID) rownum
FROM KantoType
WHERE PokemonID = 2
)
UPDATE c
SET c.TypeID = 5
FROM CTE c
WHERE c.rownum = 1;
SQL Fiddle Demo
I can suggest something like this if you just need to update a single line in your table:
UPDATE kantotype
SET
type = 2
WHERE pokemon = 2
AND NOT EXISTS (SELECT * FROM kantotype k2
WHERE kantotype.type > k2.type
AND kantotype.pokemon = k2.pokemon)
It would be easier to get the first or last item of the table if you had unique identifier field in your table.
Not sure even if you are trying to update the row with PokemenID =2 by doing a major filtering on TypeID... So just out of assumptiong (big one), you can give a try on Case
UPDATE yourtable a
LEFT JOIN youtable b on a.pokeid = b.pokeid
SET a.typeid = (CASE
WHEN a.typeid < b.typeid THEN yourupdatevalue
WHEN a.typeid > b.typeid THEN someothervalue
ELSE a.typeid END);
If you know the pokemon ID and the type id then just add both to the where clause of your query.
UPDATE KantoType
SET TypeID = x
WHERE PokémonID = 2
AND TypeID=1
If you don't know the type ID, then you need to provide more information about what you're trying to accomplish. It's not clear why you don't have this information.
Perhaps think about what is the unique identifier in your data set.

Doing an Update Ignore in SQL Server 2005

I have a table where I wish to update some of the rows. All the fields are not null. I'm doing a sub-query, and I wish to update the table with the non-Null results.
See Below for my final answer:
In MySQL, I solve this problem by doing an UPDATE IGNORE. How do I make this work in SQL Server 2005? The sub-query uses a four-table Join to find the data to insert if it exists. The Update is being run against a table that could have 90,000+ records, so I need a solution that uses SQL, rather than having the Java program that's querying the database retrieve the results and then update those fields where we've got non-Null values.
Update: My query:
UPDATE #SearchResults SET geneSymbol = (
SELECT TOP 1 symbol.name FROM
GeneSymbol AS symbol JOIN GeneConnector AS geneJoin
ON symbol.id = geneJoin.geneSymbolID
JOIN Result AS sSeq ON geneJoin.sSeqID = sSeq.id
JOIN IndelConnector AS joiner ON joiner.sSeqID = sSeq.id
WHERE joiner.indelID = #SearchResults.id ORDER BY symbol.id ASC)
WHERE isSNV = 0
If I add "AND symbol.name IS NOT NULL" to either WHERE I get a SQL error. If I run it as is I get "adding null to a non-null column" errors. :-(
Thank you all, I ended up finding this:
UPDATE #SearchResults SET geneSymbol =
ISNULL ((SELECT TOP 1 symbol.name FROM
GeneSymbol AS symbol JOIN GeneConnector AS geneJoin
ON symbol.id = geneJoin.geneSymbolID
JOIN Result AS sSeq ON geneJoin.sSeqID = sSeq.id
JOIN IndelConnector AS joiner ON joiner.sSeqID = sSeq.id
WHERE joiner.indelID = #SearchResults.id ORDER BY symbol.id ASC), ' ')
WHERE isSNV = 0
While it would be better not to do anything in the null case (so I'm going to try to understand the other answers, and see if they're faster) setting the null cases to a blank answer also works, and that's what this does.
Note: Wrapping the ISNULL (...) with () leads to really obscure (and wrong) errors.
with UpdatedGenesDS (
select joiner.indelID, name, row_number() over (order by symbol.id asc) seq
from
GeneSymbol AS symbol JOIN GeneConnector AS geneJoin
ON symbol.id = geneJoin.geneSymbolID
JOIN Result AS sSeq ON geneJoin.sSeqID = sSeq.id
JOIN IndelConnector AS joiner ON joiner.sSeqID = sSeq.id
WHERE name is not null ORDER BY symbol.id ASC
)
update Genes
set geneSymbol = upd.name
from #SearchResults a
inner join UpdateGenesDs upd on a.id = b.intelID
where upd.seq =1 and isSNV = 0
this handles the null completely as all are filtered out by the where predicate (can also be filtered by join predicate if You wish. Is it what You are looking for?
Here's another option, where only those rows in #SearchResults that are succesfully joined will be udpated. If there are no null values in the underlying data, then the inner joins will pull in no null values, and you won't have to worry about filtering them out.
UPDATE #SearchResults
set geneSymbol = symbol.name
from #SearchResults sr
inner join IndelConnector AS joiner
on joiner.indelID = sr.id
inner join Result AS sSeq
on sSeq.id = joiner.sSeqID
inner join GeneConnector AS geneJoin
on geneJoin.sSeqID = sSeq.id
-- Get "lowest" (i.e. first if listed alphabetically) value of name for each id
inner join (select id, min(name) name
from GeneSymbol
group by id) symbol
on symbol.id = geneJoin.geneSymbolID
where isSNV = 0 -- Which table is this value from?
(There might be some syntax problems, without tables I can't debug it)