Optimize update and insert query - sql-server

I have this code:
string query = #"UPDATE [dbo].[TrippingTariffTransaction]
SET [IsActive] = 0
WHERE Id in (SELECT Id
FROM [dbo].[TrippingTariffTransaction]
WHERE Trip = #Trip
AND TrippingTariffId = #TrippingTariffId);";
query += #"INSERT INTO [dbo].[TrippingTariffTransactionAuditTrail]
(LogDatetime, MasterlistId, ComputerName, TrippingTariffTransactionID, Activity)
SELECT
GETDATE(), #MasterlistId, #ComputerName, Id, #Activity
FROM
[dbo].[TrippingTariffTransaction]
WHERE
Trip = #Trip AND TrippingTariffId = #TrippingTariffId";
How can I optimize this code. I have redundant select. Thanks in advance :)

You can make use of the OUTPUT clause
update t
set IsActive = 0
OUTPUT getdate(), #MasterlistId, #ComputerName, INSERTED.Id, #Activity
INTO TrippingTariffTransactionAuditTrail
( LogDatetime, MasterlistId, ComputerName, TrippingTariffTransactionID, Activity)
FROM TrippingTariffTransaction t
WHERE t.Trip = #Trip
AND t.TrippingTariffId = #TrippingTariffId

You can use temp table:
SELECT Id INTO #T
FROM [dbo].[TrippingTariffTransaction]
WHERE Trip = #Trip
AND TrippingTariffId = #TrippingTariffId
UPDATE [dbo].[TrippingTariffTransaction]
SET [IsActive] = 0
WHERE Id in (SELECT Id FROM #T)
INSERT INTO [dbo].[TrippingTariffTransactionAuditTrail]
(LogDatetime, MasterlistId, ComputerName, TrippingTariffTransactionID, Activity)
SELECT
GETDATE(), #MasterlistId, #ComputerName, Id, #Activity
FROM #T
DROP TABLE #T

Related

Column name or number of supplied values does not match table definition in a stored procedure

I'm trying to execute this stored procedure, the query throws an error:
Column name or number of supplied value does not match table definition.
What I would like to get from this stored procedure is one line of all columns.
Please help to solve the error.
ALTER PROCEDURE `uspx_MUL_Status`
#OrderNumber VARCHAR(20),
#SelectQty BIT,
#SelectDate DATE,
#oKey INT
AS
BEGIN
CREATE TABLE #TempStatus
(
OrderNum VARCHAR (20),
`QtéCom` SMALLINT,
`DateCom` DATE,
`QtéSelec` SMALLINT,
`DateSelec` DATE,
`QtéProd` SMALLINT,
DateProd DATE
)
INSERT INTO #TempStatus
-- Quantité commandée--
SELECT OrderNumber, SUM(`od.Quantity`), MAX(CreateDate)
FROM OrderDetail `od`
JOIN Orders o ON od.oKey =o.oKey
WHERE OrderNumber = #OrderNumber
GROUP BY CreateDate, OrderNumber
-- Quantité sélectionnée--
SET #SelectQty = 0
SET #SelectDate = NULL
SELECT #SelectQty = SUM(`sd.Quantity`), #SelectDate = MAX(`ReleaseDate`)
FROM ScheduleDetail `sd`
JOIN Orders o ON o.oKey =`sd.oKey`
JOIN Schedules s ON `sd.SchedID` = `s.SchedID` AND o.LocationID = s.LocationID
WHERE o.oKey = #oKey
GROUP BY ReleaseDate
UPDATE #TempStatus
SET `QtéSelec` = #SelectQty, `DateSelec` = #SelectDate
-- Quantité produite--
SET #SelectQty = 0
SET #SelectDate = NULL
SELECT
#SelectQty = SUM(`od.CompleteQuantity`),
#SelectDate = MAX(`o.CompleteDate`)
FROM OrderDetail `od`
JOIN Orders o ON o.oKey = od.oKey
WHERE o.oKey = #oKey
GROUP BY CompleteDate
UPDATE #TempStatus
SET `QtéProd` = #SelectQty, `DateProd` = #SelectDate
SELECT * FROM #TempStatus
END
EXEC `uspx_MUL_Status` #OrderNumber='TC19227', #SelectQty=0, #SelectDate=NULL, #oKey=42334
Specify the columns on this line:
INSERT INTO #TempStatus
Like this:
INSERT INTO #TempStatus (Column1, Column2, Column3, etc)

How to insert rows into a table based on another table's rows using Triggers?

I have three tables:
Employee
Id
FirstName
LastName
EmployeeTasksId
EmployeeTasks
Id
EmployeeId
EmployeeTaskDefinitionId
EmployeeTaskDefinitions
Id
Description
etc.
What I am trying to do is once an Employee is inserted into the Employees table, I need to insert rows into the EmployeeTasks table based on the inserted Employee's Id and every EmployeeTaskDefinition's Id.
For example:
Employee with Id 1 is inserted into Employee table
EmployeeTaskDefinitions table has 6 rows with Ids 1-6
EmployeeTasks table needs to have 6 rows after this insert:
Id = 1, EmployeeId = 1, EmployeeTaskDefinitonId = 1
Id = 2, EmployeeId = 1, EmployeeTaskDefinitonId = 2
Id = 3, EmployeeId = 1, EmployeeTaskDefinitonId = 3
Id = 4, EmployeeId = 1, EmployeeTaskDefinitonId = 4
Id = 5, EmployeeId = 1, EmployeeTaskDefinitonId = 5
Id = 6, EmployeeId = 1, EmployeeTaskDefinitonId = 6
Now I have read numerous posts about cursors, with most people saying that they're a bad practice to use for this task. But how would you do something like this? Note: I don't want to use anything else other than triggers.
EDIT: This is the query I came up with.
CREATE TRIGGER CreateEmployee
ON [dbo].[EmployeeSet]
AFTER INSERT
AS
DECLARE #LoopCounter int, #MaxSettingDefinitionId int, #Id int
SELECT #LoopCounter = MIN(Id), #MaxSettingDefinitionId = MAX(Id)
FROM SettingsDefinitionSet
WHILE(#LoopCounter IS NOT NULL AND #LoopCounter <= #MaxSettingDefinitionId)
BEGIN
SELECT #Id = Id FROM SettingDefinitionSet
WHERE Id = #LoopCounter
INSERT INTO SettingSet(CompanyId, EmployeeId, SettingDefinitionId, SettingType, State, Value)
VALUES((SELECT CompanyId FROM inserted), (SELECT Id FROM inserted),
#Id,
(SELECT SettingType FROM SettingSet WHERE EmployeeId IS NULL AND CompanyId = (SELECT CompanyId FROM inserted) AND SettingDefinitionId = #Id),
(SELECT State FROM SettingSet WHERE EmployeeId IS NULL AND CompanyId = (SELECT CompanyId FROM inserted) AND SettingDefinitionId = #Id),
(SELECT Value FROM SettingSet WHERE EmployeeId IS NULL AND CompanyId = (SELECT CompanyId FROM inserted) AND SettingDefinitionId = #Id))
SELECT #LoopCounter = MIN(Id) FROM SettingDefinitionSet
WHERE Id > #LoopCounter
END
GO
This should do the trick:
INSERT INTO EmployeeTasks(EmployeeId, EmployeeTaskDefinitionId)
SELECT inserted.id as EmployeeId, t.id as EmployeeTaskDefinitionId
FROM inserted JOIN EmployeeTaskDefinitions
As I noted in comments, Employee table is bad normalized and shouldn't have EmployeeTasksId. If you want to add automatically some tasks to a new employee do it like this:
alter table EmployeeTaskDefinitions
add DefaultTask bit not null default 0
--update EmployeeTaskDefinitions set DefaultTask = 1 where...
--now create a trigger
create trigger trEmployee_i
on dbo.Employee after insert
as
begin
set nocount on
insert EmployeeTasks(EmployeeId,EmployeeTaskDefinitionId)
select i.id,td.id
from inserted i cross join EmployeeTaskDefinitions td
where td.DefaultTask = 1
end
P.S.: I hope EmployeeTasks.Id is identity column.

Updating Next_ID column

I have the following table:
VehicleID Reg_ID Next_RegID EntryDate
330034 9111 NULL 2010-12-06 00:00:00
330034 9113 NULL 2010-12-09 00:00:00
On the first row I need to update the Next_RegId column with the Reg_ID of the second row where VehicleId or (VIN/ChassisNumber) is the same. The Next_RegID column on the last entry should remain Null.
I've created a while loop procedure which works perfectly, but with millions of records in the table it takes ages to complete. Therefore, I was wondering if any of you dealt with this kind of a problem and have a solution for it.
Here's the procedure I wrote, and thanks in advance for all your help:
Declare #i as integer;
Declare #x as integer;
Declare #y as integer
Set #i= (Select Max(RID) from TempRegistration)
Set #x= 0
Set #y= 1
Declare #curChassis as nvarchar(100)
Declare #nextChassis as nvarchar(100)
While (#x <= #i)
Begin
set #curChassis = (Select ChassisNumber from TempRegistration where RID = #x)
set #nextChassis = (Select ChassisNumber from TempRegistration where RID = #y)
If (#curChassis = #nextChassis)
Begin
Update Registration set NextRegistrationId = (Select RegistrationId from TempRegistration where RID = #y)
Where RegistrationId = (Select RegistrationId from TempRegistration where RID = #x)
End
Set #x = #x + 1
Set #y = #y + 1
Print(#x)
End
TempRegistration is a temporary table I've created to assign a row_id which guides the while loop to assign the Reg_ID to the Next_RegId on the previous row.
This can be done with one UPDATE query. You haven't mentioned your RDBMS so...
For MSSQL:
Update Registration as t1
set NextRegistrationId = (Select TOP 1 RegistrationId
from Registration
where RID = t1.RID
and EntryDate>t1.EntryDate
order by EntryDate DESC)
For MySQL
Update Registration as t1
set NextRegistrationId = (Select RegistrationId
from Registration
where RID = t1.RID
and EntryDate>t1.EntryDate
order by EntryDate DESC
LIMIT 1)
If RID's are increasing with EntryDate then
Update Registration as t1
set NextRegistrationId = (Select MIN(RegistrationId)
from Registration
where RID = t1.RID
and EntryDate>t1.EntryDate
)
Tested and it seems to be working but this version uses a CTE (SQL Server)
with RegDetails as
(
select VehicleID, Reg_ID, ROW_NUMBER() OVER(PARTITION BY VehicleID ORDER BY EntryDate) AS ROWNUMBER
FROM dbo.Vehicle)
UPDATE a SET a.Next_RegID = b.Reg_ID
FROM RegDetails b
INNER JOIN dbo.Vehicle a ON (a.VehicleID = b.VehicleID)
WHERE b.ROWNUMBER = 2 and a.Next_RegID IS NULL and a.Reg_ID != b.Reg_ID

Is it possible to use MAX in update statement using sql?

i am trying to use the MAX function in sql statement. Here is what i am trying to do:
something like this:
UPDATE MainTable
SET [Date] = GETDATE()
where [ID] = Max
I know this is wrong specially where i put the where condition but cannot figure out how to use max and update in the same statement. thanks
UPDATE MainTable
SET [Date] = GETDATE()
where [ID] = (SELECT MAX([ID]) FROM MainTable)
One way
DECLARE #MaxID INT = (select MAX(id) FROM MainTable)
UPDATE MainTable
SET [Date] = GETDATE()
where [ID] = #MaxID
That is SQL 2008 syntax, in 2005 you need to do the declaraion and assignment of the variable in two steps
You could also use a common table expression
;WITH cte
AS (
SELECT TOP 1 * FROM MainTable
ORDER BY ID DESC
)
UPDATE cte SET [Date] = GETDATE()
Example you can run
CREATE TABLE testNow(id int)
INSERT testNow VALUES(1)
INSERT testNow VALUES(2)
;WITH cte
AS (
SELECT TOP 1 * FROM testNow
ORDER BY ID DESC
)
-- id with 2 will become 5
UPDATE cte SET ID = 5
SELECT * FROM testNow
Output
1
5
UPDATE MainTable
SET [Date] = GETDATE()
WHERE [ID] = (SELECT MAX(your column) FROM yourtable)

T-SQL UPDATE using self join for a table variable

Imagine there is a table:
declare #tab table (id int, val int)
insert into #tab(id, val)
values (1,10),(2,20),(1,15)
there is a need to update the table and set for every id the sum of all values with same ids in the table
update #tab
set val = (select sum(val) from #tab tab where tab.id = id)
The where clause of the last query is always true and therefore the every row would contain the sum of all values in the table.
If the table was real (not table variable) I would reference it using the table name:
update realtab
set val = (select sum(val) from #tab tab where tab.id = realtab.id)
It is possible to make such an update for table variables?
Try using UPDATE ... FROM
update t
set val = (select sum(val) from #tab tab where tab.id = t.id)
FROM #tab t
UPDATE realtab
SET val = (select sum(val) from #tab tab where tab.id = realtab.id)
FROM #tab realtab
You can also use a CTE:
WITH q AS
(
SELECT *,
SUM(val) OVER (PARTITION BY id) AS sum_val
FROM #tab
)
UPDATE q
SET val = sum_val

Resources