SQL Server FUNCTION overflow int vs bigint - sql

I am using a SQL Server function which returns a bigInt and using this in a trigger to assign a value to a column of type bigint. However when I run the trigger, an overflow exception occurs (Arithmetic overflow error converting expression to data type int.), i.e. it treats it as an int, not a bigint
The function is:
ALTER FUNCTION [dbo].[longIntDateTime] ()
RETURNS bigint
AS
BEGIN
-- Declare the return variable here
DECLARE #ResultVar bigint;
DECLARE #now Datetime;
set #now = getdate();
SET #ResultVar=DATEPART(YYYY,#now)*100000000 + DATEPART(MM,#now)*1000000 + DATEPART(DD,#now)*10000 + DATEPART(HH,#now)*100;
-- DATEPART(HH,#now)*100 + DATEPART(MI,#now);
-- Return the result of the function
RETURN (#ResultVar);
END
The trigger is:
ALTER TRIGGER [dbo].[employeesInsert]
ON [dbo].[employees]
AFTER INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for trigger here
UPDATE employees
SET changeTimeStamp = dbo.longIntDateTime()
FROM inserted INNER JOIN employees On inserted._id = employees._id
END
and the table definition is:
CREATE TABLE [dbo].[employees](
[_id] [int] IDENTITY(1,1) NOT NULL,
[employee_name] [varchar](50) NOT NULL,
[password] [varchar](50) NOT NULL,
[isActive] [int] NOT NULL,
[isDeleted] [int] NOT NULL,
[changeTimeStamp] [bigint] NOT NULL,
CONSTRAINT [PK_employees] PRIMARY KEY CLUSTERED ([_id] ASC)
)
ALTER TABLE [dbo].[employees]
ADD CONSTRAINT [DF_employees_isActive] DEFAULT ((0)) FOR [isActive]
ALTER TABLE [dbo].[employees]
ADD CONSTRAINT [DF_employees_isDeleted] DEFAULT ((0)) FOR [isDeleted]
GO
If I take two '0's off the first yyyy part of the function, the trigger succeeds, however as is, it fails.
Clearly the value produced is less than a big int.
any ideas?
anton

The problem is this line of code:
SET #ResultVar=DATEPART(YYYY,#now)*100000000 + DATEPART(MM,#now)*1000000 + DATEPART(DD,#now)*10000 + DATEPART(HH,#now)*100;
The constants are interpreted as int so the entire calculate is done that way. You can fix this easily by casting the first to bigint:
SET #ResultVar=DATEPART(YYYY,#now)*cast(100000000 as bigint)+ DATEPART(MM,#now)*1000000 + DATEPART(DD,#now)*10000 + DATEPART(HH,#now)*100;

It's because DATEPART returns int.Try to cast to bigint before multiplying
cast (DATEPART(YYYY,#now) as bigint)*100000000

Related

Create SQL Server table name that includes a variable value

I'm creating a SQL Server table via a trigger, and I want the table name to be specific each time.
For the end result, I want the table name to be tblTEMP_INA_DATA_12345.
I could obviously, just type tblTEMP_INA_DATA_12345, but the #PlanID value will be different each time.
How could I modify the create table statement to do what I want? Is this possible?
I have searched, but I'm not sure what search terms to even use. I appreciate any and all responses even if the answer is no.
DECLARE #PlanID varchar(80)
SET #PlanID = 12345
CREATE TABLE [dbo].[tblTEMP_INA_DATA_]
(
[strQuestion] [varchar](max) NULL,
[strAnswer] [varchar](max) NULL
) ON [PRIMARY]
You can use dynamic sql to do this. Like below
Declare #PlanID varchar(80),#sql nvarchar(max);
Set #PlanID = 123456
set #sql= 'Create TABLE [dbo].' + QUOTENAME('tblTEMP_INA_DATA_' + #PlanID) + '
([strQuestion] [varchar](max) NULL,
[strAnswer] [varchar](max) NULL
) ON [PRIMARY]'
exec (#sql);

Stored procedure error: "Error converting data type nvarchar to uniqueidentifier"

So I'm new to creating SPs and right now I am trying to create an SP to insert values into my table Report below.
CREATE TABLE Report (
ID UNIQUEIDENTIFIER PRIMARY KEY NOT NULL,
STAFF VARCHAR(1000)NOT NULL,
EMAIL VARCHAR(1000)NOT NULL,
LASTCHANGE DATE NOT NULL
)
CREATE PROCEDURE spInsertOrUpdate(
#ID UNIQUEIDENTIFIER,
#STAFF VARCHAR(1000),
#EMAIL VARCHAR(1000),
#LASTCHANGE DATETIME
) AS
BEGIN
INSERT INTO Report(ID, STAFF, EMAIL, LASTCHANGE)
VALUES(#ID, #STAFF, #EMAIL, #LASTCHANGE)
END
EXEC spInsertOrUpdate NEWID, 'Evlyn Dawson', 'evdawson#gmail.com', GETDATE
Right After executing the SP I following error:
Msg 8114, Level 16, State 5, Procedure spInsertOrUpdate, Line 0 Error converting data type nvarchar to uniqueidentifier
Can someone please help me out with this issue?
So if your just calling your stored procedure with getdate and newid why dont you just add them as default on your table?
Table
CREATE TABLE [dbo].[Report](
[ID] [uniqueidentifier] NOT NULL CONSTRAINT [DF_Report_ID] DEFAULT (newid()),
[STAFF] [varchar](1000) NOT NULL,
[EMAIL] [varchar](1000) NOT NULL,
[LASTCHANGE] [datetime] NOT NULL CONSTRAINT [DF_Report_LASTCHANGE] DEFAULT (getdate()),
CONSTRAINT [PK__Report__3214EC27D2D8BF72] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Procedure
create PROCEDURE spInsertOrUpdate(
#STAFF VARCHAR(1000),
#EMAIL VARCHAR(1000)
) AS
BEGIN
INSERT INTO Report(STAFF, EMAIL)
VALUES(#STAFF, #EMAIL)
END
Execute statement
EXEC spInsertOrUpdate 'Evlyn Dawson', 'evdawson#gmail.com'
Edit
Please also note that your lastchanged column is of type DATE, however if you want date with timestamp you should use datetime
This error message is a bit of a wild goose chase, the problem is that both NEWID() and GETDATE() are functions, so require parentheses. Unforunately, you cannot pass a function as a parameter to a stored procedure, so you would first need to assign the values to a variable:
DECLARE #ID UNIQUEIDENTIFIER = NEWID(),
#Date DATE = GETDATE();
EXEC #spInsertOrUpdate #ID, 'Evlyn Dawson', 'evdawson#gmail.com', #Date;
As an aside, a UNIQUEIDENTIFIER column is a very poor choice for a clustering key
I would start by calling the functions correctly:
EXEC spInsertOrUpdate NEWID(), 'Evlyn Dawson', 'evdawson#gmail.com', GETDATE();
NEWID() and GETDATE() are functions, so you need parentheses after them.
However, I don't think the lack of parentheses would cause that particular error. You would need to set variables first, and then use them for the exec.
EDIT:
A better approach is to set the ids and dates automatically:
CREATE TABLE Report (
ID UNIQUEIDENTIFIER PRIMARY KEY NOT NULL DEFAULT NEWID(),
STAFF VARCHAR(1000) NOT NULL,
EMAIL VARCHAR(1000) NOT NULL,
LASTCHANGE DATE NOT NULL DEFAULT GETDATE()
);
CREATE PROCEDURE spInsertOrUpdate (
#STAFF VARCHAR(1000),
#EMAIL VARCHAR(1000)
) AS
BEGIN
INSERT INTO Report(STAFF, EMAIL)
VALUES (#STAFF, #EMAIL)
END;
EXEC spInsertOrUpdate 'Evlyn Dawson', 'evdawson#gmail.com';
I would also discourage you from using unique identifiers as primary keys in the table. They are rather inefficient, because they can lead to page fragmentation. Use an identity column instead.
Thanks For all your help.I finally found a proper way of doing this within the SP
and I got a proper understanding of SPs now.This is how I resolved the issue
CREATE PROCEDURE spInsertOrUpdate(#STAFF VARCHAR(1000),#EMAIL VARCHAR(1000),#CARS VARCHAR(1000))
AS
BEGIN
INSERT INTO Report(ID,STAFF,EMAIL,CARS,LASTCHANGE)
VALUES(NEWID(),#STAFF,#EMAIL,#CARS,GETDATE())
END
EXEC spInsertOrUpdate 'Evlyn Dawson','evdawson#gmail.com','Ferrari'
Note that I have also a CARS column

How to create the trigger for the table in SQL Server 2008

I have the following table:
CREATE TABLE [RTS].[MFB]
(
[record_id] [int] IDENTITY(1,1) NOT NULL,
[marker_id] [nvarchar](50) NULL,
[lat] [numeric](38, 8) NULL,
[lng] [numeric](38, 8) NULL,
[address] [nvarchar](512) NULL,
[hash] [smallint] NULL,
[updated] [datetime] NULL,
[first_created_date] [datetime] NULL,
CONSTRAINT [PK_MFB_1]
PRIMARY KEY CLUSTERED ([record_id] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
where the "record_id" is the primary key.
I need to create a trigger after the INSERT operation.
The conditions are:
If the marker_id column is new, INSERT the record to the table and set the hash column to 0;
If the marker_id already exists, UPDATE the existing record by setting the new updated column;
If both the marker_id already exists and any of the "lat", "lng" and "address" has been changed, UPDATE the existing record by setting the new "lat", "lng" and/or "address" and also setting "hash" to "1".
Basically, the MFB table should not have duplicated marker_id.
How can I achieve this by a setting up a trigger? Thanks!
Rafal is right but you can make a cursor for bulk insert and update but i cant promise for performance it should be like this
CREATE TRIGGER DBO.MFBTRG
ON DBO.MFB
INSTEAD OF INSERT,UPDATE
AS
BEGIN
DECLARE #marker_id NVARCHAR(50)
DECLARE #lat NUMERIC(38,8)
DECLARE #lng NUMERIC(38,8)
DECLARE #address NVARCHAR(512)
DECLARE #hash SMALLINT
DECLARE #updated DATETIME
DECLARE #first_created_date DATETIME
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE MFBINS CURSOR FAST_FORWARD FOR Select [marker_id],[lat],[lng],[address],[hash],[updated],[first_created_date] FROM INSERTED
OPEN MFBINS
FETCH NEXT FROM MFBINS INTO #marker_id,#lat,#lng,#address,#hash,#updated,#first_created_date
WHILE (##FETCH_STATUS=0)
BEGIN
IF NOT EXISTS (SELECT [marker_id] FROM MFB WHERE [marker_id]= #marker_id)
BEGIN
INSERT INTO [dbo].[MFB] ([marker_id],[lat],[lng],[address],[hash],[updated],[first_created_date])
VALUES (#marker_id,#lat,#lng,#address,#hash,#updated,#first_created_date)
END
ELSE
BEGIN
UPDATE MFB SET [updated]=#updated WHERE [marker_id]=#marker_id
END
-- Insert statements for trigger here
FETCH NEXT FROM MFBINS INTO #marker_id,#lat,#lng,#address,#hash,#updated,#first_created_date
END
CLOSE MFBINS
DEALLOCATE MFBINS
END
GO
and you can use to detect which column is update on update trigger with
IF UPDATE(COLUMN_NAME)
BEGIN
UPDATE LOGÄ°C
END
If you really want to do it this way you would have to create INSTEAD OF INSERT trigger - but beware it is going to be slow as you wouldn't be able to benefit from bulk insert.
Alternatively you could use MERGE statement and perform your INSERT/UPDATE scenario there.

Drop temp table if it exists

Friends,
I am creating a temp table. The script may be run several times so I need to check if the temp table exist then drop it. I have the written the code below but I get an error when running the script twice, that the table already exists:
There is already an object named '#lu_sensor_name_19' in the database.
It appears that IF OBJECT_ID('alarm..#lu_sensor_name_19') IS NOT NULL does not return true when the tablle is not null. What am I doing wrong?
IF OBJECT_ID('alarm..#lu_sensor_name_19') IS NOT NULL
BEGIN
DROP TABLE #lu_sensor_name_19
END
CREATE TABLE #lu_sensor_name_19(
sensorname_id int NOT NULL,
sensorname nvarchar(50) NOT NULL,
paneltype_id smallint NOT NULL,
panel_version_id int NULL,
prefix_allowed tinyint NOT NULL,
base_allowed tinyint NOT NULL,
suffix_allowed tinyint NOT NULL,
key_value int NULL,
sort_index int NULL,
device_allowed tinyint NOT NULL,
sensor_name_group_id smallint NOT NULL,
)
Temp #Tables are created in tempdb. Try this:
IF OBJECT_ID('tempdb..#lu_sensor_name_19') IS NOT NULL
BEGIN
DROP TABLE #lu_sensor_name_19
END
CREATE TABLE #lu_sensor_name_19...
SQL Server 2016 added the ability to do the drop in one line:
DROP TABLE IF EXISTS #lu_sensor_name_19
CREATE TABLE #lu_sensor_name_19...
Use this.
IF OBJECT_ID('tempdb.dbo.##myTempTable', 'U') IS NOT NULL
BEGIN
DROP TABLE ##myTempTable;
--DROP TABLE ##tempdb.dbo.myTempTable;
/* Above line commented out, because it generates warning:
"Database name 'tempdb' ignored, referencing object in tempdb.",
which is a pain in the neck if you are using a temp table to generate SQL code,
and want to print the code to the screen.*/
END;
GO
CREATE TABLE ##myTempTable(
FooBar nvarchar(128) not null,
);
And, in SQL Server 2016, you can write:
DROP TABLE IF EXISTS ##myTempTable

Inserting record from one column to another column in the same scope or statement

I have a Stored Procedure that populates a table: This table as indicated in the code below has an identity column which is also the primary key column.
I would like to append the primary key to contain leading letters: Example: ABC123.
Obviously this is not possible because the Primary key column is INT datatype.
So I created an additional column so that I can insert the appended primary key. This works except I have to make the new column Null and I am using an UPDATE statement.
Something tells me there is a better way.
Is there a way I can do this without using UPDATE after the initial Insert and have the new column CategoryID as Not Null?
Table Code:
CREATE TABLE [dbo].[Registration] (
[SystemID] INT IDENTITY (100035891, 1) NOT NULL,
[CategoryID] CHAR (13) NULL,
[FName] VARCHAR (30) NOT NULL,
[LName] VARCHAR (30) NOT NULL,
[MInit] CHAR (1) NULL,
PRIMARY KEY CLUSTERED ([SystemID] ASC)
);
Stored Procedure:
CREATE PROCEDURE [dbo].[uspInsertRegistration]
#FName VARCHAR(30),
#LName VARCHAR(30),
#MInit CHAR(1),
#CategoryID CHAR(13),
#SystemID int OUTPUT
AS
BEGIN
SET NOCOUNT ON
DECLARE #ErrCode int
INSERT INTO [dbo].[Registration] ([FName],[LName],[MInit])
VALUES (#FName, #LName, #MInit)
SELECT #ErrCode = ##ERROR, #SystemID = SCOPE_IDENTITY()
UPDATE [dbo].[Registration]
SET CategoryID = 'ABC'+ CAST(SystemID AS CHAR)
SET NOCOUNT OFF
RETURN #ErrCode
END
Finally this is what the table looks like with the data:
Thanks for being contagious with your knowledge. :)
Guy
My suggestion is to use a computed column, as what you're trying to do introduces redundancy. See below:
http://msdn.microsoft.com/en-us/library/ms191250%28v=sql.105%29.aspx
Alternately, make it big enough to contain a GUID, put a GUID into the column on the insert, then update it afterwards.