Stored procedure "forgetting" field between update and insert statement - sql-server

We have a stored procedure that is used to UPDATE a table with a value calculated from an existing column.
I am trying to amend the stored procedure to also INSERT a row into a different table, using that same column's value but the column is being rejected by the parser as an invalid column name.
Here is a condensed version of the code. As originally supplied the sequence_no is known to the stored procedure and ends up in reference_no. i.e. the UPDATE works but the INSERT fails.
ALTER PROCEDURE [dbo].[update_references]
AS
-- Original contents:
UPDATE table1
SET reference_no = sequence_no
FROM table1 t1 WITH (NOLOCK)
LEFT OUTER JOIN proptable p1 WITH (NOLOCK) ON t1.checkval = p1.checkval
WHERE p1.fruit = 'apple'
-- I have added the INSERT
INSERT INTO table2 (next_seq_no)
VALUES (sequence_no)
The sequence_no is underlined in red in SSMS.

The insert statement in your code knows nothing about the previous update so you can't reference random columns from that and expect them to still be in scope. The easiest way of doing this is using the OUTPUT clause.
UPDATE table1
SET reference_no = sequence_no
OUTPUT INSERTED.reference_no INTO table2 (next_seq_no)
FROM table1 t1
LEFT OUTER JOIN proptable p1 ON t1.checkval = p1.checkval
WHERE p1.fruit = 'apple'

Related

How to set trigger based on update query in SQL Server?

