How to reference column on inserted table in after trigger - sql

I have an update to process on a trigger when a specific code in the column is input. When I reference the inserted table, which shows in the intellisence dropdown list when I type inserted I get the error:
The multipart identifier "inserted.contact" could not be bound.
Any idea how to reference a column in the inserted table for a trigger? Also, why is it better to use the inserted table than the existing table?
USE PCUnitTest
GO
UPDATE P
SET
P.First_Name = T.ForeName
,P.Middle_Name = T.Middle_Name
,P.Last_name = T.Surname
FROM GMUnitTest.dbo.Contact1 C
INNER JOIN PCUnitTest.dbo.People P
ON P.People_ID = C.Key4
CROSS APPLY dbo.NameParser(inserted.Contact) T --"the multipart identifier "inserted.contact" could not be bound"
WHERE C.Key1 = '76'
;

You bring in inserted just like any table:
UPDATE P
SET P.First_Name = T.ForeName,
P.Middle_Name = T.Middle_Name,
P.Last_name = T.Surname
FROM PCUnitTest.dbo.People P JOIN
GMUnitTest.dbo.Contact1 C
ON P.People_ID = C.Key4 JOIN
inserted i
ON i.?? = c.?? CROSS APPLY
dbo.NameParser(i.Contact) T
WHERE C.Key1 = '76';
The only question is what columns you use for the JOIN. The ?? are for your column names.

Related

replace missing value in update left join statement

I updated an existing table with the update left join statement as per the following:
UPDATE A
SET A.SPSS_FieldForce = B.Remarks
FROM FBL1IN_working as A
left JOIN remarks_master_data as B
ON A.Vendor = B.Vendor_Code;
However, I need to replace the NULL values in the SPSS_FieldForce column with "Non SPSS / FFV' value. Currently, I am doing this with another statement as follows:
UPDATE
FBL1IN_working
SET
SPSS_FieldForce = 'Non SPSS/ FFV'
WHERE
SPSS_FieldForce IS NULL;
This does the job, but I would like to combine this two different statement into one. I am sure that there is a way to replace the missing value on the first update left join statement, but I just have no clue how to get it done.
It seems to be sqlserver syntax, right ?
Then
UPDATE A
SET A.SPSS_FieldForce = WHEN B.Vendor_Code IS NULL THEN 'Non SPSS / FFV' ELSE B.Remarks END
FROM FBL1IN_working as A
LEFT JOIN remarks_master_data as B ON A.Vendor = B.Vendor_Code;
Having B.Vendor_Code to be NULL means that the record is missing in your B table
Use COALESCE():
UPDATE w
SET SPSS_FieldForce = COALESCE(rmd.Remarks, 'Non SPSS/ FFV')
FROM FBL1IN_working w LEFT JOIN
remarks_master_data rmd
ON w.Vendor = rmd.Vendor_Code;
Notice that I also changed the table aliases so they are meaningful -- abbreviations for the table names. Arbitrary letters make the query much harder to read.
UPDATE A SET
A.SPSS_FieldForce = ISNULL( B.Remarks, 'Non SPSS/ FFV')
FROM FBL1IN_working as A
left JOIN remarks_master_data as B ON A.Vendor = B.Vendor_Code;

Update different data type columns

I have two tables GCB.NewsOne & GCB.NewsTwo both table are same except one column
it's GCode in dbo.News table GCode is varchar(100) null and GCB.News table has a bigint null column.
Now I want to update the code in GCode in dbo.News to the value of GCB.News.
I tried like below, but it's not working
UPDATE [GCB].[NewsOne] AS G
SET G.Code = (SELECT P.Code FROM GCB.NewsTwo P WHERE G.ID = P.ID)
Try casting the bigint to varchar:
UPDATE G
SET Code = CAST(P.Code AS VARCHAR(MAX))
FROM [GCB].[NewsOne] G
INNER JOIN GCB.NewsTwo P
ON G.ID = P.ID;
This assumes that your problem really is the types of the two codes, and not something else.
Also note that I rewrote your join using update join syntax, which I think is easier to read.
You may not use an alias in an update statement. This works fine:
UPDATE [GCB].[NewsOne]
SET [GCB].[NewsOne].Code = ( SELECT P.Code FROM GCB.NewsTwo P
WHERE [GCB].[NewsOne].ID=P.ID )

SQL Server update statement error

