How can I select the top 1 column value into a variable? - sql

Here is my table definition where I store the installation information:
CREATE TABLE [dbo].[InstallInfo](
[ID] [uniqueidentifier] NOT NULL,
[Module] [int] NOT NULL,
[Version] [nvarchar](50) NOT NULL,
[InstallDate] [datetime] NOT NULL,
CONSTRAINT [PK_InstallInfo] 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]
What I want to do is get the top 1 row (install version) for a module, based on the latest date:
ALTER PROCEDURE [dbo].[InstallInfo_GetLatest]
-- Add the parameters for the stored procedure here
#Module int,
#Version nvarchar(50) out
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
set #Version = ''
-- Insert statements for procedure here
SELECT TOP 1 #Version=[Version]
from InstallInfo
where [Module] = #Module
order by InstallDate
END
However, when I run the stored proc, I get this error:
Msg 8114, Level 16, State 5, Procedure InstallInfo_GetLatest, Line 0
Error converting data type nvarchar to int.
Here is how I am executing the stored proc:
declare #Module int
set #Module = 1
declare #versionOut nvarchar(50)
exec InstallInfo_GetLatest Module, #versionOut output
select #versionOut as 'v OUT'
FOUND IT: Forgot the # sign
exec InstallInfo_GetLatest #Module, #versionOut output
Thanks everybody !

Here is the answer after multiple comments and feedback:
exec InstallInfo_GetLatest #Module, #versionOut output

Related

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.

SQL DLETE Statement not working

I have a customized application in my company where I can create a place for users to input their values to a database.
The table where I am submitting the data has 5 columns with its SQL CREATE Query as below:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Log_Ongoing](
[ID] [int] IDENTITY(1,1) NOT NULL,
[LogType] [int] NULL,
[ActivityDate] [datetime] NOT NULL,
[ActivityDescription] [text] NULL,
[Train] [int] NULL,
CONSTRAINT [PK_Log_Ongoing] 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] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[Log_Ongoing] WITH CHECK ADD CONSTRAINT [FK_Log_Ongoing_Trains] FOREIGN KEY([Train])
REFERENCES [dbo].[Trains] ([Id])
GO
ALTER TABLE [dbo].[Log_Ongoing] CHECK CONSTRAINT [FK_Log_Ongoing_Trains]
GO
The purpose of this table is to record the ongoing activities in the plant.
The user can come later and modify those activities by updating, adding or deleting through the application by choosing the report data then modifying the data.
My thinking was that before the user submits the data I will delete the old data with the same report date first then insert the new data again.
Unfortunately the data is submitted successfully, but not deleted.
I made a SQL trace to check the queries that the application sends to the database, and I found the below two statements:
exec sp_executesql N'DELETE FROM Log_Ongoing WHERE ActivityDate = #StartDate',N'#startDate datetimeoffset(7)',#startDate='2017-02-12 07:00:00 +02:00'
exec sp_executesql N'INSERT INTO Log_Ongoing (LogType, ActivityDate, ActivityDescription, Train ) VALUES (1,#StartDate, #Activity, #Train)',N'#Train int,#Activity nvarchar(2),#startDate datetimeoffset(7)',#Train=1,#Activity=N'11',#startDate='2017-02-12 07:00:00 +02:00'
When I tested the INSERT staement in the SSMS, it worked fine, but then when I tested the DELETE statement, it didn't work. What is wrong with this query?

Filtered Unique Index causing UPDATE to fail because incorrect 'QUOTED_IDENTIFIER' settings

