MS SQL trigger remove all before - sql-server

Need some help...
I have a column whereby the data is shown as -
USEREMAIL:-USERNAME
e.g.
John.smith#test.com:-JSmit
janet.smit#test.co.uk:-JanSmit
peter.parker#test.ca:-PPark
I need a trigger that will automatically remove everything apart from the username when a new entry is added.
So the above examples would just become
JSmit
JanSmit
PPark
Any suggestions would be greatly appreciated.

Here is the syntax to create the described trigger:
Test table:
CREATE TABLE xx(UserName varchar(100))
You will have to expand the trigger to contain all columns.
Trigger syntax:
CREATE TRIGGER xx_trggr
ON xx
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO xx (UserName)
SELECT stuff(UserName, 1, charindex(':-', UserName) + 1, '')
FROM inserted
END
GO
Inserting data:
INSERT xx(UserName)
values
('John.smith#test.com:-JSmit'),
('janet.smit#test.co.uk:-JanSmit'),
('peter.parker#test.ca:-PPark')
Testing input:
SELECT UserName FROM xx
Result:
UserName
JSmit
JanSmit
PPark
You could make an AFTER trigger instead, but that would require a unique key
Using this table instead:
CREATE TABLE xx(id int identity(1,1), UserName varchar(100))
And this trigger:
CREATE TRIGGER xx_trggr
ON xx
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
UPDATE xx
SET [UserName] = stuff(xx.UserName, 1, charindex(':-', xx.UserName) + 1, '')
FROM inserted JOIN xx On inserted.id = xx.id
END
Same result as the other trigger.

You need to create a AFTER INSERT trigger on your table and in your trigger body use something like below to strip down the email part
select right('John.smith#test.com:-JSmit',(LEN('John.smith#test.com:-JSmit') - CHARINDEX('-','John.smith#test.com:-JSmit')))

This will give you username from column
SET columnName= select SUBSTRING( columnName, CHARINDEX('-',columnName)+1 , LEN(columnName))
Use it in trigger
EDIT 1: (If you are worried your email can contain -)
SET columnName= select SUBSTRING( columnName, CHARINDEX(':-',columnName)+2 , LEN(columnName))

Related

Can I do a bulk insert into a table from Microsoft SQL Server Management Studio with a copy and paste list?

