Selective update in SQL Server - sql

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.

Related

SQL Update involving two tables with multiple column conditioning

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.

SQL Server 2014 Replace Distinct? DeIdentify Data

I am going to explain again what I am trying to do in hopes that you can help.
Table 1 has 4061 rows with columns that include
[Name],[Address1],[Address2],[Address3],[City],[State],[Zip],[Country],[Phone]
and 20 other columns. Table 1 is data that needs to be deidentified. Table 1 has 1534 distinct [Name] rows out of 4061 rows total.
Table 2 has auto generated data which includes the same columns. I would like to replace the above mentioned columns in table 1 with data from table 2. I want to select distinct based on [Name] from table one and then [Name],[Address1],[Address2],[Address3],[City],[State],[Zip],[Country],[Phone] with a new set of distinct data from table 2.
I do not want to just update each row with a new address as that will screw up the data consistency. By replacing only distinct this will allow me to preserve the data consistency while changing the row data in table 1. When I am done I would like to have 1534 distinct new de-identified [Name] [Address1],[Address2],[Address3],[City],[State],[Zip],[Country],[Phone] in table 1 from table 2.
You would use join in the update. You can generate a join key for 1500 rows using row_number():
update toupdate
set t.address = f.address
from (select t.*, row_number() over (order by newid()) as seqnum
from table t
) toupdate join
(select f.*, row_number() over (order by newid()) as seqnum
fake f
) f
on toupdate.seqnum = f.seqnum and t.seqnum <= 1500;
Here is how I ended up doing it.
First I ran a statement to select distinct and inserted it into a table.
Select Distinct [Name],[Address1],[City],[State],[Zip],[Country],[Phone]
INTO APMAST2
FROM APMAST
I then added name2 column in APMAST2 and used a statement to create a sequential id field into APMAST2.
DECLARE #id INT
SET #id = 0
UPDATE APMAST2
SET #id = id = #id + 1
GO
Now I have my distinct info plus a blank name field and a sequential ID field in APMAST2. Now I can join this date with my fakenames table which I generated from. HERE using their bulk tool.
Using a Join Statement I joined my fake data with APMAST2
Update dbo.APMAST2
SET dbo.APMAST2.Name = dbo.fakenames.company,
dbo.APMAST2.Address1 = dbo.fakenames.streetaddress,
dbo.APMAST2.City = dbo.fakenames.City,
dbo.APMAST2.State = dbo.fakenames.State,
dbo.APMAST2.Zip = dbo.fakenames.zipcode,
dbo.APMAST2.Country = dbo.fakenames.countryfull,
dbo.APMAST2.Phone = dbo.fakenames.telephonenumber
FROM
dbo.APMAST2
INNER JOIN
dbo.fakenames
ON dbo.fakenames.number = dbo.APMAST2.id
Now I have my fake data loaded but I kept my original Name field so I could reload this data into my full table ARMAST so now I can do a join between ARMAST2 and ARMAST.
Update dbo.APMAST
SET dbo.APMAST.Name = dbo.APMAST2.Name,
dbo.APMAST.Address1 = dbo.APMAST2.Address1,
dbo.APMAST.City = dbo.APMAST2.City,
dbo.APMAST.State = dbo.APMAST2.State,
dbo.APMAST.Zip = dbo.APMAST2.Zip,
dbo.APMAST.Country = dbo.APMAST2.Country,
dbo.APMAST.Phone = dbo.APMAST2.Phone
FROM
dbo.APMAST
INNER JOIN
dbo.apmast2
ON dbo.apmast.name = dbo.APMAST2.name2
Now my original table has all fake data in it but it keeps the integrity it had , well most of it, so the data looks good when reported on but is de-identified. You can now remove APMAST2 or keep it if you need to match this with other data later on. I know this is long and I am sure there is a better way to do it but this is how I did it, suggestions welcome.

T-SQL Query to check if related col is true and update another table col

I have this 2 tables SupplierOrder and SupplierOrderDetails which are linked by SupplierOrder PK. Now I have this col called isComplete in the SupplierOrder table which I want o update to true once all the values in the SupplierORderDetails table's isComplete are all true for that supplierOrder ID. Please see the attachment for the tables. I have tried myself with this query but I think it could be a better way or more efficient.
SELECT 1
FROM supplierOrder so
inner JOIN supplierOrderdetails sod
ON so.id = sod.supplierOrderID
WHERE so.id = 1
AND sod.isComplete= 1
This should work, I maynot have correct table names but this should work if u change it
UPDATE suplierorder
SET iscomplete = 'true'
WHERE id IN (SELECT suplierorderid
FROM (SELECT suplierorderid,
--case statement to set to 0 if complete and 1 if not complete (i.e any other value null or false)
Sum(CASE
WHEN iscomplete = 'true' THEN 0
ELSE 1
END) AS complete
FROM suplierorderdetails
--make sure we only update the new ones and makes sure that your select records are limited to Just not complete records, so if your tables grow this will make your update statement doesn't take a lot of time
WHERE suplierorderid IN (SELECT id
FROM suplierorder
WHERE iscomplete IS NULL)
--I am grouping on suplierorderid so that we can add all the iscomplete status of each suplierorderid column
GROUP BY suplierorderid) A
--now that the inner query outputs suplierorderid and complete status which will be 0 if everything is complete we are writing below condition
WHERE complete = 0)
All we need is to find supplierOrderID where MIN(isComplete)=1. So it means that ALL isComplete=TRUE
UPDATE supplierOrder SET isComplete=1
WHERE id in
(
SELECT supplierOrderID
FROM supplierOrderdetails
GROUP BY supplierOrderID
HAVING MIN(CAST(isComplete as Int))=1
)
AND
(
(isComplete is NULL ) OR (isComplete = 0)
)
SQLFiddle demo
PS: Since isComplete is a BIT type field you can't use MIN(isComplete) but you can use MIN(CAST(isComplete as Int))

