Get the table name where data is updated/inserted - sql

Is there any way to get the table name where data is updated/inserted?
UPDATE
a
SET
a.Salary = a.Salary + 5000
FROM
dbo.Employee a
INNER JOIN
dbo.Status b
ON
a.StatusID = b.ID
WHERE
b.Description = 'Regular'
SELECT ##TableUpdated
Ouput should be Employee

It's a hack and can be done only inside a trigger but still you can try this and may help someone to get an idea:
CREATE TRIGGER z ON dbo.Employee
AFTER UPDATE
AS
IF(UPDATE(a))
BEGIN
IF EXISTS(SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Employee'
AND COLUMN_NAME = 'a')
begin
SELECT 'Employee'
end
ELSE // you can add more if statements
begin
SELECT 'Status'
END
end
Once you create trigger, use that update statement you provided in your question, the trigger should return you the name of the table.

You can parse this sql query to get a list of affected table like this:
sstupdate
a(dbo.Employee)(tetUpdate)
StatusID
Salary
Salary
dbo.Employee(tetSelect)
dbo.Status(tetSelect)
ID
Description

Related

Stored procedure to create tables for each employee code using INTO clause

I am trying to create tables which are specific to employee ID.
I can run simple select statement in a stored procedure. But I want to create tables using INTO clause which I can then export into CSV files. When I write INTO clause, I get an error
"Incorrect syntax near 'zz_'". If I hover mouse over 'zz_', I see error as "expecting '.', ID, or Quoted_ID".
I even tried to replace it using a variable called #table_employee (not included in below code). But even that code doesn't work. I do not want to use INSERT INTO way of writing query.
Also is below code an efficient way of writing SQL program?
DECLARE #employeeID INT
DECLARE #deptartment VARCHAR(2)
SET #employeeID = (select MIN(ID) from employee)
SET #deptartment = 'HR'
WHILE #employeeID <= (SELECT MAX(ID) FROM employee)
BEGIN
IF EXISTS
(
select * from companydata
where ID = #employeeID
)
select a.employeeID, b.Name,
SUM(a.RATE * a.Quantity) 'Revenue'
into 'zz_' + Region + '_' + Product + '_' + #employeeID
from
employee a join
companydata b on a.employeeID = b.ID
where a.employeeID = #employeeID and a.departmentname = #deptartment
group by a.employeeID, b.Name, Region, Product
order by a.employeeID, b.Name
ELSE
PRINT CAST(#employeeID as varchar) + ' Does not exist'
SET #employeeID = #employeeID + 1
END
You don't really want a bunch of different tables for this. A single summary table can efficiently hold the data for all employees, eg
select
a.employeeID,
b.Name,
Region,
Product
SUM(a.RATE * a.Quantity) 'Revenue'
into zz_HR_RevenueByEmployeeRegionProduct
from
employee a join
companydata b on a.employeeID = b.ID
where a.departmentname = 'HR'
group by a.employeeID, b.Name, Region, Product

Need Combined SQL Query to Update 2 Tables

I am having 2 tables. Table1 and Table2. I need to update these 2 tables based on some conditions.
The SQL select query from Table1 will return multiple records, let's
name it as SQLQuery1
From SQLQuery1 results returned I need to loop through each record and
execute another SQL query from Table2 which will return only 1
record, let's name it as SQLQuery2
Update Table1 and Table2 with the results returned from SQLQuery2.
Is there is a single query to combine the above operations?
If you need more information please let me know
UPDATE:
Following are the Sample Queries used,
SELECT E.Id,E.Name
from Employee E
where E.transdate > '2019-01-201 00:00:01' -- Multiple Results(SQLQuery1)
SELECT top 1 ED.Id,ED.balance
FROM EmployeeDetails ED
where ED.Name= #Name -- Single Results((SQLQuery2)
UPDATE Employee set IsProcessed=true
where Id=#Id
UPDATE EmployeeDetails set IsProcessed=true
where Id=#Id
I would use an UPDATE with an INNER JOIN. I have no idea if it's best practice at this point in time or whether there is a better way to do this but it works for the example I have created in dbfiddle.
Something like this:
UPDATE E
SET IsProcessed = 1
FROM Employee E
INNER JOIN EmployeeDetails ED ON E.Id = ED.Id
WHERE E.transdate >= '2019-01-20 00:00:01' AND ED.name = 'Martin'
UPDATE ED
SET IsProcessed = 1
FROM EmployeeDetails ED
INNER JOIN Employee E ON E.Id = ED.Id
WHERE E.transdate >= '2019-01-20 00:00:01' AND ED.name = 'Martin'
I used >= because I just set all 3 created records to the datetime you have and forgot that looking for a datetime greater than that would provide me with nothing. I also used a hard-coded name Martin instead of using a variable.
Here is my link to the dbfiddle I created in which I created Employee and EmployeeDetails, filled them with test data and then proceeded to identify the correct records using the date, time and name joined by their ID values:
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=4492b27a9790f34b0bff0996e7fb6d36
Use INNER JOIN :
update e
set e.IsProcessed = 1 -- assuming BIT type
from employee e inner join
EmployeeDetails ed
on ed.name = e.name and ed.id = e.id
where e.transdate > '2019-01-201 00:00:01';
update ed
set ed.IsProcessed = 1 -- assuming BIT type
from EmployeeDetails ed inner join
Employee e
on ed.name = e.name and ed.id = e.id and
where e.transdate > '2019-01-201 00:00:01';
I wouldn't do it like this.
You can use outer apply to get rid of the cursor:
SELECT *
FROM T_Query1
OUTER APPLY
(
SELECT TOP 1 * FROM T_Query2
WHERE T_Query2.query1_id = T_Query1.id
) AS tQuery2
Then you can do an update like this:
UPDATE A
SET some_value = tQuery2.some_new_value
FROM T_Query1 AS A
OUTER APPLY
(
SELECT TOP 1 * FROM T_Query2
WHERE T_Query2.query1_id = A.id
) AS tQuery2
Besides that, you cannot update 2 tables with one update statement, AFAIK.
Your best bet would be
;WITH CTE AS
(
SELECT T_Query1.field1, T_Query2.field2, T_Query2.newField1
FROM T_Query1
OUTER APPLY
(
SELECT TOP 1 * FROM T_Query2
WHERE T_Query2.query1_id = T_Query1.id
) AS tQuery2
)
-- SELECT * FROM CTE
UPDATE CTE SET field1 = newField1, field2 = newField1
but I don't think CTE updating can handle outer-apply.

How to write a Trigger based on row update

I am first time using a trigger, Now I am facing some problems,
I have 3 tables, InvoiceHead, InvoiceDetails, InventoryMaster .
when I update 'Status' field of InvoiceHead (from 0 to 1), 'Status' fields of InvoiceDetails and InventoryMaster need to be changed based on the updated row.
Reltionships :
InvoiceHead_id=InvoiceDetails_id (FK) and
InventoryMaster_Processid=InvoiceHead_id (FK)
How can write a trigger in InvoiceHead ?
Please help to solve this..
Try this
create trigger your_trigger
on InvoiceHead
after update
as
//declare #status int;
//select #status=i.status from inserted i;
//IF #status == 1
//BEGIN
update d
set d.status = b.status
from InvoiceDetails as d
join inserted as b
on a.InvoiceDetails_id = b.InvoiceHead_id
where b.status == 1;
update m
set m.status = b.status
from InventoryMaster as m
join inserted as b
on m.InventoryMaster_Processid = b.InvoiceHead_id
where b.status == 1;
end
go
But keep in mind that in SQL trigger works on entire update not like rowwise in oracle. so if this trigger will fire for more than one row at a time my code won't work for your requirement..You need to fine tune it..

Return 'something' instead of null

I have this code:
select f.name
from Firms F
where
f.id = #{_firmID}
Code select name of firm by inserted ID. But if I insert bad ID (nonexisting ID), table return null. I need to rewrite this code to return 'wrong ID' if id not exist for example.
How can I achieve this? Thanks for all reply
Untested syntax, but you get the idea, I hope:
select f.name
from Firms F
where
f.id = #{_firmID}
union
select 'wrong ID' as name
from firms
where #{_firmID}
not in (select id from firms)
If you really want to do it with SQL rather than in application side, then using selectable stored procedure is perhaps easiest way:
CREATE PROCEDURE GetFirmName(aID INTEGER)
RETURNS(Name VARCHAR(255))
AS
BEGIN
Name = NULL;
SELECT Name FROM Firms WHERE id = :aID INTO :Name;
IF(Name IS NULL)THEN Name = 'wrong ID';
END
and then
SELECT Name FROM GetFirmName(42);

DB2 set default when null on join / Open table after FETCH

This is kind of a double question, just thinking of ways to accomplish my problem.
Also, I'm pretty new to DB2 and stored procedures, so bear with me.
I'm creating a stored procedure that gets a value from two tables using a Left Join statement. This will result in some of the values in the second table returning a null value (since they don't exist in tableB).
DECLARE CURSOR C1 WITH RETURN FOR
select a.name, a.title, b.order from tableA a
left outer join tableB b on a.name = b.name;
Now, I need some way to set these null values to a default value of 0.
The program I'm working with can do it ( CAST-IRON ) but if the result set is too large, it slows down the orchestrations and truncates the job log. So I'm trying to figure it out using the stored procedure.
My first thought was to use the FETCH INTO statement and a WHILE loop.
WHILE AT_END = 0 DO
FETCH C1 INTO CHNAME, CHTITLE, CHORDER;
IF CHORDER IS NULL
THEN SET CHORDER = 0;
END IF;
IF SQLCODE = 100
THEN SET AT_END = 1;
END IF;
END WHILE;
But it seems like that would require a temporary table being created, and declaring another cursor with that table, using an insert command after the 'FETCH INTO'. So I was wondering if there were another way to do this, or to automatically set a default in the select statement?
Set a default in the select statement using COALESCE.
DECLARE CURSOR C1 WITH RETURN FOR
select a.name, a.title, COALESCE(b.order,0) as order
from tableA a
left outer join tableB b on a.name = b.name;