Creating a temporary table within a TRIGGER with GROUP BY - sql-server

I need to create and use a temporary table with GROUP BY clause within a trigger, but I'm having difficulties doing so.
My attempt:
Here I'm trying to use two temporary tables which are dropped after the trigger reach an end.
First I create a #Temptable and the trigger.
CREATE TABLE #TempTable (admID smallint, diagID smallint);
CREATE TRIGGER tr_newTest
ON Adm_Diag
FOR INSERT
AS
BEGIN
...
END
Since the table inserted only contains rows for a current INSERT and UPDATE statements I'm passing several INSERT and UPDATE statements to #TempTable.
DECLARE #admID smallint
SELECT #admID = Adm_ID
FROM inserted
DECLARE #diagID smallint
SELECT #diagID=Diag_ID
FROM inserted
INSERT INTO #TempTable VALUES (#admID, #diagID)
Now with this data I want to create a temporary table that groups the rows of #TempTable:
SELECT *
INTO #TempGroupTable
FROM
(
SELECT admID, COUNT(*) as Diag
FROM #TempTable
GROUP BY admID
) t1
WHERE Diag > 2
The whole script
CREATE TABLE #TempTable (admID smallint, diagID smallint);
CREATE TRIGGER tr_newTest
ON Adm_Diag
FOR INSERT
AS
BEGIN
DECLARE #admID smallint
SELECT #admID = Adm_ID
FROM inserted
DECLARE #diagID smallint
SELECT #diagID=Diag_ID
FROM inserted
INSERT INTO #TempTable VALUES (#admID, #diagID)
-- Below I'm tring to create #TempGroupTable
SELECT *
INTO #TempGroupTable
FROM
(
SELECT admID, COUNT(*) as Diag
FROM #TempTable
GROUP BY admID
) t1
WHERE Diag > 2
END
After executing the trigger I get an error:
Msg 208, Level 16, State 0, Line 41 Invalid object name
'#TempGroupTable'.
How can I create #TempGroupTable?

Not quote sure what you are trying to do but would a global temporary tables which starts with ## work for you? So make the #TempGroupTable into ##TempGroupTable?

Why not dispense with all the overhead of temp tables and variables? Try:
CREATE TRIGGER tr_newTest
ON Adm_Diag
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO Adm_Diag (adminID, Diag)
SELECT admID, COUNT(*) as Diag
FROM inserted
GROUP BY admID
END

Related

Trigger to insert multiple record

