I have a SQL Server database in which I store millions of records. Now, I have to delete a big number of records continuously, so what I do is running thousands of queries like this within the same execution:
delete TWEET
from TWEET
where REQUEST_ID >= x and TWEET_ID = y and ID < z
The single query is immediate, but putting them all together is extremely slow.
What would you suggest to me?
You can use this. You can delete 100000 rows every turn. This works faster than delete all rows in the same time.
DECLARE #RC INT = 1
WHILE #RC > 0
BEGIN
delete TOP(100000)
from TWEET
where REQUEST_ID >= x and TWEET_ID = y and ID < z
SET #RC = ##ROWCOUNT
END
Using a JOINed table is probably your best bet (see below). Another option is to use Service Broker: you send a delete request into SB and some asynchronous process deletes it when is has the CPU to do so.
------------------------------------------------------------------------
-- Create a table to hold the delete requests:
CREATE TABLE DeleteTweets (
ID INT IDENTITY(1,1) PRIMARY KEY
, REQUEST_ID INT
, TWEET_ID INT
)
GO
------------------------------------------------------------------------
-- Create an index to keep the deletions fast:
CREATE INDEX IX_DeleteTweets ON dbo.DeleteTweets (REQUEST_ID, TWEET_ID)
GO
------------------------------------------------------------------------
-- However you can put your delete requests into that table. This might
-- be part of you front-end application or via some batch process:
INSERT INTO dbo.DeleteTweets
( REQUEST_ID, TWEET_ID )
VALUES ( 0, /*REQUEST_ID*/, 0 /*TWEET_ID*/)
, ( 0, /*REQUEST_ID*/, 0 /*TWEET_ID*/)
, ( 0, /*REQUEST_ID*/, 0 /*TWEET_ID*/)
, ( 0, /*REQUEST_ID*/, 0 /*TWEET_ID*/)
, ( 0, /*REQUEST_ID*/, 0 /*TWEET_ID*/)
GO
------------------------------------------------------------------------
-- Delete from the main table via JOIN:
DELETE t
FROM TWEET t
INNER JOIN dbo.DeleteTweets dt
ON t.REQUEST_ID = dt.REQUEST_ID
AND t.TWEET_ID = dt.TWEET_ID
GO
------------------------------------------------------------------------
-- Once they're done, empty the table so you can re-fill with new deletion requests:
TRUNCATE TABLE dbo.DeleteTweets
GO
--IN QUERY WINDOW 1
DROP TABLE TWEETDEL
GO
DROP TABLE TWEET
GO
CREATE TABLE TWEET
(ID int NOT NULL
,REQUEST_ID AS ID*2
,TWEET_ID AS ID*10
)
GO
INSERT TWEET WITH (TABLOCKX) (ID )
SELECT TOP 20000000 id
FROM
(SELECT ROW_NUMBER() OVER (ORDER BY a.id) AS id
FROM sys.sysobjects AS a, sys.syscolumns AS b, sys.syscolumns AS c) x
GO
ALTER TABLE TWEET ADD PRIMARY KEY (ID)
GO
SELECT IDENTITY(INT,1,1) AS TWEETDELPK, *
INTO TWEETDEL
FROM TWEET
WHERE REQUEST_ID%14=0
GO
ALTER TABLE TWEETDEL ADD PRIMARY KEY (TWEETDELPK)
GO
ALTER TABLE TWEETDEL
ADD CONSTRAINT fk101
FOREIGN KEY (ID) REFERENCES TWEET(ID) ON DELETE CASCADE
GO
-- IN THE SAME WINDOW
SET NOCOUNT OFF
DECLARE #ID INT
CR:
DELETE TOP (SELECT CNT FROM ##) t WITH (PAGLOCK)
FROM TWEET AS t
WHERE EXISTS
(SELECT 1 FROM TWEET AS x WHERE T.ID = X.ID)
IF ##ROWCOUNT >0 GOTO CR
-- IN ANOTHER WINDOW
CREATE TABLE ## (CNT INT)
INSERT ## SELECT 1000
select COUNT(1) from tweetdel
select COUNT(1) from tweet
CHECK FOR LOCKING - IF LOCKS ARE STAYING OPEN TOO LONG, RAISE OR LOWER CHUNKSIZE ACCORDINGLY
UPDATE ## SET CNT =5000
SELECT resource_type, resource_associated_entity_id,
request_status, request_mode,request_session_id,
resource_description
FROM sys.dm_tran_locks
WHERE resource_database_id = DB_ID()
AND request_mode in ('x')
Related
I am facing a problem when I query master table (having ~700 Million records and high transactional table) to look for newly inserted records. My aim is to get all the newly created IDs from the #IDs temp table (Min and Max records) and dump it in another child table. But random IDs are missing in the child table.
Setup:
We have a primary and secondary server (SQL Server 2016) and they are in sync mode.
Tables:
CREATE TABLE tblMaster
(
ID BIGINT IDENTITY(1,1) NOT NULL,
EmployeeID INT NOT NULL
)
CREATE TABLE tblChild
(
ChildID IDENTITY(1,1),
ID BIGINT NOT NULL,
TransactionDate Datetime NOT NULL
)
tblChild.ID references tblMaster.ID.
Stored procedure:
DECLARE #MaxID BIGINT
SELECT #MaxID = MAX(ID) FROM tblChild WITH(NOLOCK)
SET #MaxID = ISNULL(#MaxID, 0)
DROP TABLE IF EXISTS #IDS
SELECT ID
INTO #IDS
FROM tblMaster WITH(NOLOCK)
WHERE ID > #MaxID
--25k RECORDS BATCH INSERT INTO tblChild - MAINLY TAKE CARE NEWLY inserted records
STARTIDS:
IF EXISTS (SELECT TOP 1 * FROM #IDS)
BEGIN
DROP TABLE IF EXISTS #TOPIDS
SELECT TOP 25000 ID INTO #TOPIDS
FROM #IDS
ORDER BY ID ASC
INSERT INTO tblChild (ID, CreatedBy, CreatedDate)
SELECT ID, SYSTEM_USER, GETDATE()
FROM #TOPIDS
DELETE AA
FROM #IDS AA
INNER JOIN #TOPIDS BB ON AA.ID = BB.ID
GOTO STARTIDS
END
Please help where it's going wrong.
We have a few tables with an IsPrimary column, e.g. many members belonging to an account. The requirement is if an account has one or more members, one and only one of them must have IsPrimary = 1. We want to achieve this using triggers for both maximum assurance of data integrity and ease of use from applications. But due to the batch nature of triggers, I'm struggling to accomplish it and in the most efficient way.
So far I have an insert/delete trigger (see below) that handles inserting a new primary record or deleting the primary record. Where I got stuck is ensuring the first record inserted has IsPrimary=1 and then realizing there could be multiple modifications to the same account in the batch...
Does anyone have any experience or and example with something like this?
ALTER TRIGGER dbo.trg_PrimaryTest_InsertDelete
ON dbo.PrimaryTest
AFTER INSERT,DELETE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
--SET NOCOUNT ON;
PRINT 'executing trigger'
--If inserting a primary, set all others to 0
UPDATE PrimaryTest
SET IsPrimary = 0
FROM inserted
INNER JOIN PrimaryTest ON inserted.fk_ID = PrimaryTest.fk_ID
WHERE inserted.IsPrimary = 1
AND PrimaryTest.pk_ID <> inserted.pk_ID
AND PrimaryTest.IsPrimary = 1
--If deleting the primary, set most recent remaining phone to 1
UPDATE PrimaryTest
SET IsPrimary = 1
WHERE PrimaryTest.pk_ID IN (
SELECT TOP 1 PrimaryTest.pk_ID
FROM deleted
INNER JOIN PrimaryTest ON deleted.fk_ID = PrimaryTest.fk_ID
WHERE deleted.IsPrimary = 1
ORDER BY PrimaryTest.CreatedDate DESC
)
PRINT 'trigger executed'
END
GO
Table ddl:
CREATE TABLE [dbo].[PrimaryTest](
[pk_ID] [uniqueidentifier] NOT NULL,
[Value] [nvarchar](50) NULL,
[CreatedDate] [datetime2](7) NOT NULL,
[IsPrimary] [bit] NOT NULL,
[fk_ID] [int] NOT NULL,
CONSTRAINT [PK_PrimaryTest] PRIMARY KEY CLUSTERED
(
[pk_ID] ASC
)
GO
EDIT:
I think this might work or is at least headed in the right direction. I think it may be reading more records than it needs to in the 2nd C.T.E. case though. (Note I added update)
ALTER TRIGGER dbo.trg_PrimaryTest_InsertDelete
ON dbo.PrimaryTest
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
--SET NOCOUNT ON;
PRINT 'executing trigger'
--If setting a new primary, set all others to 0
UPDATE PrimaryTest
SET IsPrimary = 0
FROM inserted
INNER JOIN PrimaryTest ON inserted.fk_ID = PrimaryTest.fk_ID
WHERE inserted.IsPrimary = 1
AND PrimaryTest.pk_ID <> inserted.pk_ID
AND PrimaryTest.IsPrimary = 1
--Set IsPrimary on any modified sets left without an primary
;WITH cte
AS
(
SELECT *, ROW_NUMBER() OVER(PARTITION BY fk_ID ORDER BY CreatedDate DESC) as RowNum
FROM PrimaryTest p1
WHERE fk_ID IN (SELECT FK_ID FROM inserted UNION SELECT FK_ID FROM deleted) --Only look at modified sets
AND NOT EXISTS (SELECT NULL FROM PrimaryTest p2 WHERE p2.fk_ID = p1.fk_ID AND p2.IsPrimary = 1) --Select rows in a set without an IsPrimary=1 record
)
UPDATE cte
SET IsPrimary = 1
WHERE RowNum = 1
PRINT 'trigger executed'
END
GO
I am looking to create a SQL Server trigger that moves a record from one table to an identical replica table if the record matches a specific condition.
Questions: do I need to specify each column, or can I use a wildcard?
Can I use something like:
SET #RecID = (SELECT [RecoID] FROM Inserted)
IF NULLIF(#RecID, '') IS NOT NULL
(then insert....)
THANKS!
There's a lot of stuff you "CAN" do in a trigger, but that doesn't mean you should. I'd would urge to to avoid setting scalar variables within a trigger at all costs. Even if you 100% sure your table will never have more that 1 row inserted per transaction because that's how the app is designed... You'll be in for very rude awakening when you find out that not all transactions come through the application.
Below is a quick demonstration of both types of triggers...
USE tempdb;
GO
IF OBJECT_ID('tempdb.dbo.PrimaryTable', 'U') IS NOT NULL
DROP TABLE dbo.PrimaryTable;
GO
IF OBJECT_ID('tempdb.dbo.TriggerScalarLog', 'U') IS NOT NULL
DROP TABLE dbo.TriggerScalarLog;
GO
IF OBJECT_ID('tempdb.dbo.TriggerMultiRowLog', 'U') IS NOT NULL
DROP TABLE dbo.TriggerMultiRowLog;
GO
CREATE TABLE dbo.PrimaryTable (
Pt_ID INT NOT NULL IDENTITY (1,1) PRIMARY KEY CLUSTERED,
Col_1 INT NULL,
Col_2 DATE NOT NULL
CONSTRAINT df_Col2 DEFAULT (GETDATE())
);
GO
CREATE TABLE dbo.TriggerScalarLog (
Pt_ID INT,
Col1_Old INT,
Col1_New INT,
Col2_Old DATE,
Col2_New DATE
);
GO
CREATE TABLE dbo.TriggerMultiRowLog (
Pt_ID INT,
Col1_Old INT,
Col1_New INT,
Col2_Old DATE,
Col2_New DATE
);
GO
--=======================================================
CREATE TRIGGER dbo.PrimaryCrudScalar ON dbo.PrimaryTable
AFTER INSERT, UPDATE, DELETE
AS
SET NOCOUNT ON;
DECLARE
#Pt_ID INT,
#Col1_Old INT,
#Col1_New INT,
#Col2_Old DATE,
#Col2_New DATE;
SELECT
#Pt_ID = ISNULL(i.Pt_ID, d.Pt_ID),
#Col1_Old = d.Col_1,
#Col1_New = i.Col_1,
#Col2_Old = d.Col_2,
#Col2_New = i.Col_2
FROM
Inserted i
FULL JOIN Deleted d
ON i.Pt_ID = d.Pt_ID;
INSERT dbo.TriggerScalarLog (Pt_ID, Col1_Old, Col1_New, Col2_Old, Col2_New)
VALUES (#Pt_ID, #Col1_Old, #Col1_New, #Col2_Old, #Col2_New);
GO -- DROP TRIGGER dbo.PrimaryCrudScalar;
CREATE TRIGGER PrimaryCrudMultiRow ON dbo.PrimaryTable
AFTER INSERT, UPDATE, DELETE
AS
SET NOCOUNT ON;
INSERT dbo.TriggerMultiRowLog (Pt_ID, Col1_Old, Col1_New, Col2_Old, Col2_New)
SELECT
ISNULL(i.Pt_ID, d.Pt_ID),
d.Col_1,
i.Col_1,
d.Col_2,
i.Col_2
FROM
Inserted i
FULL JOIN Deleted d
ON i.Pt_ID = d.Pt_ID;
GO -- DROP TRIGGER dbo.TriggerMultiRowLog;
--=======================================================
--=======================================================
-- --insert test...
INSERT dbo.PrimaryTable (Col_1)
SELECT TOP 100
o.object_id
FROM
sys.objects o;
SELECT 'INSERT Scarar results';
SELECT * FROM dbo.TriggerScalarLog tsl;
SELECT 'INSERT Multi-Row results';
SELECT * FROM dbo.TriggerMultiRowLog tmrl;
UPDATE pt SET
pt.Col_1 = pt.Col_1 + rv.RandomVal,
pt.Col_2 = DATEADD(DAY, rv.RandomVal, pt.Col_2)
FROM
dbo.PrimaryTable pt
CROSS APPLY ( VALUES (ABS(CHECKSUM(NEWID())) % 10000 + 1) ) rv (RandomVal);
SELECT 'UPDATE Scarar results';
SELECT * FROM dbo.TriggerScalarLog tsl;
SELECT 'UPDATE Multi-Row results';
SELECT * FROM dbo.TriggerMultiRowLog tmrl;
DELETE pt
FROM
dbo.PrimaryTable pt;
SELECT 'DELETE Scarar results';
SELECT * FROM dbo.TriggerScalarLog tsl;
SELECT 'DELETE Multi-Row results';
SELECT * FROM dbo.TriggerMultiRowLog tmrl;
You could, but I'd recommend against it. If your source table changed things would start failing.
Also, in your example if you were to ever have more than one row inserted at a time you would get thrown an error (or have unpredictable results). I'd recommend a more set based approach:
INSERT table2 ( user_id ,
user_name ,
RecoID
)
SELECT user_id ,
user_name ,
RecoID
FROM inserted i
LEFT JOIN table2 t ON i.RecoID = t.RecoID
WHERE t.RecoID IS NULL;
EDIT:
If you want to stop the insert happening on your original table then you'll need to do something along the lines of:
CREATE TRIGGER trigger_name
ON table_orig
INSTEAD OF INSERT
AS
BEGIN
-- make sure we aren't triggering from ourselves from another trigger
IF TRIGGER_NESTLEVEL() <= 1
return;
-- insert into the table_copy if the inserted row is already in table_orig (not null)
INSERT table_copy ( user_id ,
user_name ,
RecoID
)
SELECT user_id ,
user_name ,
RecoID
FROM inserted i
LEFT JOIN table_orig c ON i.RecoID = c.RecoID
WHERE t.RecoID IS NOT NULL;
-- insert into table_orig if the inserted row is not already in table_orig (null)
INSERT table_orig ( user_id ,
user_name ,
RecoID
)
SELECT user_id ,
user_name ,
RecoID
FROM inserted i
LEFT JOIN table_orig c ON i.RecoID = c.RecoID
WHERE t.RecoID IS NULL;
END;
The instead of will stop the insert if you don't want it to actually be inserted, so you'll need to do that yourself (the second insert statement).
Please note I changed some nulls to not nulls and the table we are left joining to in some cases.
I Have the following scenario:
CREATE TABLE dbo.Orders
(
OrderID int IDENTITY (1,1) NOT NULL
, OrderVersion int DEFAULT(1)
, Customer varchar(30)
, ScheduleDate date
, PaymentOption int
);
CREATE TABLE dbo.OrdersItems
(
OrderItemsID int IDENTITY (1,1) NOT NULL
, OrderID int
, Product varchar(100)
, Qty int
, value decimal(18,2)
);
CREATE TABLE dbo.logOrders
(
OrderID int NOT NULL
, OrderVersion int DEFAULT(1)
, Customer varchar(30)
, ScheduleDate date
, PaymentOption int
);
CREATE TABLE dbo.logOrdersItems
(
OrderItemsID int NOT NULL
, OrderID int
, Product varchar(100)
, Qty int
, value decimal(18,2)
);
-- Insert values into the table.
INSERT INTO dbo.Orders (Customer , ScheduleDate, PaymentOption)
VALUES ('John', 2016-09-01, 1);
INSERT INTO dbo.OrdersItems( OrderId, Product, Qty, Value)
VALUES (1, 'Foo', 20, 35.658),
(1, 'Bla', 50, 100)
(1, 'XYZ', 10, 3589)
First Statement
UPDATE Orders set ScheduleDate = 2016-10-05 WHERE OrderId = 1
Second Statement
Delete From OrdersItems WHERE OrderItemsID = 2
UPDATE OrdersItems set Qty = 5 WHERE OrderItemsID = 1
Third Statement
Update Orders set PaymentOption = 2 WHERE OrderId = 1
Update OrdersItems set Value = 1050 WHERE OrderItemsID = 3
I am trying to figure out how to make a trigger that after each one of the Statements Sample above Insert on the log Tables the data before the changing. And setting the OrderVersion to OrderVersion + 1 on table Orders.
So on the log Tables I will have all versions after the later one.
Is it possible to make a single trigger to monitor both tables and execute getting the original data before the UPDATE, DELETE , INSERT statement to get the original data and INSERT on the logTables ?
Here comes a sample to explain better what result I want.
This is the Initial Data on table Orders and OrdersItems
If I make an Update on Orders ( any column ) or Make an Update,Insert,Delete on OrdersItems I need to Insert on respectively logTables the data on the image.
And with this I'll have on logOrders and logItems the original data and on the Orders and Items the altered data.
I Hope I could explain better what I mean.
You will need two triggers. The trigger for the Orders table handles Orders table update/delete. The trigger for the OrdersItems table does the same for OrdersItems. The triggers look like this:
For the Orders table:
CREATE TRIGGER dbo.Orders_trigger
ON dbo.Orders
AFTER DELETE,UPDATE
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO dbo.logOrders
SELECT * FROM DELETED;
INSERT INTO dbo.logOrdersItems
SELECT oi.* FROM OrdersItems oi
WHERE oi.OrderID IN (SELECT OrderId FROM DELETED);
END
GO
For OrdersItems:
CREATE TRIGGER dbo.OrdersItems_trigger
ON dbo.OrdersItems
AFTER DELETE,UPDATE
AS
BEGIN
SET NOCOUNT ON;
--Inerst the changed/deleted OrdersItems into the log
INSERT INTO dbo.logOrdersItems
SELECT * FROM DELETED
--Inserts the unchanged sibling OrdersItems records into the log
INSERT INTO dbo.logOrdersItems
SELECT oi.* FROM OrdersItems oi
WHERE oi.OrderId IN (SELECT DISTINCT OrderId FROM DELETED)
AND oi.OrderItemsID NOT IN (SELECT DISTINCT OrderItemsID FROM DELETED);
INSERT INTO dbo.logOrders
SELECT o.* FROM Orders o
WHERE o.OrderID IN (SELECT DISTINCT OrderId FROM DELETED);
END
GO
The Orders Trigger is fairly straightforward. Use the virtual DELETED table to insert the original version of the records into the log. Then join to the child OrdersItems records and insert them into the log as well. The way this is written, it will work even if you update or delete multiple Order records at a time.
The OrdersItems Trigger is a bit more complicated. You need to log the pre-chage version of the OrdersItems and Orders Records. But you also want (I think) to log the unchanged "sibling" OrdersItems records as well so that you have a complete picture of the records.
I know this is just your sample data, but you will want to add some kind of a timestamp to the records in the log tables. Otherwise you just end up with a bunch of duplicate rows and you cannot tell which is which. At the beginning of the trigger you can create a variable to hold the update datetime and then append that to your INSERT statement for the logs.
DECLARE #UpdateDateTime DATETIME;
SET #UpdateDateTime = GETUTCDATE();
I am using SQL Server 2008 R2 on a windows 7 machine. I have a trigger that should be fired on an insert but unfortunately it does not. I do not have the SQL Profiler because I have an express edition. Is there any other way to see what is going wrong?. The insert into the table teams is done with the Import Wizard of SQL Server, an i import from .CSV into a table.
CREATE TRIGGER teams.process ON teams
AFTER INSERT
AS
BEGIN
DECLARE #homeTeamId INT
DECLARE #awayTeamId INT
DECLARE #maxTeamId INT
DECLARE #matchId INT
SELECT #maxTeamId = 0
SELECT #maxTeamId = ISNULL(MAX(teamId), 0) from tblTeams
--- Check if home team has already been inserted into the table.
SELECT #homeTeamId = -1
SELECT
#homeTeamId = teamId
FROM
tblTeams t
JOIN inserted i
ON t.teamName = i.hometeam
IF (#homeTeamId = -1)
BEGIN
SELECT #homeTeamId = #maxTeamId + 1
SELECT #maxTeamId = #maxTeamId + 1
INSERT INTO tblTeams SELECT #homeTeamId, i.hometeam FROM inserted i
END
--- Check if away team has already been inserted into the table.
SELECT #awayTeamId = -1
SELECT
#awayTeamId = teamId
FROM
tblTeams t
JOIN inserted i
ON t.teamName = i.awayteam
IF (#awayTeamId = -1)
BEGIN
SELECT #awayTeamId = #maxTeamId + 1
SELECT #maxTeamId = #maxTeamId + 1
INSERT INTO tblTeams SELECT #awayTeamId, i.awayteam FROM inserted i
END
-- insert a record into the matches table with the home team ID and away team ID.
SELECT #matchId = 0
SELECT #matchId = ISNULL(MAX(MatchId), 0) FROM tblMatches
INSERT INTO tblMatches
SELECT #matchId + 1, #homeTeamId, #awayTeamId, i.score
FROM inserted i
END
Okay. If we can change the table definitions of tblTeams and tblMatches slightly, so that they maintain their own ID columns using IDENTITY, then we can fix the trigger to be safe for multi-row inserts:
create table teams (
hometeam varchar(10) not null,
awayteam varchar(10) not null,
score int not null
)
create table tblteams (
teamId int IDENTITY(1,1) not null,
teamName varchar(10) not null
)
create table tblmatches (
matchId int IDENTITY(1,1) not null,
HomeTeamID int not null,
AwayTeamID int not null,
Score int not null
)
go
CREATE TRIGGER process ON teams
AFTER INSERT
AS
SET NOCOUNT ON
declare #TeamIDs table (TeamID int not null,TeamName varchar(10) not null)
;with AllTeams as (
select hometeam as teamName from inserted
union
select awayteam from inserted
)
merge into tblTeams tt using AllTeams at on tt.teamName = at.teamName
when matched then update set teamName = at.teamName
when not matched then insert (teamName) values (at.teamName)
output inserted.TeamID,inserted.teamName into #TeamIDs;
insert into tblmatches (HomeTeamID,AwayTeamID,Score)
select ht.TeamID,at.TeamID,i.Score
from inserted i
inner join #TeamIDs ht on i.hometeam = ht.TeamName
inner join #TeamIDs at on i.awayteam = at.TeamName
GO
And then we test it out:
insert into teams (hometeam,awayteam,score) values
('abc','def',10),
('def','ghi',5),
('jkl','mno',7)
go
insert into teams (hometeam,awayteam,score) values
('abc','ghi',19),
('pqr','stu',11)
go
select * from tblteams
select * from tblmatches
The issue with your existing trigger is it didn't cope with inserted containing multiple rows - the trigger is fired once per statement, not once per row. So e.g. these line are wrong:
SELECT #homeTeamId = #maxTeamId + 1
SELECT #maxTeamId = #maxTeamId + 1
INSERT INTO tblTeams SELECT #homeTeamId, i.hometeam FROM inserted i
Since there might be multiple homeTeam values to deal with.
It also didn't deal well with concurrency - two calls to the trigger happening in parallel might end up with the same #maxTeamId value - and then attempt to insert rows into tblTeam with the same TeamId values - whereas using IDENTITY columns, SQL Server deals with this for us automatically.
The only slight fudge in the above is using MERGE to insert new teams - the WHEN MATCHED line will do a No-Op UPDATE for existing rows (since we know the teamName matches on both sides), but it's a nice trick to do the lookup of existing rows and INSERT of new rows in a single statement.
I've just realised that you've said that you're using the Import data wizard. I have a feeling that the SSIS Package that it generates creates a destination using Fast Load, and doesn't specify FIRE_TRIGGERS. That could scupper you also.
You could either generate the package using the wizard, then edit the properties, or use the wizard to insert into a staging table, then do a plain INSERT/SELECT from that table into our teams table, and let the trigger fire that way.
Bulk insert wizards / data import wizards usually bypass triggers on the destination table.