SQL Update Skipping duplicates

Table 1 looks like the following.
ID SIZE TYPE SERIAL
1 4 W-meter1 123456
2 5 W-meter2 123456
3 4 W-meter 585858
4 4 W-Meter 398574
As you can see. Items 1 and 2 both have the same Serial Number. I have an innerjoin update statement that will update the UniqueID on these devices based on linking their serial number to the list.
What I would like to do. Is modify by hand the items with duplicate serial numbers and scripted update the ones that are unique. Im presuming I have to reference the distinct command here somewhere buy not sure.
This is my update statement as is. Pretty simple and straight forward.
update UM00400
Set um00400.umEquipmentID = tb2.MIUNo
from UM00400 tb1
inner join AA_Meters tb2 on
tb1.umSerialNumber = tb2.Old_Serial_Num
where tb1.umSerialNumber <> tb2.New_Serial_Num
;WITH CTE
AS
(
SELECT * , rn = ROW_NUMBER() OVER (PARTITION BY SERIAL ORDER BY SERIAL)
FROM UM00400
)
UPDATE CTE
SET CTE.umEquipmentID = tb2.MIUNo
inner join AA_Meters tb2
on CTE.umSerialNumber = tb2.Old_Serial_Num
where tb1.umSerialNumber <> tb2.New_Serial_Num
AND CTE.rn = 1
This will update the 1st record of multiple records with the same SERIAL.
If i understand your question correctly below query will help you out :
;WITH CTE AS
(
// getting those serial numbers which are not duplicated
SELECT umSerialNumber,COUNT(umSerialNumber) as CountOfSerialNumber
FROM UM00400
GROUP BY umSerialNumber
HAVING COUNT(umSerialNumber) = 1
)
UPDATE A SET A.umEquipmentID = C.MIUNo
FROM UM00400 A
INNER JOIN CTE B ON A.umSerialNumber = B.umSerialNumber
INNER JOIN AA_Meters C ON A.umSerialNumber = C.Old_Serial_Num

How to increment a column based on two tables that are joined

I am trying to increment a column on a sql server table based on the join between the initial table and the joined table. The idea is to update tblForm10Objectives, set the ObjectiveNumber column to an increment number starting with 1 based on the number of rows returned from the join of tblForm10GoalsObjectives and tblForm10Objectives where ID_Form10Goal equals a number. Example query so far:
Update tblForm10Objectives
Set ObjectiveNumber = rn
From (
Select ROW_NUMBER() over (PARTITION by OG.ID_Form10Goal) as rn
, *
From (
Select *
From tblForm10GoalsObjectives OG
Join tblForm10Objectives O On OG.ID_Form10Objective = O.ID_Form10Objective
Where OG.ID_Form10Goal = 4
Order by O.ID_Form10Objective
) as tblForm10Objectives;
If the select portion of the query is performed the columns are displayed so you can see the ObjectiveNumber is currently 0 where ID_Form10Goal = 4
Once the update runs I need for the ObjectiveNumber to show 1 , 2; since there are two rows for ID_Form10Goal = 4.
I had to introduce a new table to the logic of this update statement, the table name is tblForm10Goals. The objectives need to be pulled by ID_Agency instead of ID_Form10Goal I am getting an error message stating a "a multipart identifier 'dbo.tblForm10Objectives.ID_Form10Objective = rns.ID_Form10Objective' could not be bound. I am using the following SQL Update statement:
UPDATE dbo.tblForm10Objectives
SET ObjectiveNumber = rn
FROM tblForm10Goals As g
Left Join tblForm10GoalsObjectives gobs ON g.ID_Form10Goal = gobs.ID_Form10Goal
Right Join
(
SELECT
ROW_NUMBER() OVER (PARTITION BY g.ID_Agency
ORDER BY OB.ID_Form10Objective) AS rn,
OB.ID_Form10Objective
FROM tblForm10Goals g
LEFT JOIN dbo.tblForm10GoalsObjectives gobs ON g.ID_Form10Goal = gobs.ID_Form10Goal
RIGHT JOIN dbo.tblForm10Objectives OB ON gobs.ID_Form10Objective = OB.ID_Form10Objective
Where g.ID_Agency = 2
) rns ON dbo.tblForm10Objectives.ID_Form10Object = rns.ID_Form10Objective
Your example seems to be missing a closing parenthesis somewhere, and without the table structures to look at, I can't be certain of my answer. It seems you have two tables:
tblForm10Objectives
-------------------
ID_Form10Objective
ObjectiveNumber
...
and
tblForm10GoalsObjectives
------------------------
ID_Form10Goal
ID_Form10Objective
...
If this is the case, the following query should give you the results you desire:
UPDATE dbo.tblForm10Objectives
SET ObjectiveNumber = rn
FROM dbo.tblForm10Objectives INNER JOIN
(
SELECT
ROW_NUMBER() OVER (PARTITION BY OG.ID_Form10Goal
ORDER BY O.ID_Form10Objective) AS rn,
O.ID_Form10Objective
FROM dbo.tblForm10Objectives O INNER JOIN
dbo.tblForm10GoalsObjectives OG ON OG.ID_Form10Objective = O.ID_Form10Objective
Where OG.ID_Form10Goal = 4
) rns ON dbo.tblForm10Objectives.ID_Form10Objective = rns.ID_Form10Objective
If you run the inner SELECT statement, you will see the desired ObjectiveNumber values and the corresponding ID_Form10Objective that will get updated with those values.
If you post your table structures, I or someone else may be able to be of more help.