I'm trying to create a trigger to insert all the value that I delete from a table in a "Backup" table,
Ex:
Table 1: NomePilota, ModelloVettura, NomeScuderia
BackupTable1 (Table 2): NomePilota, ModelloVettura, NomeScuderia
What I want from the trigger to do: Insert into 'Table 2' deleted values from table 1.
I tried like this:
CREATE TRIGGER Backup ON dbo.Table1 AFTER (i can only use after) DELETE AS
BEGIN
DECLARE #Pilota VARCHAR(20) = (SELECT NomePilota FROM deleted)
DECLARE #Vettura VARCHAR(50) = (SELECT ModelloVettura FROM deleted)
DECLARE #Scuderia VARCHAR(20) = (SELECT NomeScuderia FROM deleted)
INSERT INTO Table2 (NomePilota, ModelloVettura, NomeScuderia) VALUES (#Pilota, #Vettura, #Scuderia)
But it send a error:
Cannot insert multiple records in #Pilota, #Vet, #Scud
How can I fix that? Does the deleted table already have a default ID column to use like in a for? Can I use something like vectors? (like #Nome[] = SELECT * FROM Tabella, Insert into Tabella2 (Nome) VALUES #Nome[#Numero (numero is like the record number of nome]).
Why not make life simple?
INSERT INTO Table2 (NomePilota, ModelloVettura, NomeScuderia)
SELECT NomePilota, ModelloVettura, NomeScuderia FROM deleted
The insert statment can work on the results of a select -- here we leverage this to simplify the task at hand.

Adding constraints to list items in SQL Server database

I have table holding items for a given list id in my Ms Sql server database (2008R2).
I would like to add constraints so that no two list ids have same item list. Below illustrate my schema.
ListID , ItemID
1 a
1 b
2 a
3 a
3 b
In above example ListID 3 should fail. I guess you can't put constarint/check within the database itself (Triggers,check) and the logic constaint can only be done from the frontend?
Thanks in advance for any help.
Create a function that performs the logic you want and then create a check constraint or index that leverages that function.
Here is a functional example, the final insert fails. The function is evaluated row by row, so if you need to insert as a set and evaluate after, you'd need to do an "instead of" trigger:
CREATE TABLE dbo.Test(ListID INT, ItemID CHAR(1))
GO
CREATE FUNCTION dbo.TestConstraintPassed(#ListID INT, #ItemID CHAR(1))
RETURNS TINYINT
AS
BEGIN
DECLARE #retVal TINYINT = 0;
DECLARE #data TABLE (ListID INT, ItemID CHAR(1),[Match] INT)
INSERT INTO #data(ListID,ItemID,[Match]) SELECT ListID,ItemID,-1 AS [Match] FROM dbo.Test
UPDATE #data
SET [Match]=1
WHERE ItemID IN (SELECT ItemID FROM #data WHERE ListID=#ListID)
DECLARE #MatchCount INT
SELECT #MatchCount=SUM([Match]) FROM #data WHERE ListID=#ListID
IF NOT EXISTS(
SELECT *
FROM (
SELECT ListID,SUM([Match]) AS [MatchCount]
FROM #data
WHERE ListID<>#ListID
GROUP BY ListID
) dat
WHERE #MatchCount=[MatchCount]
)
BEGIN
SET #retVal=1;
END
RETURN #retVal;
END
GO
ALTER TABLE dbo.Test
ADD CONSTRAINT chkTest
CHECK (dbo.TestConstraintPassed(ListID, ItemID) = 1);
GO
INSERT INTO dbo.Test(ListID,ItemID) SELECT 1,'a'
INSERT INTO dbo.Test(ListID,ItemID) SELECT 1,'b'
INSERT INTO dbo.Test(ListID,ItemID) SELECT 2,'a'
INSERT INTO dbo.Test(ListID,ItemID) SELECT 2,'b'
Related

Count # of Rows in Stored Procedure Result, then Insert result into table

I have an SSIS package which will first run my sp_doSomething. This stored procedure will select data from several different tables and join them for possible storage into dbo.someTable. But I only want that IF the select is > 1 row of selected data.
I want to then have a precedence restraint that looks at the amount of rows my stored procedure returned.
If my row count > 1, then I want to take the results of the stored procedure and insert them into one of my tables.
Otherwise, I will record an error/send an email, or whatever.
I really don't want to run this stored procedure more then once, but that is the only way I could think to do it (Run it, count the rows. Then, run it again and insert the result).
I'm a complete TSQL/SSIS newb. So I'm sorry if this question is trivial.
I can't find a good answer anywhere.
Create a variable with Package Scope of type Int32 and name rowcount.
Data Flow
Control Flow
you can try this
declare #tableVar table(col1 varchar(100))
declare #Counter int
insert into #tableVar(col1) exec CompanyNames
set #Counter = (select count(*) from #tableVar)
insert into Anytable(col) Values (#counter)
Within the Stored Proc, write the results to a #Temp. Then Select Count(*) from the #Temp, into a variable.
Select #intRows = Count(*) from myTempResults
Then evaluate the value of #intRows.
If #intRows > 1 BEGIN
Insert Into dbo.SomeTable
Select * from #Temp
End
Will a #temp table work for you?
IF OBJECT_ID('tempdb..#Holder') IS NOT NULL
begin
drop table #Holder
end
CREATE TABLE #Holder
(ID INT )
declare #MyRowCount int
declare #MyTotalCount int = 0
/* simulate your insert, you would read from your real table(s) here */
INSERT INTO #HOLDER (ID)
select 1 union all select 2 union all select 3 union all select 4
Select #MyRowCount = ##ROWCOUNT, #MyTotalCount = #MyTotalCount + #MyRowCount
Select 'TheMagicValue1' = #MyRowCount, 'TheMagicTotal' = #MyTotalCount
INSERT INTO #HOLDER (ID)
select 5 union all select 6 union all select 7 union all select 8
/* you will note that I am NOT doing a count(*) here... which is another strain on the procedure */
Select #MyRowCount = ##ROWCOUNT, #MyTotalCount = #MyTotalCount + #MyRowCount
Select 'TheMagicValue1' = #MyRowCount, 'TheMagicTotal' = #MyTotalCount
/* Optional index if needed */
CREATE INDEX IDX_TempHolder_ID ON #Holder (ID)
/* CREATE CLUSTERED INDEX IDX_TempHolder_ID ON #Holder (ID) */
if #MyTotalCount > 0
BEGIN
Select 'Put your INSERT statement here'
END
/* this will return the data to the report */
Select ID from #HOLDER
IF OBJECT_ID('tempdb..#Holder') IS NOT NULL
begin
drop table #Holder
end

Trying to create a trigger for a table

I have a table [dbo].[main] composed of 4 columns:
MovieGenre
MusicGenre
PodcastGenre
CombinedColumn
I want to create a trigger where if anything is inserted in MovieGenre, PodcastGenre, MusicGenre that it also gets inserted into CombinedColumn.
CREATE TRIGGER trgAfterInsert ON [dbo].[Main]
FOR INSERT
AS
???
GO
--dbo.main` needs a key column (let's say its a identity column 'id1')
CREATE TRIGGER trgAfterInsert
ON [dbo].[Main]
FOR INSERT AS
declare #allcols varchar(500)
declare #key1 int
set #key1 = ident_current('dbo.main')
select #allcols = MovieGenre+' '+ PodcastGenre+' '+ MusicGenre from inserted
update dbo.main set CombindedColumn= #allcols where id1 = #key1
Okay, this will add values to Combined Column one after another. "Stacking" them as you want:
CREATE TRIGGER trgAfterInsert on dbo.main
AFTER INSERT
AS
INSERT INTO yourTable(CombinedColumn)
SELECT MovieGenre
FROM inserted
UNION ALL
SELECT PodcastGenre
FROM inserted
UNION ALL
SELECT MusicGenre
FROM inserted
GO

Merge statement on a single record table

I need to write a single statement to insert or update a record in a single record table
the merge statement allows me to write this:
create table t1 (n int)
-- insert into t1 (n) Values (1); -- uncomment to test the matched branch
MERGE t1 AS P
USING (SELECT 3 AS n) AS S
ON 1 = 1
WHEN MATCHED THEN
UPDATE SET n = S.n
WHEN NOT MATCHED THEN
INSERT (n)
VALUES (S.n);
select * from t1
this work, but I think that the 1=1 condition purpose is not very easy to understand.
Is there a different syntax to insert a record when the table is empty or update the record when it does already exist?
The other option would be to do it the old fashioned way.
if exists (select null from t1)
update t1 set n = 3
else
insert into t1 (n) values (3)
Replace
ON 1 = 1
with
ON S.n = P.n
Example of recent procedure I wrote to either update an existing row or insert a new row.
Table has the same structure as MembershipEmailFormat the table variable.
Found it easiest to create a table variable to be the source in the Using clause. I realize that the main purpose of Merge statements really are merging muliple rows between two tables. My use case is that I need to insert a new email address for a user or modify and existing email address.
CREATE PROCEDURE [dbo].[usp_user_merge_emailformat]
#UserID UNIQUEIDENTIFIER,
#Email varchar(256),
#UseHTML bit
AS
BEGIN
--SELECT #UserID='04EFF187-AEAC-408E-9FA8-284B31890FBD',
-- #Email='person#xxxx.com',
-- #UseHTML=0
DECLARE #temp TABLE
(
UserID UNIQUEIDENTIFIER,
Email varchar(256),
HtmlFormat bit
)
INSERT INTO #temp(UserID,Email, HtmlFormat)
Values(#UserID,#Email,#UseHTML)
SELECT * FROM #temp
MERGE dbo.MembershipEmailFormat as t
USING #temp AS s
ON (t.UserID = s.UserID and t.Email = s.Email)
WHEN MATCHED THEN UPDATE SET t.HtmlFormat = s.HtmlFormat
WHEN NOT MATCHED THEN INSERT VALUES(s.UserID,s.Email,s.HtmlFormat);
END

Resources