I am writing a script to update the duplicate contact and all its tables where it is referenced.
One of the update statements that I have is the following:
/* update the contactid, and the compcontactid on the compcontact table */
UPDATE cmpc
SET cmpc.contactid = tt.contactid,
cmpc.compcontactid = (SELECT MAX(cc.compcontactid)
FROM compcontact cc
INNER JOIN #tempDupContacts tdup ON tdup.contactid = cc.contactid
INNER JOIN #tempTable tt ON tt.namefml = tdup.namefml)
FROM compcontact cmpc
INNER JOIN #tempDupContacts tdup ON tdup.contactid = cmpc.contactid
INNER JOIN #tempTable tt ON tt.namefml = tdup.namefml
However, when I run the script (script is way tooo long to post here), I get the following error:
Msg 2601, Level 14, State 1, Line 255
Cannot insert duplicate key row in object 'dbo.compcontact' with unique index 'XPKcompcontact'. The duplicate key value is (A000UZCU, A00JTCAP, X00GM2NF).
Can anyone explain why this is happening, and what the fix would be?
Is this because It is attempting to update the value that has the
You are attempting to update a unique key value to a value that already exists in the column. This is not allowed, since each value in the unique key must be unique.
As #sion_corn said, you're trying to update a column having unique key constraint.
Try adding a WHERE clause in your update statement to exclude the value which already exists.
For example:
UPDATE cmpc
SET cmpc.contactid = tt.contactid,
cmpc.compcontactid = (SELECT MAX(cc.compcontactid)
FROM compcontact cc
INNER JOIN #tempDupContacts tdup ON tdup.contactid = cc.contactid
INNER JOIN #tempTable tt ON tt.namefml = tdup.namefml
WHERE cc.compcontactid <> cmpc.compcontactid)
FROM compcontact cmpc
INNER JOIN #tempDupContacts tdup ON tdup.contactid = cmpc.contactid
INNER JOIN #tempTable tt ON tt.namefml = tdup.namefml
WHERE cmpc.contactid <> tt.contactid

Join different tables depending on field values

I have the following sql view result which contains the audited changes for every field for every table in the system:
In this case the above image tell us that both read and write permissions were revoked for the user Lucas for the subscription called MySubscription.
I need to display that info in a grid however that is not what I want to display, I mean, I donĀ“t want to display IDs. I need to display "Read" instead of 50, "Write" instead of 51, "Lucas" instead of 1 and "MySubscription" instead of 6.
To do that I would like to improve the sql view to get the values instead of their IDs as I mention above. The result that I am looking for is this one:
The database contains the tables Subscriptions, ProductPermissions and TenantUsers to get the needed info using joins.
Could you please give me some clues about how could I achieve what I need? Thank you.
You could do this with a series of LEFT JOINs, some casting might be required to get the datatype of the joining column the same as NewValue (I've assumed a column called Name in all your joining tables, this may need changing):
SELECT a.AuditLogId,
a.Operation,
a.[Table],
a.RowId,
a.Name,
[OldValue] = COALESCE(s_Old.Name, pp_old.Name, t_Old.Name),
[NewValue] = COALESCE(s_New.Name, pp_New.Name, t_New.Name)
FROM AuditLog a
LEFT JOIN Subscriptions s_Old
ON a.OldValue = CAST(s_Old.SubscriptionID AS VARCHAR)
AND a.Name = 'SubscriptionID'
LEFT JOIN ProductPermissions pp_Old
ON a.OldValue = CAST(p_Old.ProductPermissionID AS VARCHAR)
AND a.Name = 'ProductPermissionId'
LEFT JOIN TenantUsers t_Old
ON a.OldValue = CAST(t_Old.TenantUserId AS VARCHAR)
AND a.Name = 'TenantUsers'
LEFT JOIN Subscriptions s_New
ON a.NewValue = CAST(s_New.SubscriptionID AS VARCHAR)
AND a.Name = 'SubscriptionID'
LEFT JOIN ProductPermissions pp_New
ON a.NewValue = CAST(p_New.ProductPermissionID AS VARCHAR)
AND a.Name = 'ProductPermissionId'
LEFT JOIN TenantUsers t_New
ON a.NewValue = CAST(t_New.TenantUserId AS VARCHAR)
AND a.Name = 'TenantUsers'
If required you could then PIVOT this into one row per transaction:
SELECT a.AuditLogId,
a.Operation,
a.[Table],
a.RowId,
[OldSubscriptionValue] = MAX(s_old.Name),
[OldProductPermissionValue] = MAX(pp_old.Name),
[OldTennantUserValue] = MAX(t_old.Name),
[NewSubscriptionValue] = MAX(s_New.Name),
[NewProductPermissionValue] = MAX(pp_New.Name),
[NewTennantUserValue] = MAX(t_New.Name)
FROM AuditLog a
LEFT JOIN Subscriptions s_Old
ON a.OldValue = CAST(s_Old.SubscriptionID AS VARCHAR)
AND a.Name = 'SubscriptionID'
LEFT JOIN ProductPermissions pp_Old
ON a.OldValue = CAST(p_Old.ProductPermissionID AS VARCHAR)
AND a.Name = 'ProductPermissionId'
LEFT JOIN TenantUsers t_Old
ON a.OldValue = CAST(t_Old.TenantUserId AS VARCHAR)
AND a.Name = 'TenantUsers'
LEFT JOIN Subscriptions s_New
ON a.NewValue = CAST(s_New.SubscriptionID AS VARCHAR)
AND a.Name = 'SubscriptionID'
LEFT JOIN ProductPermissions pp_New
ON a.NewValue = CAST(p_New.ProductPermissionID AS VARCHAR)
AND a.Name = 'ProductPermissionId'
LEFT JOIN TenantUsers t_New
ON a.NewValue = CAST(t_New.TenantUserId AS VARCHAR)
AND a.Name = 'TenantUsers'
GROUP BY a.AuditLogId, a.Operation, a.[Table], a.RowId;
It is a pretty dirty solution, I would be inclined to store this data in the format you want to select it in i.e. instead of 50/51, store read/write directly in the NewValue column.
Alternatively, if you did want the second format with one row per transaction then I'd be inclined to store it in this way. It could be worth reading about the Entity-Attribute-Value Antipattern.
You could PIVOT the data and LEFT JOIN to the lookup tables. Then UNPIVOT if necessary.
If you simply need to display words instead of numbers, create a lookup table that maps between the number and the word you want to display:
create table NewValueText (
NewValue integer,
Description char(20)
);
insert into NewValueText values
(50, 'Read'),
(51, 'Write'); --etc.
--MyTable is your table that contains the NewValue column.
select Description from MyTable
inner join NewValueText on MyTable.NewValue = NewValueText.NewValue;
You could try joining in your tables where your values are specific. You'll need to create a look-up table for other values other than Really it's a dirty solution because it means hard coding your NewValue fields into the SQL:
...
FROM
audit LEFT JOIN
mysubscription ON audit.rowid = mysubscription.tenantuserid
AND audit.newvalue = 1
LEFT JOIN
lookup_list ON audit.rowid = lookup_list.lookup_id
AND audit.newvalue <> 1
...
That may work for you.

How to copy column from one table to another using JOIN

What is wrong with the following PostgreSQL query?
UPDATE project_project SET project_project.create_date = assignments.start_date
FROM project_project
LEFT JOIN account_analytic_account ON account_analytic_account.id = project_project.analytic_account_id
LEFT JOIN assignments ON assignments.accounts_ref = account_analytic_account.id
gives
[SQL] UPDATE project_project SET project_project.create_date = assignments.start_date
FROM project_project
LEFT JOIN account_analytic_account ON account_analytic_account.id = project_project.analytic_account_id
LEFT JOIN assignments ON assignments.accounts_ref = account_analytic_account.id
[Err] ERROR: table name "project_project" specified more than once
I tried,
UPDATE pp SET pp.create_date = am.start_date
FROM project_project as pp
LEFT JOIN account_analytic_account as aa ON aa.id = pp.analytic_account_id
LEFT JOIN assignments as am ON am.accounts_ref = aa.id
gives
[SQL] UPDATE pp SET pp.create_date = am.start_date
FROM project_project pp
LEFT JOIN account_analytic_account aa ON aa.id = pp.analytic_account_id
LEFT JOIN am ON am.accounts_ref = aa.account_analytic_account.id
[Err] ERROR: relation "pp" does not exist
LINE 1: UPDATE pp SET pp.create_date = am.start_date
What is the correct syntax?
There are two problems to avoid:
1- in SET column=value, do not prepend a table name or alias to column. It yields an error and is useless anyway, since UPDATE tablename is only able to update columns from tablename. An alias of tablename can be used in other places, but not in the SET clause.
2- don't repeat the name of the table to update in the rest of the query unless you want to specifically induce a secondary and uncorrelated scan of this table.
Here is my proposal of a modified query that I hope does what you intend:
UPDATE project_project pp SET create_date =
(select assignments.start_date FROM account_analytic_account LEFT JOIN assignments
ON assignments.accounts_ref = account_analytic_account.id
WHERE
account_analytic_account.id = pp.analytic_account_id);