SQL rookie here. I'm trying to update a specific row of values using values from another row in the same table. However, I want the initial values to only update if it's null or does not match the new value.
My current unfinished script:
DECLARE #Record1 VARCHAR(50) = 'ID1',
#Record2 VARCHAR(50)='ID2'
UPDATE R1
SET r1.column1 = COALESCE(r1.column1, r2.column1),
r1.column2 = COALESCE(r1.column2, r2.column2),
r1.column3 = COALESCE(r1.column3, r2.column3),
r1.column4 = COALESCE(r1.column4, r2.column4)
FROM TABLE1 r1
INNER JOIN TABLE1 r2 ON r1.ID1 = #Record1 AND r2.ID2 = #Record2
I'm currently using SQL Server 2016 Management Studio.
EDIT:
After reading Sgeddes's reply, I realize my question was very dumb. Of course replacing everything in Record1 from Record2 makes the most sense.
I guess what I was fishing for was if there way a way to place a condition on each column to update. For example, if I wanted to update Record1's columns 1 & 2 only if NULL, but replace everything in columns 3 & 4 from Record2.
You would use a left join . . . carefully:
UPDATE R1
SET r1.column1 = coalesce(r1.column1, r2.column1),
r1.column2 = coalesce(r1.column2, r2.column2),
r1.column3 = coalesce(r1.column3, r2.column3),
r1.column4 = coalesce(r1.column4, r2.column4)
FROM TABLE1 r1 LEFT JOIN
TABLE1 r2
ON r2.ID2 = #Record2
WHERE r1.ID1 = #Record1 ;
Note that the condition on r1 goes in the where clause so it actually filters rows. The condition on t2 stays in the on clause, so all rows are returned, even when there are no matches in r2.
Related
I have two tables, temp_am and amphibian. The relationship between the two tables comes from the lake_id and the survey_date column in both tables. Both tables have 24,109 entries.
temp_am
id
lake_id
survey_date
1
10,001
7/25/2001
5
10,005
7/27/2001
6
10,006
7/29/2001
etc...
amphibain
id
lake_id
survey_date
amhibian_survey_id
1
10,002
7/25/2001
2
10,005
7/27/2001
etc...
I want to input the temp_am.id into the amphibian.amphibian_survey_id when both lake_ids and survey dates equal each other.
I have tried this sql query but it never worked. I canceled the query after 600 seconds as I figured a 29,000 observation table should not take that long. Please let me know if you see any issues in my query statement.
update amphibian
set amphibian_survey_id = tm.id
from amphibian a
inner join temp_am tm
on a.lake_id = tm.lake_id
and a.survey_date = tm.survey_date
This query worked in microsoft access but not on DBeaver
UPDATE amphibian
inner JOIN amphibian_survey_meta_data md ON
(amphibian.survey_date = md.survey_date) AND (amphibian.lake_id = md.lake_id) SET amphibian.amphibian_survey_id = [md.id];
Postgres does not require repeating the table name for an update join. In this case even the join is not necessary just set <column> = ( select ... ) is sufficient. See demo here.
update amphibain a
set amhibian_survey_id =
( select tm.id
from temp_am tm
where (tm.lake_id, tm.survey_date) =
(a.lake_id, a.survey_date)
) ;
With 20+ years of experience with MS Access and SQL Server, I'm not a novice with respect to SQL, but I am new to PostgreSQL and I have encountered an issue that makes me feel like a complete noob. I have a simple UPDATE query in which I want to update the destination table d with data from the source View m:
UPDATE chgman.tc_data
SET reporttime = m.reporttime, endtime = m.endtime,
itismessage = m.itismessage, shortdesc = m.shortdesc,
longdesc = m.longdesc, severity = m.severity,
tc_source = m.tc_source, tc_state = m.tc_state,
ushr_state = m.ushr_state, mainroad = m.mainroad,
start_location = m.start_location, end_location = m.end_location
FROM
chgman.tc_matched_raw AS m
INNER JOIN
chgman.tc_data AS d ON d.tc_id = m.tc_id;
The result of the query is that EVERY row in table d is populated with data from the FIRST row of View m.
I am prepared for the embarrassment - please enlighten me as to what I have done wrong...
The from/update in Postgres works a bit differently from SQL Server/MS Access.
This should do what you want:
UPDATE chgman.tc_data d
SET reporttime = m.reporttime, . . .
FROM chgman.tc_matched_raw m
WHERE d.tc_id = m.tc_id;
You don't repeat the table in the FROM clause -- that is a new reference to the table.
I have an issue in information link SQL query which joins multiple tables where some dynamic column names are returned. They are stored in label and value attribute of the below query. Please note we had certain fields in the database which when null doesn't appear as column in the output. For e.g a field test1 in the database has all values null then test1 doesn't get returned. However, even if a single value (row) of test1 has some data, I see test1 in the output. The requirement is always have this field in the output irrespective of whether it has the data for not. Please see the query below and point out what is causing issue.
SELECT
I1."item_uid" AS "ITEMUID",
I1."item_reference_uid" AS "ITEMREFERENCEUID",
w2."workflow_abbrv" AS "STATUS",
s3."label" AS "LABEL",
s3."value" AS "VALUE",
a4."active_status_desc" AS "ACTIVESTATUSDESC",
I5."item_reference_uid" AS "PARENTID",
I5."item_desc_display" AS "PARENTDESCDISPLAY"
FROM
("synaptica"."dbo"."sub_elements" s3 LEFT OUTER JOIN "synaptica"."dbo"."ITEMS_REPOSITORY" I1 ON I1."item_uid" = s3."item_uid")
LEFT OUTER JOIN("synaptica"."dbo"."ITEMS_REPOSITORY" I5
RIGHT OUTER JOIN(select "syndetic_key_item", "rel_type_abbrv", "syndetic_rel_item" from "synaptica"."dbo"."SYNDETIC_NETWORK" s55
left join "synaptica"."dbo"."RELATIONSHIP_TYPES" R66 ON S55."syndetic_rel_type" = R66."rel_type_uid"
where (R66."rel_type_abbrv" = 'PhysParent' or R66."rel_type_abbrv" is null))S6
ON
I5."item_uid" = S6."syndetic_rel_item") ON I1."item_uid" = S6."syndetic_key_item",
"synaptica"."dbo"."workflow_types" w2,
"synaptica"."dbo"."active_statuses" a4,
"synaptica"."dbo"."OBJECT_CLASSES" O8,
"synaptica"."dbo"."approval_statuses" a9
WHERE
(I1."item_active_status" = a4."active_status_uid")
AND (a9."approval_status_uid" = I1."item_approval_status")
AND (I1."item_object_class" = O8."object_class_uid")
AND (I1."item_workflow" = w2."workflow_uid")
AND ((left(O8."object_class_abbrv",
7) = left(?VER,
7)))
AND (s3."label" <> 'CLS360_OBJECT_ID')
AND (RIGHT(O8."object_class_abbrv",
10) = 'PHYS CLASS')
The script below returns the 01427 error that the single row sub-query returns more than one row. The rownum<2 gets a few rows updated. The obvious solution is looping through with pl/sql, but I am trying to determine if there is a SQL only solution.
UPDATE ldl.clens le
SET master_song_id =
(SELECT cf.song_id#
FROM lt.master_songs cf
WHERE le.lot_id = cf.lot_id
AND song_id#_fk =
(SELECT msc_songs.song_id#
FROM lt.msc_songs
WHERE msc_songs.song_name = le.song_name)
---- AND ROWNUM < 2
);
Any and all help and suggestions deeply appreciated!
MD
I'm not sure I grasped the relation between the tables, but if I did, you can use below UPDATE:
UPDATE ldl.clens le
SET master_song_id =
(SELECT cf.song_id#
FROM lt.master_songs cf
JOIN lt.msc_songs ms ON (cf.song_id#_fk = ms.song_id#)
WHERE
ms.song_name = le.song_name
AND le.lot_id = cf.lot_id)
;
It will work if msc_songs.song_name and master_songs.lot_id will give you a unique master_songs.song_id#.
What I have is a table with the following columns
All columns are nvarchar expect for the Date columns which are datetime
CreateDateA InvIDA StorageIDA CreateDateB InvIDB StorageIDB UniID
What I want to do is move the values on each row (based on UniID) into the represenative B columns where UniID is 1 less, so the 'A' columns where UniID = 2 should go to the B Columns where the UniID = 1.
This is the query i'm using but it's not updating any columns.
update InvSubmission
set CreateDateB = CreateDateA,
InvIDB = InvIDA ,
StorageIDB = StorageIDA
where StorageIDB = StorageIDA and UniID = (select UniID-1 from InvSubmission)
There is multiple storageid's in this table, however, each record has a match to at least one other row.
#PinnyM's answer is close, but in SQL Server, you have to name the updated table in the from clause also:
update toUpdate
set CreateDateB = sourceTable.CreateDateA,
InvIDB = sourceTable.InvIDA
FROM
InvSubmission toUpdate
inner Join
InvSubmission sourceTable
ON sourceTable.UniID = toUpdate.UniID + 1
AND sourceTable.StorageIDA = toUpdate.StorageIDB
Otherwise, this note becomes relevant:
If the object being updated is the same as the object in the FROM clause and there is only one reference to the object in the FROM clause, an object alias may or may not be specified
And then you're suffering the same problem that #Yuck pointed out - you're trying to compare the UniID value within a single row to a value one less than itself.
UniID = (select UniID-1 from InvSubmission) is equivalent to UniID = UniID - 1. So, for example, you're basically saying:
WHERE 2 = (2 - 1)
And that's never going to be true, which is why the query isn't modifying anything.
If both the A and B columns are in the same row you don't even need to qualify by using the ID clause. Otherwise you need to self-join like this:
update InvSubmission
set CreateDateB = B.CreateDateA,
InvIDB = B.InvIDA ,
StorageIDB = B.StorageIDA
from InvSubmission A INNER JOIN
InvSubmission B ON A.UniID = B.UniId - 1
where A.StorageIDB = A.StorageIDA;
As I mentioned it's a little confusing because your example makes it look like the columns are all contained in the same row...
It may actually depend on which RDBMS you are using (some are finicky on how aliases can be used), but you can try:
update InvSubmission
set CreateDateB = sourceTable.CreateDateA,
InvIDB = sourceTable.InvIDA ,
StorageIDB = sourceTable.StorageIDA
FROM InvSubmission sourceTable
WHERE sourceTable.UniID = InvSubmission.UniID + 1