I often get a list of names I need to update in a table from an Excel list, and I end up creating a SSIS program to reads the file into a staging table and doing it that way. But is there I way I could just copy and past the names into a table from Management Studio directly? Something like this:
create table #temp (personID int, userName varchar(15))
Insert
Into #temp (userName)
values (
'kmcenti1',
'ladams5',
'madams3',
'haguir1',
)
Obviously this doesn't work but I've tried different variations and nothing seems to work.
Here's an option with less string manipulation. Just paste your values between the single quotes
Declare #List varchar(max) = '
kmcenti1
ladams5
madams3
haguir1
'
Insert into #Temp (userName)
Select username=value
From string_split(replace(#List,char(10),''),char(13))
Where Value <>''
For Multiple Columns
Source:
-- This is a copy/paste from Excel --
-- This includes Headers which is optional --
-- There is a TAB between cells --
Declare #List nvarchar(max) = '
Name Age email
kmcenti1 25 kmcenti1#gmail.com
ladams5 32 ladams5#gmail.com
madams3 18 madams3#gmail.com
haguir1 36 haguir1#gmail.com
'
Select Pos1 = JSON_VALUE(JS,'$[0]')
,Pos2 = JSON_VALUE(JS,'$[1]') -- could try_convert(int)
,Pos3 = JSON_VALUE(JS,'$[2]')
From string_split(replace(replace(#List,char(10),''),char(9),'||'),char(13)) A
Cross Apply (values ('["'+replace(string_escape(Value,'json'),'||','","')+'"]') ) B(JS)
Where Value <>''
and nullif(JSON_VALUE(JS,'$[0]'),'')<>'Name'
Results
Is this along the lines you're looking for?
create table #temp (personID int identity(1,1), userName varchar(15))
insert into #temp (userName)
select n from (values
('kmcenti1'),
('ladams5'),
('madams3'),
('haguir1'))x(n);
This assumes you want the ID generated for you since it's not in your data.
That SQL statement you have won't work (That's one row). But I have a work around. Build what you need with a formula in Excel.
Assuming user IDs are in column A:
In Cell B2, insert this formula:
="('"&A1&"'),"
And then drag the formula down you list.
Go to SSMS and type in:
insert into [your table](userName) values
And then paste in column B from Excel and delete the last comma.

SELECT INTO breaks DDL/DML trigger but CREATE TABLE followed by INSERT works?

In SQL Server 2017 (SSMS v18.3) I'm using a DDL trigger to create output tables for given input tables.
I then create a DML trigger on the input tables to populate the output tables.
This works as intended when using CREATE TABLE followed by INSERT INTO
When using SELECT INTO the query throws this error:
Msg 539, Level 16, State 78, Line 50
Schema changed after the target table was created. Rerun the Select Into query.
and while the input, output, and trigger gets created, none of the data is inserted.
I've tried CATCH RETRY on every part of the query but I can't pin it down.
How can I overcome this error while still using SELECT INTO to create tables in the [input] schema?
And what schema are SELECT INTO tables created in?
Here's a DB fiddle demonstrating this issue
Here's another DB Fiddle that demonstrates the same issue contained in one schema with different table names.
And here's my code:
USE TestData
GO
/*--
CREATE SCHEMA input
GO
CREATE SCHEMA output
GO
--*/
;IF EXISTS ( SELECT * FROM sys.triggers WHERE name = 'CreateDMLTriggerOnTable') DROP TRIGGER CreateDMLTriggerOnTable ON DATABASE;
GO
CREATE TRIGGER CreateDMLTriggerOnTable ON DATABASE
AFTER CREATE_TABLE
AS
declare #schemaname as varchar(128) = 'input'
--Only act on tables in our target scheme [input]
;IF EVENTDATA().value('(/EVENT_INSTANCE/SchemaName)[1]','varchar(128)') <> #schemaname RETURN;
declare #tablename as varchar(128) = EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]','nvarchar(max)')
declare #tb_input as varchar(261) = '[input].[' + #tablename + ']'
declare #tb_output as varchar(261) = '[output].[' + #tablename + ']'
--Create a matching [output] table for the newly created [input] table
declare #tmpsql as nvarchar(max)
set #tmpsql = 'CREATE TABLE ' + #tb_output + ' ( CountOfRows tinyint ) '
print isnull(#tmpsql,'NULLED!')
EXEC(#tmpsql)
--Populate [output] with data from [input] table using DML trigger
set #tmpsql = ''
set #tmpsql = #tmpsql + ';CREATE TRIGGER InsertState_' + #tablename + ' ON ' + #tb_input + ' FOR INSERT AS '
set #tmpsql = #tmpsql + ';INSERT INTO ' + #tb_output + ' SELECT count(*) CountOfRows FROM inserted'
print isnull(#tmpsql,'NULLED!')
EXEC(#tmpsql)
GO
;IF OBJECT_ID('input.firsttest','U') is not null DROP TABLE [input].[firsttest]
;IF OBJECT_ID('output.firsttest','U') is not null DROP TABLE [output].[firsttest]
;IF OBJECT_ID('input.secondtest','U') is not null DROP TABLE [input].[secondtest]
;IF OBJECT_ID('output.secondtest','U') is not null DROP TABLE [output].[secondtest]
--As long as the table is created before any inserts the trigger is also created and both tables are populated
;CREATE TABLE input.firsttest ( AnyColumn tinyint)
INSERT INTO input.firsttest VALUES (10),(20),(30)
SELECT 'input1' tb , * FROM [input].[firsttest]
UNION ALL
SELECT 'output1' tb , * FROM [output].[firsttest]
GO
--This is where things go wrong. Trying to create a trigger on a table that is in the process of being created by a SELECT INTO statement throws error 539
SELECT * INTO [input].[secondtest] FROM [input].[firsttest]
GO
--No data goes into either of the tables. However,
SELECT 'input2a' tb, * FROM [input].[secondtest]
UNION ALL
SELECT 'output2a' tb, * FROM [output].[secondtest]
GO
--This works and shows that the trigger is created on the table.
INSERT INTO [input].[secondtest] SELECT * FROM [input].[firsttest]
GO
--The table is populated as it should be by the SELECT INTO statement
SELECT 'input2b' tb, * FROM [input].[secondtest]
UNION ALL
SELECT 'output2b' tb, * FROM [output].[secondtest]
As you are using, select * INTO [input].[secondtest] the below statement creates the permanent table on fly with the same schema and properties as of [input].[firsttest]. If the table already exists and you perform INTO [input].[secondtest] then sql server throws the mentioned error so if you want multiple inserts to take place in the trigger so go with plain insert logic
INSERT INTO [input].[secondtest](AnyColumn) SELECT AnyColumn FROM [input].[firsttest]
Instead of
SELECT * INTO [input].[secondtest] FROM [input].[firsttest]

How to create a SQL trigger to update a date field on one table when another table is updated

I want to create a trigger in my database which should run when table 'Valve' is updated.
As part of the trigger following must happen:
ME table should be created or updated as per the Schema of Valve table [PnPID, Position X/Y/Z, LineNumberTag, Tag, Spec.]
All information from existing table Valve, to be copied/updated into the table ME
The changes, should happen automatically in the table ME as per the source Valve without the need for any manual intervention.
Please help me create such a Trigger? I am new in SQL.
On my table ME.Valve I want to add other columns with new information that I do not want to appear in the Valve table (do not corrupt it). I attach a picture with existing table Valve.
So, what I want is to copy from tabel "Valve_PNP" in my tabel SQL_P3D_Test_ME for example only column "LineNumberTag" , "Tag", but when value from tabel "Valve_PNP" column "LineNumberTag" , "Tag" are changing, to change and into my tabel SQL_P3D_Test_ME automatically.
And in my tabel SQL_P3D_Test_ME add new column for exampe Made By in witch I insert information manualy in row in front of each valve.
It is possible?
This is what I want, in table "dbo.Source Tabel" you have one row in that you have information in columns "TextColumn", "ValueColumn" etc. For start this information will be copied in table [me].[Destination Table], but when information into tabel"dbo.Source Tabel" for example in column "TextColumn" change from "test insert and update with no data change" with "Marius", to update in tabel [me].[Destination Table] only this information and not add new row. And so on for each column.
I use Microsoft SQL Server Management Studio
I suggest adding the trigger to the "Valve" table that contains the update to the "ME.Valve" table. Let me know if I should write a sample of the syntax.
Here's an example of my solution..
USE [SpecifyYourDatabaseHere]
CREATE TABLE dbo.SourceTable
(
SourcePrimaryKeyID INT IDENTITY PRIMARY KEY,
TextColumn VARCHAR(2048),
ValueColumn DECIMAL(18,3),
NumberColumn INT
)
CREATE TABLE [me].[DestinationTable]
(
DestinationPrimaryKeyID INT IDENTITY PRIMARY KEY,
SourcePrimaryKeyID INT,
TextColumn VARCHAR(2048),
ValueColumn DECIMAL(18,3),
NumberColumn INT,
ActionType VARCHAR(100),
CreatedDate AS GETDATE(), -- Default to current date
CreatedDatabaseUser AS SUSER_SNAME()
)
GO
-- You will need an insert, update and delete trigger.
-- INSERT TRIGGER
-- This trigger will insert any new records into the destination table.
CREATE TRIGGER [dbo].[SourceTable_Insert]
ON [dbo].[SourceTable]
FOR INSERT
AS
INSERT INTO [me].[DestinationTable]
(
SourcePrimaryKeyID,
TextColumn,
ValueColumn,
NumberColumn,
ActionType
)
SELECT INSERTED.SourcePrimaryKeyID,
INSERTED.TextColumn,
INSERTED.ValueColumn,
INSERTED.NumberColumn,
'Insert' AS ActionType
FROM INSERTED
GO
-- UPDATE TRIGGER
-- Conditional Update Trigger : This trigger will only insert data in destination of any of the values in the data columns has changed (Saves space).
CREATE TRIGGER [dbo].[SourceTable_Update]
ON [dbo].[SourceTable]
FOR UPDATE
AS
INSERT INTO [me].[DestinationTable]
(
SourcePrimaryKeyID,
TextColumn,
ValueColumn,
NumberColumn,
ActionType
)
SELECT INSERTED.SourcePrimaryKeyID,
INSERTED.TextColumn,
INSERTED.ValueColumn,
INSERTED.NumberColumn,
'Update' AS ActionType
FROM INSERTED
INNER JOIN
(
SELECT SourcePrimaryKeyID,TextColumn,ValueColumn,NumberColumn
FROM [me].[DestinationTable]
INNER JOIN
(
SELECT MAX(DestinationPrimaryKeyID) MaxDestinationPrimaryKeyID,
COUNT(1) DestinationRecordCount
FROM [me].[DestinationTable]
INNER JOIN
INSERTED ON
[me].[DestinationTable].SourcePrimaryKeyID = INSERTED.SourcePrimaryKeyID
GROUP BY
[me].[DestinationTable].SourcePrimaryKeyID
) MaxDestinationPrimaryKey ON
MaxDestinationPrimaryKey.MaxDestinationPrimaryKeyID = [me].[DestinationTable].DestinationPrimaryKeyID
) DestinationData ON
DestinationData.SourcePrimaryKeyID = INSERTED.SourcePrimaryKeyID
AND (
ISNULL(DestinationData.TextColumn,'') != ISNULL(INSERTED.TextColumn,'') OR
ISNULL(DestinationData.ValueColumn,0) != ISNULL(INSERTED.ValueColumn,0) OR
ISNULL(DestinationData.NumberColumn,0) != ISNULL(INSERTED.NumberColumn,0)
)
GO
-- DELETE TRIGGER
-- This trigger will insert any deleted records into the destination table.
CREATE TRIGGER [dbo].[SourceTable_Delete]
ON [dbo].[SourceTable]
FOR DELETE
AS
INSERT INTO [me].[DestinationTable]
(
SourcePrimaryKeyID,
TextColumn,
ValueColumn,
NumberColumn,
ActionType
)
SELECT INSERTED.SourcePrimaryKeyID,
INSERTED.TextColumn,
INSERTED.ValueColumn,
INSERTED.NumberColumn,
'Delete' AS ActionType
FROM INSERTED
GO
-- Test the code..
-- Insert trigger
INSERT [dbo].[SourceTable]
SELECT 'test insert and update with no data change',
123.456,
1
INSERT [dbo].[SourceTable]
SELECT 'test insert and update with data changed',
123.456,
1
INSERT [dbo].[SourceTable]
SELECT 'test delete',
123.456,
1
-- Update trigger test 1 - no data changed (Must not add record in destination)
UPDATE [dbo].[SourceTable]
SET NumberColumn = 1
WHERE SourcePrimaryKeyID = 1
-- Update trigger test 2 - Data changed (Must add record in destination)
UPDATE [dbo].[SourceTable]
SET NumberColumn = NumberColumn + 1
WHERE SourcePrimaryKeyID = 2
-- Deleted trigger test
DELETE FROM [dbo].[SourceTable]
WHERE SourcePrimaryKeyID = 3
SELECT *
FROM dbo.SourceTable
SELECT *
FROM me.DestinationTable
ORDER BY
SourcePrimaryKeyID,
DestinationPrimaryKeyID

How to INSERT INTO table column with string/variable

This is the data I have pulled from powershell and inserted it into a #temptable:
Name : SULESRKMA
Location : Leisure Services - Technology Services
Shared : False
ShareName :
JobCountSinceLastReset : 0
PrinterState : 131072
Status : Degraded
Network : False
I'm while looping through the data and have stripped the values from the identifiers. I'd like to use these identifiers to insert the values into a table with identical Column names to the identifiers. So for example, I have a variable called #identifier = "Name" and a temp table #printers with a column name of Name. I'd like to do something like:
SELECT --select statement
INSERT INTO #printers(#identifier)
But This doesn't seem to work, unsurprisingly. Is there a way to accomplish this? (The #identifier variable will be changing to the other identifiers in the data throughout the course of the while loop.)
Any alternate suggestions that don't even involve using this sort of method are welcome. My ultimate goal is just to get this data as a row into a table.
(I'm currently using Microsoft SQL Server Management Studio if that matters)
First, it's unlikely you need to loop over anything in this situation. Think set based operations when you think about SQL.
INSERT INTO #temptable (Column1Name, Column2Name, Column3Name)
VALUES (#identifer, #anotherIdentifier, #someOtherIdentifier)
--optional clauses
WHERE Column1Name = 'some value' OR Column1Name = #someIdentifier
Or you can SELECT INTO
SELECT
#identifier,
#anotherIdentifer,
#someOtherIdentifier
INTO #temptable
It's important that you have a value in your SELECT INTO for each column in the table which you are trying to add the data to. So, for example, if there were 4 columns in #temptable and you only had 3 values to insert (columns 1, 2 , and 3) then you'd need to NULL column 4 or set it statically.
SELECT
#identifier,
#anotherIdentifer,
#someOtherIdentifier,
NULL
INTO #temptable
--or
SELECT
#identifier,
#anotherIdentifer,
#someOtherIdentifier,
'static value'
INTO #temptable
EDIT
If you want to use a varible to speciy the column that you want to insert into, you have to use dynamic sql. Here is an example:
if object_id ('tempdb..#tempTable') is not null drop table #tempTable
create table #tempTable (Column1Name int, Column2Name int, Column3Name int)
declare #columnName varchar(64) = 'Column1Name'
declare #sql varchar(max)
set #sql =
'insert into #tempTable (' + #columnName + ')
select 1'
exec(#sql)
select * from #tempTable

Will an FOR INSERT trigger fire after an INSTEAD OF INSERT trigger has performed an insert?

The title pretty much says it all... I have a table with an INSTEAD OF INSERT trigger which checks certain things and does the actual insert if things are OK. It also has an FOR INSERT, UPDATE trigger which updates values in other tables based on the values in the newly inserted row.
I suspect that the FOR INSERT, UPDATE trigger is not firing. Why would this be?
which updates values in other tables
based on the values in the newly
inserted row.
The "inserted" table in the FOR INSERT trigger will contain the values inserted by your INSTEAD OF trigger, NOT your insert statement. For example, consider the following script:
CREATE TABLE Test (
id int IDENTITY NOT NULL,
value varchar(20) NOT NULL,
forTriggerValue char(1) NULL
)
GO
CREATE TRIGGER forTrigger
ON Test
AFTER UPDATE
AS
IF EXISTS (SELECT * FROM inserted WHERE value = 'MyNewValue')
BEGIN
UPDATE Test SET
forTriggerValue = 'A'
FROM inserted
WHERE Test.id IN (SELECT id FROM inserted)
END
ELSE IF EXISTS (SELECT * FROM inserted WHERE value = 'InsteadOfValue')
BEGIN
UPDATE Test SET
forTriggerValue = 'B'
FROM inserted
WHERE Test.id IN (SELECT id FROM inserted)
END
ELSE
BEGIN
UPDATE Test SET
forTriggerValue = 'C'
FROM inserted
WHERE Test.id IN (SELECT id FROM inserted)
END
GO
CREATE TRIGGER insteadOfTrigger
ON Test
INSTEAD OF UPDATE
AS
UPDATE Test SET
value = 'InsteadOfValue'
FROM inserted
WHERE Test.id IN (SELECT id FROM inserted)
GO
INSERT INTO Test (value) VALUES ('MyValue')
GO
UPDATE Test SET value = 'MyNewValue' WHERE value = 'MyValue'
GO
SELECT * FROM Test
GO
Your "forTriggerValue" will be 'B', not 'A'.
Check the "Allow Triggers to Fire Others" setting on the server. In SSMS, right click on the Server and choose Properties. Then look at the Advanced tab.

Resources