I am trying to set trigger whenever phone is updated in table1 and then do operation like check phone from table2 and if present, pick up the employee code from table2 and then update employee code in table1.
My code for trigger:
CREATE TRIGGER UPDATED_Contact_Trigger
ON table1
AFTER UPDATE
AS
DECLARE #tuid bigint;
DECLARE #phone varchar(15);
DECLARE #employee_code varchar(10);
IF (UPDATE (phone)) --Phone is the Column Name
BEGIN
SELECT #employee_code = i.emp_code
FROM table2 i (nolock)
WHERE i.MOBILE_NO = #phone
UPDATE table1
SET client_code = #employee_code
WHERE tuid= #tuid
END;
This trigger is set, but there is no update on table1 even if I update a contact which is present in table2
You're not even looking at the Inserted or Deleted pseudo tables in your code - how do you want to know what rows have been updated??
Inserted is a pseudo table that contains all updated rows - and it contains the new values after the update operation, while Deleted contains the same rows, but with the old values before the update.
You need to do something like this:
join your Table1 to Inserted to get the rows that were updated (since you didn't show your table structure, I cannot know what your primary key on Table1 is - you need to use that to join to Inserted)
add a join to your Table2 and pick those rows that have been updated, and limit those to the ones that have been updated in the Phone column (by comparing the Inserted.Phone value to Deleted.Phone)
Try this code:
CREATE TRIGGER UPDATED_Contact_Trigger
ON table1
AFTER UPDATE
AS
BEGIN
-- update your base table
UPDATE t1
-- set the client_code to the employee_code from Table2
SET client_code = t2.employee_code
FROM dbo.Table1 t1
-- join to "Inserted" to know what rows were updated - use the primary key
INNER JOIN Inserted i ON t1.(primarykey) = i.(primarykey)
-- join to "Deleted" to check if the "Phone" has been updated (between Deleted and Inserted)
INNER JOIN Deleted d ON i.(primarykey) = d.(primarykey)
-- join to "Table2" to be able to fetch the employee_code
INNER JOIN dbo.Table2 t2 ON t2.mobile_no = t1.phone
-- ensure the "Phone" has changed, between the old values (Deleted) and new values (Inserted)
WHERE i.Phone <> d.Phone;
END;

(TRIGGER) if cell1 = 'value' THEN INSERT INTO table (date) VALUES (CURRENT_TIMESTAMP)

I need to create a trigger in SQL Server that triggers every time that the value from column "status" = 'Baja'
CREATE TRIGGER trg_triggerName
ON dbo.table1
AFTER UPDATE
AS
BEGIN
IF status = 'Baja' THEN BEGIN
INSERT INTO dbo.table1 (fechaBaja)
VALUES (CURRENT_TIMESTAMP)
END
END
GO
I got this error message
Msg 207, Level 16, State 1, Procedure trg_FechaBaja, Line 3 [Batch Start Line 34]
Invalid column name 'status'.
IF status = 'Baja' THEN BEGIN
In this line the "status" give me the message "invalid column name 'status'" and I'm 100% sure that my column has that name.
IN RESUME: Got a table named table1 that has a column named 'status' and another column named 'fechaBaja'
Every time that the 'status' value changes to 'Baja', I need to trigger and update the cell 'fechaBaja' with the current_timestamp
All the operations are in the same table1.
First, you want an update, not an insert.
Second, A trigger in SQL Server is fired once per statement, not once per row. This means that if the update statement that fired the trigger have updated multiple rows, your trigger will be fired once, and include data about these rows in the inserted and deleted tables.
Third, You need to make sure that the update statement inside the trigger will not raise it again. Do that by configuring the database.
The code you need is something like this:
CREATE TRIGGER trg_triggerName ON dbo.table1
AFTER UPDATE AS
BEGIN
UPDATE t
SET fechaBaja = CURRENT_TIMESTAMP
FROM dbo.table1 As T
INNER JOIN Inserted As I
ON T.<PrimaryKey> = I.<PrimaryKey>
INNER JOIN Deleted As D
ON T.<PrimaryKey> = D.<PrimaryKey>
WHERE I.[status] = 'Baja'
AND (D.[Status] IS NULL OR D.[Status] <> 'Baja')
END
GO
I believe you want to update fechaBaja field if updated row status field equal'Baja'. You need to capture primary key information as well. I put 'Id' but you need to change it with your actuel field name.
CREATE TRIGGER trg_triggerName ON dbo.table1
AFTER UPDATE AS
BEGIN
UPDATE dbo.table1 SET fechaBaja=CURRENT_TIMESTAMP
WHERE EXISTS (SELECT 1 FROM INSERTED I WHERE dbo.table1.Id = I.Id AND I.Status='Baja')
END
GO
You can do it by joining the three tables like
CREATE TRIGGER trg_triggerName ON dbo.table1 AFTER UPDATE AS
BEGIN
UPDATE T1
SET T1.fechaBaja = CURRENT_TIMESTAMP
FROM dbo.table1 T1 INNER JOIN INSERTED T2 ON T1.ID = T2.ID
INNER JOIN DELETED T3 ON T1.ID = T3.ID
WHERE T2.[status] = 'Baja'
AND
(T3.[status] <> 'Baja' OR T3.[status] IS NULL);
END
GO
There is no need to use IF.
status is a reserved word, enclose it in brackets.
Join your table with INSERTED table to get all the IDs of the rows updated.
Join your table with DELETED table to get all the IDs where the data is not 'Baja'.
Filter by where INSERTED.[status] = 'Baja' AND DELETED.[status] <> 'Baja' to update only those rows.

SQL Trigger Insert on Create convert column

I am trying to create a trigger to insert a record into one table when a record is created in another table. I have figured out how to do this however I am trying to figure out how to change a value of one of the columns value.
In the originating table I have 'County' and in the second table I have a 'CountyID' that comes from a 'County' table. How would I take the 'County' and convert it into a 'CountyID'?
My trigger so far -
CREATE TRIGGER [dbo].[AQB_RMS_LocationCreate] on [AVData].[dbo].[SourceSite]
AFTER INSERT
AS
BEGIN
INSERT INTO AQB_MON.[AQB_RMS].[Location]
([LocationName],[Latitude],[Longitude],[Enabled]
,[StreetAddress1],[StreetAddress2],[City],[CountyID],[StateAbbr],[ZipCode],[DATE_CREATED])
SELECT i.[Description],i.[Latitude],i.[Longitude],i.[Enabled]
,i.[StreetAddress1],i.[StreetAddress2],i.[City],i.[County],i.[StateRegion],i.[ZipCode], getdate()
from [AVData].[dbo].[SourceSite] ss
inner join inserted i on ss.SourceSiteID = i.SourceSiteID
END
GO
Wouldn't this work?
CREATE TRIGGER [dbo].[AQB_RMS_LocationCreate] on [AVData].[dbo].[SourceSite]
AFTER INSERT
AS
BEGIN
INSERT INTO AQB_MON.[AQB_RMS].[Location]
([LocationName],[Latitude],[Longitude],[Enabled]
,[StreetAddress1],[StreetAddress2],[City],[CountyID],[StateAbbr],[ZipCode],[DATE_CREATED])
SELECT i.[Description],i.[Latitude],i.[Longitude],i.[Enabled]
,i.[StreetAddress1],i.[StreetAddress2],i.[City],C.CountyId,i.[StateRegion],i.[ZipCode], getdate()
from [AVData].[dbo].[SourceSite] ss
inner join inserted i on ss.SourceSiteID = i.SourceSiteID
inner join dbo.County C on C.County = i.County
END

2 nvarchar fields are not matching though the data is same?

I want to join 2 tables using an Inner Join on 2 columns, both are of (nvarchar, null) type. The 2 columns have the same data in them, but the join condition is failing. I think it is due to the spaces contained in the column values.
I have tried LTRIM, RTRIM also
My query:
select
T1.Name1, T2.Name2
from
Table1 T1
Inner Join
Table2 on T1.Name1 = T2.Name2
I have also tried like this:
on LTRIM(RTRIM(T1.Name1)) = LTRIM(RTRIM(T2.Name2))
My data:
Table1 Table2
------ ------
Name1(Column) Name2(Column)
----- ------
Employee Data Employee Data
Customer Data Customer Data
When I check My data in 2 tables with
select T1.Name1,len(T1.Name1)as Length1,Datalength(T1.Name1)as DataLenght1 from Table1 T1
select T2.Name2,len(T2.Name2)as Length2,Datalength(T2.Name2)as DataLenght2 from Table2 T2
The result is different Length and DataLength Values for the 2 tables,They are not same for 2 tables.
I can't change the original data in the 2 tables. How can I fix this issue.
Thank You
Joins do not have special rules for equality. The equality operator always works the same way. So if a = b then the join on a = b would work. Therefore, a <> b.
Check the contents of those fields. They will not be the same although you think they are:
select convert(varbinary(max), myCol) from T
Unicode has invisible characters (that only ever seem to cause trouble).
declare #t table (name varchar(20))
insert into #t(name)values ('Employee Data'),('Customer Data')
declare #tt table (name varchar(20))
insert into #tt(name)values ('EmployeeData'),('CustomerData')
select t.name,tt.name from #t t
INNER JOIN #tt tt
ON RTRIM(LTRIM(REPLACE(t.name,' ',''))) = RTRIM(LTRIM(REPLACE(tt.name,' ','')))
I would follow the following schema
Create a new table to store all the possible names
Add needed keys and indexes
Populate with existing names
Add columns to your existing tables to store the index of the name
Create relative foreign keys
Populate the new columns with correct indexes
Create procedure to perform an insert in new tables names only in case the value is not existing
Perform the join using the new indexes

Updating table based on Select query in stored procedure / ColdFusion

I am using ColdFusion for for a project and I have a written a query which I think can be faster using a stored procedure, but I not a T-SQL person, so I am not sure how to do it to compare.
I am running an initial query which selects a number of fields from a table based on a dynamically built cfquery. I think I know how to convert this query into the SQL Server stored procedure.
However, directly after that, I then take all of the primary key IDs from that query and run another query against a separate table that "locks" records with those IDs. The lock is a bit field (a flag) in the second table that tells the system that this record is "checked out". I have wrapped both queries in a cftransaction so that they execute as a unit.
Code Overview:
<cftransaction>
<cfquery name="selectQuery">
SELECT id, field2, field3
FROM table1
WHERE (bunch of conditions here)
</cfquery>
<cfquery name="updateQuery">
UPDATE table2
SET lockField = 1
WHERE table2.id IN (#ValueList(selectQuery.id#)
</cfquery>
</cftransaction>
I then return the selectQuery resultset to my app which uses it for outputting some data. How would I accomplish the same thing in a single SQL Server 2008 stored procedure that I could call using cfstoredproc?
Again, I am thinking that the native CF way (with cfquery) is not as efficient as a stored procedure since I have to retrieve the resultset back to CF, then call another query back to the DB. A single stored procedure does everything in the DB and then returns the original query resultset for use.
Any ideas?
You could add an OUTPUT clause to the UPDATE statement to capture the id's of the records updated and insert them into a table variable/temp table. Then JOIN back to table1 to return the result set.
DECLARE #UpdatedRecords TABLE ( ID INT )
UPDATE t2
SET t2.lockField = 1
OUTPUT Inserted.ID INTO #UpdatedRecords ( ID )
FROM table2 t2 INNER JOIN table1 t1 ON t2.id = t1.id
WHERE (bunch of conditions for table1 here)
SELECT t1.id, t1.field2, t1.field3
FROM table1 t1 INNER JOIN #UpdatedRecords u ON t1.id = u.id
Keep in mind that if table1 is in constant flux, the other values ("field2" and "field3") are not guaranteed to be what they were when the UPDATE occurred. But I think your current method is susceptible to that issue as well.
Your problem is "bunch of conditions here". Are those conditions always static? So is it ALWAYS: (FOO = #x AND BAR = #y)? Or is it conditional where sometimes FOO does not exist at all as a condition?
If FOO is not always present then you have a problem with the stored proc. T-SQL cannot do dynamic query building, in fact even allowing it would kind of negate the point of the proc, which is to compile and pre-optimize the SQL. You CAN do it of course, but you end up just having to build a SQL string inside the proc body and then executing it at the end. You're much better off using CFQuery with cfqueryparams. Actually have you considered doing this instead?
<cfquery name="updateQuery">
UPDATE table2
SET lockField = 1
WHERE table2.id IN (SELECT id
FROM table1
WHERE (bunch of conditions here))
</cfquery>
You could do your update in one query by making your first query a subquery and then using a separate statement to return your results. The whole thing could be a single stored procedure:
CREATE PROCEDURE myUpdate
#Variable [datatype], etc...
AS
BEGIN
UPDATE table2
SET lockField = 1
WHERE table2.id IN (
SELECT id
FROM table1
WHERE (bunch of conditions here)
)
SELECT id, field2, field3
FROM table1
WHERE (bunch of conditions here)
END
You'll probably have to pass some parameters in, but that's the basic structure of a stored procedure. Then you can call it from ColdFusion like so:
<cfstoredproc procedure="myUpdate">
<cfprocparam type="[CF SQL Type]" value="[CF Variable]">
etc...
<cfprocresult name="selectQuery" resultSet="1">
</cfstoredproc>
You could use those query results just like you were using them before.
No need for a SPROC.
UPDATE table2
SET table2.lockField = 1
FROM table1
WHERE table1.id = table2.id
AND table1.field2 = <cfqueryparam ....>
AND table1.field3 = <cfqueryparam ....>

Resources