Couldn't drop and recreate the table if exist on SQL Server - sql-server

Expecting to drop and re-create if the table is exist. Actual is instead of dropping the table, inserting data again on to the table.
BEGIN
PRINT N'Seeding [Proj].[UserTable]...';
SET NOCOUNT ON
--
-- BEGIN SEED DATA SECTION
--
IF OBJECT_ID('#tempdb..#SeedData') IS NOT NULL DROP TABLE #SeedData
SET NOCOUNT ON
CREATE TABLE #SeedData (
[UserName] nvarchar(50) NULL,
[CreatedById] [bigint] NULL,
[CreatedDate] [datetimeoffset](7) NULL
)
INSERT INTO #SeedData SELECT N'UserA',-1,getdate()
...
--
-- END SEED DATA SECTION
--
SET NOCOUNT OFF
INSERT INTO [Proj].[UserTable] (
[UserName],
[CreatedById],
[CreatedDate]
)
SELECT seed.[UserName]
,seed.[CreatedById]
,seed.[CreatedDate]
FROM #SeedData seed
DROP TABLE #SeedData
SET NOCOUNT OFF
END
GO
Tried codes:
- IF OBJECT_ID('#SeedData', 'U') IS NOT NULL DROP TABLE #SeedData
- IF OBJECT_ID('tempdb..#SeedData', 'U') IS NOT NULL DROP TABLE #SeedData

use
IF OBJECT_ID('tempdb..#SeedData') is not null
drop table #seeddata
I am not able to repro the issue,even passing the table parameter..
Test :
create table #test
(
id int
)
select * from tempdb.sys.objects--you can see table
if object_id('tempdb..#test','u') is not null
drop table #test
select * from tempdb.sys.objects--you can't see table

Remove the hash in front of '#temp db..'
BEGIN
PRINT N'Seeding [Proj].[UserTable]...';
SET NOCOUNT ON
--
-- BEGIN SEED DATA SECTION
--
IF OBJECT_ID('tempdb..#SeedData') IS NOT NULL DROP TABLE #SeedData
SET NOCOUNT ON
CREATE TABLE #SeedData (
[UserName] nvarchar(50) NULL,
[CreatedById] [bigint] NULL,
[CreatedDate] [datetimeoffset](7) NULL
)
INSERT INTO #SeedData SELECT N'UserA',-1,getdate()
...
--
-- END SEED DATA SECTION
--
SET NOCOUNT OFF
INSERT INTO [Proj].[UserTable] (
[UserName],
[CreatedById],
[CreatedDate]
)
SELECT seed.[UserName]
,seed.[CreatedById]
,seed.[CreatedDate]
FROM #SeedData seed
DROP TABLE #SeedData
SET NOCOUNT OFF
END
GO

Try this instead for the drop table statement, replacing [Database].[Schema].[TableName] for the object you're trying to drop.
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[Database].[Schema].[TableName]') AND type in (N'U'))
DROP TABLE [Database].[Schema].[TableName]
GO

Related

MSSQL Trigger Update on column