We've put in place the following filtered index on a table in our SQL Server 2016 database:
CREATE UNIQUE NONCLUSTERED INDEX [fix_SystemPKeyExecutionOrder] ON [DataInt].[TaskMaster]
(
[SystemPkey] ASC,
[ExecutionOrder] ASC
)
WHERE ([ExecutionOrder] IS NOT NULL)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 95)
GO
Which is causing SQL code to fail now with the following error:
UPDATE failed because the following SET options have incorrect
settings: 'QUOTED_IDENTIFIER'. Verify that SET options are correct for
use with indexed views and/or indexes on computed columns and/or
filtered indexes and/or query notifications and/or XML data type
methods and/or spatial index operations. [SQLSTATE 42000] (Error
1934). The step failed.
When the filtered index is removed, the code runs perfectly.
Looking on MSDN for Index Options, there's nothing about QUOTED_IDENTIFIERS.
None of the UPDATE statements in our SQL code have double quotes for any of the values. The only double-quotes we can see are the following:
SET #ROWCOUNT = ##ROWCOUNT
If (#ROWCOUNT = 0)
BEGIN
RAISERROR('The "File Import" task ACTIVE_YN could not be updated to "Y". Either the task does not exist or the system "File Import To Stage" does not exist.', 16, 1)
END
ELSE
BEGIN
Print 'Successfully updated the "File Import" task ACTIVE_YN to "Y".'
END
Even if we change those double quotes " to two single quotes '', the code still fails with the same error.
The table itself was created with:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [DataInt].[TaskMaster](
[Pkey] [bigint] IDENTITY(1,1) NOT NULL,
[ScheduleMasterPkey] [int] NOT NULL,
[SystemPkey] [int] NOT NULL,
[SourcePkey] [int] NOT NULL,
[TargetPkey] [int] NOT NULL,
[TaskName] [varchar](255) NOT NULL,
[TaskTypePkey] [int] NOT NULL,
[Active_YN] [char](1) NOT NULL,
[ModifiedDate] [datetime] NULL,
[ModifiedBy] [varchar](100) NULL,
[RowVersion] [timestamp] NOT NULL,
[ExecutionOrder] [int] NULL,
CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED
(
[Pkey] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 95) ON [PRIMARY],
CONSTRAINT [uc_TaskName] UNIQUE NONCLUSTERED
(
[TaskName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 95) ON [PRIMARY]
) ON [PRIMARY]
GO
Like I said though, the entirety of the code runs perfectly if we do not create the filtered index; it only fails with the index.
So why is the filtered index suddenly causing our SQL to bomb and how can we fix it?
UPDATE: here is a small snippet of code that reproduces the failure. This code is run through an SQL Agent Job. When the index is removed, this code runs as expected stating the error the task does not exist:
DECLARE #ROWCOUNT INT = 0
UPDATE [DataIntegrationMaster].[DataInt].[TaskMaster]
Set Active_YN = 'Y'
where TaskName = 'File Import'
and SystemPkey = 0
SET #ROWCOUNT = ##ROWCOUNT
If (#ROWCOUNT = 0)
BEGIN
RAISERROR('The "File Import" task ACTIVE_YN could not be updated to "Y". Either the task does not exist or the system "File Import To Stage" does not exist.', 16, 1)
END
ELSE
BEGIN
Print 'Successfully updated the "File Import" task ACTIVE_YN to "Y".'
END
UPDATE2 with ANSWER:
As pointed out by the helpful answers below, I had to put
SET QUOTED_IDENTIFIER ON
at the top of the SQL for it to work properly.
SET QUOTED_IDENTIFIER ON
has NO EFFECT when I use it creating the index.
There is: SET QUOTED_IDENTIFIER (Transact-SQL)
In order to prevent similar issues, I would recommend to check the exact requirements for creating a filtered index: CREATE INDEX (Transact-SQL). It has a nice neat table that shows SET options required for a filtered index to be created.
As pointed out in #Roger Wolf's answer, creating a filtered index requires you to have the QUOTED_IDENTIFER setting to be set to ON, which is what you did. Had you not done so, you would have been unable to create the filtered index in the first place.
However, once created, it would seem that any DML operation (not just updates) on that table require you to have the QUOTED_IDENTIFER setting to be set to ON as well. This is what you are currently missing, and the reason why you get the error.
So, I don't know what the context of your update is, whether you are running this as an ad-hoc statement, or if this is part of a stored procedure. Either way, make sure to include the SET QUOTED_IDENTIFIER ON statement somewhere at the beginning.

Why doesn't this Check constraint work?

I have created a check constraint in SQL Server 2005, but this check constraint doesn't work. The SQL Server Management Studio tells me by an insert statement the following message:
Msg 547, Level 16, State 0, Line 1
The INSERT statement conflicted with the CHECK constraint "MY_CHECK_CONSTAINT". The conflict occurred in database "MY_DB", table "dbo.MY_TABLE", column 'MY_COLUMN'.
I have added the check constraint with the following code:
ALTER TABLE MY_TABLE WITH NOCHECK
ADD CONSTRAINT CK_MY_CHECK_CONSTRAINT CHECK (dbo.MY_FUNCTION(MY_PARAMETER)<1)
The calling function "MY_FUNCTION" returns an int.
My target is that if my function returns an int which is less than 1 the insert statement can successfully be completed and if the return value is bigger than 0 the insert statement has to be terminated.
My problem now is that my function returns the value 0 but the insert statement has been terminated always. What am I doing wrong?
The code of my function is the following:
CREATE FUNCTION MY_FUNCTION(#MY_PARAMETER uniqueidentifier)
RETURNS int
AS
BEGIN
declare #return int = 0
SET #return = (SELECT COUNT(MY_COLUMN) FROM MY_TABLE WHERE MY_COLUMN= #MY_PARAMETER )
return #return
END
Thanks for your help.
I was able to reproduce your problem in 100%. Try this new
example below. Now my table table1 is empty, and I cannot insert
any number into it :) Very interesting situation, absolutely the
same as yours, I believe.
"Maybe when your UDF code is executed, it already sees this same
row which you're just trying to insert (it sees it's in the table).
I don't know the inner workings and don't have much time now to check it.
But that could be the issue. My UDF doesn't perform a check based on some
SELECT in the same table, that's what's conceptually different between
your example and my example."
OK, after 5 more minutes of research, turns out my guess was right.
When your UDF is called, it sees the row you're just trying
to insert.
See the accepted answer here.
Check constraint UDF with multiple input parameters not working
So - mystery uncovered, it seems :)
--- 1 ---
USE [test]
GO
/****** Object: UserDefinedFunction [dbo].[ContainsNumber] Script Date: 11/26/2013 07:06:41 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[ContainsNumber]
(
#number int
)
RETURNS INT AS
BEGIN
declare #result int
select #result = count(*)
from test.dbo.table1
where
number = #number
if (#result > 0)
begin
set #result = 1
end
return #result
END
GO
--- 2 ---
USE [test]
GO
/****** Object: Table [dbo].[table1] Script Date: 11/26/2013 07:06:33 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[table1](
[id] [int] IDENTITY(1,1) NOT NULL,
[number] [int] NULL,
CONSTRAINT [PK_table1] 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]
GO
ALTER TABLE [dbo].[table1] WITH CHECK ADD CONSTRAINT [CK_table1] CHECK (([dbo].[ContainsNumber]([number])=(0)))
GO
ALTER TABLE [dbo].[table1] CHECK CONSTRAINT [CK_table1]
GO
1) Maybe you can try this in your code:
SELECT #return = COUNT(MY_COLUMN)
FROM MY_TABLE WHERE MY_COLUMN = #MY_PARAMETER
instead of what you did.
2) Try naming the variable not #return but e.g. #result.
3) Try walking your function outside of its normal call.
4) Also, you might want to try this test below.
I don't see any issues with it ... But OK,
it's not 100% the same as yours.
This check constraint below works fine and uses
my user defined function IsEvenNumber.
----- 1 -----
USE [test]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[IsEvenNumber]
(
#number int
)
RETURNS INT AS
BEGIN
declare #result int
set #result = 1
if (((#number) % 2) <> 0)
begin
set #result = 0
end
return #result
END
GO
----- 2 -----
USE [test]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[table1](
[id] [int] IDENTITY(1,1) NOT NULL,
[number] [int] NULL,
CONSTRAINT [PK_table1] 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]
GO
ALTER TABLE [dbo].[table1] WITH CHECK ADD CONSTRAINT [CK_Table1] CHECK (([dbo].[IsEvenNumber]([number])<(1)))
GO
ALTER TABLE [dbo].[table1] CHECK CONSTRAINT [CK_Table1]
GO
----- 3 -----
insert into table1(number) values (3) -- OK
insert into table1(number) values (10) -- FAILED
insert into table1(number) values (0) -- FAILED
insert into table1(number) values (5) -- OK