I have 2 tables and I want table 1 to have a trigger that insert or update in table 2, but I'm not sure how to do that.
Table 1:
CREATE TABLE [dbo].[DevicePorts](
[ID] [int] IDENTITY(1,1) NOT NULL,
[IsInUse] [bit] NOT NULL,
)
Table 2:
CREATE TABLE [dbo].[DevicePortActivities](
[ID] [uniqueidentifier] NOT NULL,
[StartTime] [datetimeoffset](7) NOT NULL,
[EndTime] [datetimeoffset](7) NULL,
[FK_DevicePortID] [int] NOT NULL FOREIGN KEY REFERENCES DevicePorts(ID),
)
Start of my trigger:
CREATE TRIGGER PortInUse
ON DevicePorts
AFTER UPDATE
AS BEGIN
SET NOCOUNT ON;
IF UPDATE (IsInUse)
BEGIN
IF IsInUse = 1
THEN
INSERT INTO [dbo].[DevicePortActivities]
(
[ID]
,[StartTime]
,[EndTime]
,[FK_DevicePortID]
)
VALUES
(
NEWID(),
SYSDATETIMEOFFSET(),
null,
<DevicePortID>
)
ELSE
UPDATE [dbo].[DevicePortActivities]
SET EndTime = SYSDATETIMEOFFSET()
WHERE FK_DevicePortID = <DevicePortID> AND EndTime is null
END
END
END
GO
What I'm trying to do is when 'IsInUse' is modified it should insert a row into 'DevicePortActivities' or update.
Conditions are, if 'IsInUse' is true then it should insert a record, if it's false it should update the last record where 'EndTime' is null.
You need to treat inserted as a table. I'd suggest looking at MERGE for this (because different rows may have had different changes applied by a single UPDATE).
Something like:
CREATE TRIGGER PortInUse
ON DevicePorts
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
MERGE INTO [dbo].[DevicePortActivities] t
USING (select i.ID,i.IsInUse as NewUse,d.IsInUse as OldUse
from inserted i inner join deleted d on i.ID = d.ID) s
ON
t.FK_DevicePortID = s.ID
WHEN MATCHED AND t.EndTime is null AND NewUse = 0 and OldUse = 1
THEN UPDATE SET EndTime = SYSDATETIMEOFFSET()
WHEN NOT MATCHED AND NewUse = 1 and OldUse = 0
THEN INSERT ([ID]
,[StartTime]
,[EndTime]
,[FK_DevicePortID])
VALUES (NEWID(),
SYSDATETIMEOFFSET(),
null,
s.ID);
END
I found a solution for my question
CREATE TRIGGER [dbo].[PortInUse]
ON [dbo].[DevicePorts]
AFTER UPDATE
AS BEGIN
SET NOCOUNT ON;
IF UPDATE (IsInUse)
BEGIN
DECLARE #IsInUse bit;
DECLARE #PortID int;
SELECT #IsInUse = i.IsInUse FROM inserted i;
SELECT #PortID = i.ID FROM inserted i;
IF (#IsInUse = 1)
INSERT INTO [dbo].[DevicePortActivities]
(
[ID]
,[StartTime]
,[EndTime]
,[FK_DevicePortID]
)
VALUES
(
NEWID(),
SYSDATETIMEOFFSET(),
null,
#PortID
);
ELSE
UPDATE [dbo].[DevicePortActivities]
SET EndTime = SYSDATETIMEOFFSET()
WHERE FK_DevicePortID = #PortID AND EndTime is null;
END
END
I'm not sure if there is a better way to do this, but it's working.

How do I populate a table that contains only an identity column?

Consider the following table
CREATE TABLE [dbo].[Numbers]
(
[Id] [INT] IDENTITY(1,1) NOT NULL
) ON [PRIMARY]
How do I populate it?
If I add a column (text nchar(20) say) then I can populate it with:
insert into numbers (text) values ('')
but if there are no other columns besides the identity, what do I do?
insert into numbers ( ) values ( )
This throws an error
Incorrect syntax near ')'.
I want to use this for a find the missing sequence number problem.
Specify DEFAULT VALUES:
INSERT INTO dbo.Numbers DEFAULT VALUES;
Or even you can use SET IDENTITY_INSERT:
SET IDENTITY_INSERT YourTable ON;
GO
INSERT INTO YourTable (IdentityColumn) VALUES
(1),
(2),
(3);
GO
SET IDENTITY_INSERT YourTable OFF;
Sample:
CREATE TABLE [dbo].[Numbers](
[Id] [int] IDENTITY(1,1) NOT NULL
) ON [PRIMARY];
DECLARE #Start INT=1;
DECLARE #End INT=100;
SET IDENTITY_INSERT [dbo].[Numbers] ON;
WITH Gen AS (
SELECT #Start AS Num
UNION ALL
SELECT Num + 1 FROM Gen WHERE Num + 1 <= #End
)
INSERT INTO [dbo].[Numbers] (Id)
SELECT Num
FROM Gen
OPTION (maxrecursion 100);
SET IDENTITY_INSERT [dbo].[Numbers] OFF;
SELECT *
FROM [dbo].[Numbers];

Statement contains an OUTPUT clause without INTO clause error using trigger in SQL Server 2012?

I have a trigger for auditing record insert,update and delete. My code is
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[mytable_insertafter_audit]
ON [dbo].[mytable]
AFTER INSERT, DELETE, UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Action as char(1);
SET #Action = (CASE WHEN EXISTS(SELECT * FROM INSERTED)
AND EXISTS(SELECT * FROM DELETED)
THEN 'U' -- Set Action to Updated.
WHEN EXISTS(SELECT * FROM INSERTED)
THEN 'I' -- Set Action to Insert.
WHEN EXISTS(SELECT * FROM DELETED)
THEN 'D' -- Set Action to Deleted.
ELSE NULL -- Skip. It may have been a "failed delete".
END)
IF (#Action = 'I')
BEGIN
INSERT INTO audit_trg
SELECT
lr.sanction_status, i.sanction_status,
GETDATE(), lr.id, 'mytable', #Action
FROM
mytable lr
INNER JOIN
INSERTED i ON i.id = lr.id
END
ELSE IF (#Action = 'U')
BEGIN
INSERT INTO audit_trg
SELECT
i.sanction_status, lr.sanction_status,
GETDATE(), lr.id, 'mytable', #Action
FROM
mytable lr
INNER JOIN
DELETED i ON i.id = lr.id
END
ELSE
BEGIN
INSERT INTO audit_trg
SELECT
lr.sanction_status, i.sanction_status,
GETDATE(), lr.id, 'mytable', #Action
FROM
mytable lr
INNER JOIN
DELETED i ON i.id = lr.id
END
END
and audit_trg table
CREATE TABLE [dbo].[audit_trg]
(
[id] [int] IDENTITY(1,1) NOT NULL,
[old_status] [varchar](50) NULL,
[new_status] [varchar](50) NULL,
[u_datetime] [datetime] NULL,
[ref_id] [int] NULL,
[table_name] [varchar](50) NULL,
[actions] [varchar](50) NULL,
CONSTRAINT [PK_audit_trg]
PRIMARY KEY CLUSTERED ([id] ASC)
) ON [PRIMARY]
but I get error after some inserted that is
The target table 'dbo.mytable' of the DML statement cannot have
any enabled triggers if the statement contains an OUTPUT clause
without INTO clause.

Exception when updating row with rowversion?

I have a table that looks like this :
CREATE TABLE [dbo].[akut_prioritering]
(
[behandling_id] [int] NOT NULL,
[akutstatus] [int] NOT NULL,
[nasta_dag] [bit] NOT NULL,
[sort_order] [bigint] NOT NULL,
[rowversion] [timestamp] NOT NULL,
CONSTRAINT [XPKakut_prioritering]
PRIMARY KEY CLUSTERED ([behandling_id] ASC)
) ON [PRIMARY]
And then I have this stored procedure that tries to update rows in this table :
ALTER PROCEDURE [dbo].[akutlistaSave]
#behandlingSortOrder dbo.akutlista_sortorder_tabletype READONLY
AS
BEGIN
SET NOCOUNT ON;
DECLARE #behandlingId INT;
DECLARE #sortOrder BIGINT;
DECLARE #rowversion ROWVERSION;
DECLARE sortOrderCursor CURSOR LOCAL SCROLL STATIC FOR
SELECT behandling_id, sort_order FROM #behandlingSortOrder
OPEN sortOrderCursor
BEGIN TRAN
FETCH NEXT FROM sortOrderCursor INTO #behandlingId, #sortOrder, #rowversion
WHILE ##FETCH_STATUS = 0
BEGIN
IF EXISTS(SELECT *
FROM akut_prioritering ap
WHERE ap.behandling_id = #behandlingId
AND ap.rowversion = #rowversion)
BEGIN
UPDATE akut_prioritering
SET sort_order = #sortOrder
WHERE behandling_id = #behandlingId;
END
ELSE
BEGIN
RAISERROR ('Rowversion not correct.', 16, 1);
END
FETCH NEXT FROM sortOrderCursor INTO #behandlingId, #sortOrder, #rowversion
END
CLOSE sortOrderCursor
SELECT
ap.behandling_id, ap.rowversion
FROM
akut_prioritering ap
INNER JOIN
#behandlingSortOrder bso ON ap.behandling_id = bso.behandling_id;
DEALLOCATE sortOrderCursor
END
The inparameter type looks like this :
CREATE TYPE [dbo].[akutlista_sortorder_tabletype] AS TABLE
(
[behandling_id] [int] NULL,
[sort_order] [bigint] NULL,
[rowversion] [timestamp] NULL
)
When running this I get a SqlException :
Cannot insert an explicit value into a timestamp column. Use INSERT with a column list to exclude the timestamp column, or insert a DEFAULT into the timestamp column.
From what I understand the rowversion column should be updated with a new value automatically, there is no reason in my case to set it manual.
You can't set the rowversion value in dbo.akutlista_sortorder_tabletype because it is not updateable: it is auto generated
However, rowversion (a.k.a deprecated timestamp) is simply a (var)binary(8) with some special rules. You can define and set a (var)binary(8) in dbo.akutlista_sortorder_tabletype and compare on that in the UPDATE
From the first link
A nonnullable rowversion column is semantically equivalent to a binary(8) column. A nullable rowversion column is semantically equivalent to a varbinary(8) column.
It looks like you are trying to insert a timestamp value in a custom table type and then passing that to your stored procedure. As your error suggests, you cannot insert explicit timestamp values into timestamp columns.
You will need to find a different way of passing you table values to this stored procedure to work.

Alter scalar function in SQL server 2008 that referring in the computed column of a table

I have created a scalar function in SQL Server 2008 and the same I am referring in a computed column in few of my tables. Now I want to alter the function without dropping the table. But it throws an error:
Cannot ALTER 'dbo.GetStatus' because it is being referenced by object
'Order'.
Is is possible to alter the function? Or do I drop and create all dependable table first and then alter the function?
Here is my function:
CREATE FUNCTION [dbo].[GetStatus]
(
#FromDate datetime,
#ToDate datetime
)
RETURNS tinyint
AS
BEGIN
declare #ret tinyint;
if(#FromDate<=GETDATE() and (#ToDate>=GETDATE() or #ToDate is null))
set #ret= 1
else
set #ret= 0
return #ret
END
And it is referring in a table:
CREATE TABLE [dbo].[Order](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](200) NOT NULL,
[EffectiveFromDate] [datetime] NOT NULL,
[EffectiveToDate] [datetime] NULL,
[Status] AS ([dbo].[GetStatus]([EffectiveFromDate],[EffectiveToDate]))
)
This is by design. You should first drop all defaults/constraints, then alter your function and the add those constraints back. No need to drop the tables.
But you can work around this by the following trick:
add intermediate function that will call your actual function;
alter computed columns to call intermediate function instead of actual.
Example:
CREATE FUNCTION dbo.fnActual ( #p INT )
RETURNS INT
AS
BEGIN
RETURN #p + 1
END
GO
CREATE FUNCTION dbo.fnIntermediate ( #p INT )
RETURNS INT
AS
BEGIN
RETURN dbo.fnActual(#p)
END
GO
CREATE TABLE TestTable(id INT, fn AS dbo.fnIntermediate(id))
GO
Insert some value:
INSERT INTO dbo.TestTable VALUES ( 1 )
SELECT * FROM dbo.TestTable --selects 2
--throws exception
ALTER FUNCTION dbo.fnIntermediate ( #p INT )
RETURNS INT
AS
BEGIN
RETURN dbo.fnActual(#p)
END
GO
--succseeds
ALTER FUNCTION dbo.fnActual ( #p INT )
RETURNS INT
AS
BEGIN
RETURN #p + 2
END
GO
SELECT * FROM dbo.TestTable --selects 3
ALTER TABLE [dbo].[Order]
DROP COLUMN [Status]
GO
ALTER FUNCTION [dbo].[GetStatus] ...
GO
ALTER TABLE [dbo].[Order]
ADD [Status] AS ([dbo].[GetStatus]([EffectiveFromDate],[EffectiveToDate]))
GO
or even
ALTER TABLE [dbo].[Order]
DROP COLUMN [Status]
GO
ALTER TABLE [dbo].[Order]
ADD [Status] AS CAST(CASE WHEN [EffectiveFromDate] <= GETDATE() AND ([EffectiveToDate] >= GETDATE() OR [EffectiveToDate] IS NULL) THEN 1 ELSE 0 END as tinyint)
GO

Resources