I have this database with table 'crigsStaffActivity'. I managed to retrieve the values and display it. But the result is not showing as my expectation.
Script to create table with values
CREATE TABLE [dbo].[crigsStaffActivity]
(
[projectRef] [varchar](200) NOT NULL,
[activityLine] [int] NOT NULL,
[cost] [real] NOT NULL,
[staffCost] [varchar](500) NOT NULL
) ON [PRIMARY]
GO
INSERT [dbo].[crigsStaffActivity] ([projectRef], [activityLine], [cost], [staffCost])
VALUES (N'MRC/CRIGS/330', 1, 1, N'ProjectLeader'),
(N'MRC/CRIGS/330', 2, 2, N'Research Collaborators'),
(N'MRC/CRIGS/330', 1, 1, N'Project Collaborators'),
(N'MRC/CRIGS/330', 2, 2, N'Project Collaborators'),
(N'MRC/CRIGS/330', 2, 3, N'Research/Project Assistant');
ALTER TABLE [dbo].[crigsStaffActivity]
ADD CONSTRAINT [DF__crigsStaff__cost__5535A963] DEFAULT ((0)) FOR [cost]
GO
Screenshot of table:
My stored procedure:
ALTER PROCEDURE [dbo].[getCrigsStaffActivity]
#ProjectRef AS VARCHAR(1000),
#staffCost AS varchar(1000)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #val AS VARCHAR(2000);
SET #val='';
DECLARE #temp AS VARCHAR(2000);
DECLARE #activityLine AS VARCHAR(2000);
DECLARE #cost AS VARCHAR(2000);
DECLARE #ref as CURSOR;
SET #ref = CURSOR FOR
SELECT activityLine, cost
FROM crigsStaffActivity
WHERE projectRef = #ProjectRef
AND staffCost = #staffCost
OPEN #ref;
FETCH NEXT FROM #ref INTO #activityLine, #cost;
WHILE ##FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM #ref INTO #activityLine, #cost;
SET #val = CONCAT(#activityLine,',',#cost);
END
CLOSE #ref;
DEALLOCATE #ref;
SELECT #val AS ref;
END
When I execute the stored procedure, I get this result:
ref
----
2,2
The issue is that for project collaborators I have two repeating values, thus I need to get a result like this:
ref
-----
1,1
2,2
My question is how to achieve the result mentioned above.
A better result of this stored procedure could have been:
ref
-----------------------------
1,1,ProjectLeader
2,2,Research collaborators
1,1,Project collaborators
2,2,Project collaborators
2,3,Research/Project Assistant
If I got it correct. you don't need to use the cursor.
ALTER PROCEDURE [dbo].[getCrigsStaffActivity]
#ProjectRef AS VARCHAR(1000),
#staffCost AS varchar(1000)
AS
BEGIN
SET NOCOUNT ON;
SELECT CONCAT(activityLine,',', cost,',', staffCost) as ref
FROM crigsStaffActivity
WHERE projectRef = #ProjectRef
AND staffCost = #staffCost
END
Please try this Procedure.
USE [***]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[getCrigsStaffActivity]
#ProjectRef as VARCHAR(1000),
#staffCost as varchar(1000)
AS
BEGIN
SET NOCOUNT ON;
Declare #val as varchar(2000);
set #val='';
Declare #temp as Varchar(2000);
Declare #activityLine as Varchar(2000);
Declare #cost as Varchar(2000);
DECLARE #ref as CURSOR;
SET #ref = CURSOR FOR
SELECT DISTINCT activityLine, cost
FROM crigsStaffActivity
where projectRef = #ProjectRef
and staffCost = #staffCost
OPEN #ref;
FETCH NEXT FROM #ref INTO #activityLine, #cost;
WHILE ##FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM #ref INTO #activityLine, #cost;
set #val = CONCAT(#activityLine,',',#cost);
END
CLOSE #ref;
DEALLOCATE #ref;
select #val as ref;
END
Related
Recently I have had to change a query from the following (fully working):
/****** WORKING ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [operations].[ROIWarehouseDatas]
(#Operation VARCHAR(50) = NULL,
#TableName NVARCHAR(255) = NULL,
#Results [dbo].[ForeSightData] READONLY)
AS
BEGIN
DECLARE #err INT
SET #err = 0
IF (#Operation = 'Insert')
BEGIN
DECLARE #SQLString NVARCHAR(4000)
DECLARE #ParamDefinition NVARCHAR(4000)
SET #SQLString = N'TRUNCATE TABLE ['+ #TableName + N'];
INSERT INTO ['+ #TableName + N']
SELECT [ID], [BrandName], [AdvertName], [VersionName], [WCPM]
FROM #Results;';
SET #ParamDefinition = N'#Operation VARCHAR(50), #Results [dbo].[ForeSightData] READONLY';
EXECUTE sp_executesql #SQLString, #ParamDefinition, #TableName, #Results
END
--ENDIF Insert
SET #err = ##ERROR
RETURN #err
END
To the following (not working):
/****** NOT WORKING ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [operations].[ROIWarehouseDatas]
(#Operation VARCHAR(50) = NULL,
#TableName NVARCHAR(255) = NULL,
#Results [dbo].[ForeSightData] READONLY)
AS
BEGIN
DECLARE #err INT
DECLARE #SQLString NVARCHAR(4000)
DECLARE #ParamDefinition NVARCHAR(4000)
SET #err = 0
IF (#Operation = 'Insert')
BEGIN
SET #SQLString = N'MERGE INTO ['+ #TableName +'] AS T
USING #Results AS S ON T.ID = S.ID
WHEN MATCHED
THEN UPDATE
SET T.[BrandName] = S.[BrandName],
T.[AdvertName] = S.[AdvertName],
T.[VersionName] = S.[VersionName],
T.[VersionDuration] = S.[VersionDuration],
T.[WCPM] = S.[WCPM]
WHEN NOT MATCHED BY TARGET
THEN INSERT ([ID], [BrandName], [AdvertName], [VersionName], [WCPM])
VALUES (S.[ID], S.[BrandName], S.[AdvertName], S.[VersionName], S.[WCPM]);';
SET #ParamDefinition = N'#Operation VARCHAR(50), #Results [dbo].[ForeSightData] READONLY';
EXECUTE sp_executesql #SQLString, #ParamDefinition, #TableName, #Results
END
--ENDIF Insert
SET #err = ##ERROR
RETURN #err
END
However, when I run the program I get the following error:
An object or column name is missing or empty. For SELECT INTO statements, verify each column has a name. For other statements, look for empty alias names. Aliases defined as "" or [] are not allowed. Change the alias to a valid name. Unclosed quotation mark after the character string ''.
Incorrect syntax near ''.
I tried checking the syntax - and that came up as fine.
Seems not correct syntax for SQL MERGE.
WHEN NOT MATCHED BY T THEN should be Target not T:
WHEN NOT MATCHED BY Target
THEN .....
I'm sure this is a easy fix, but I can't find an answer here. Been many a years since I have written stored procedures..
These are my procedures:
This first one works, and returns the newly created Id.
ALTER PROCEDURE [dbo].[sp_CreateBytegymType]
#Name NVARCHAR(200),
#Type NCHAR(1),
#Description NVARCHAR(MAX) NULL,
#Comment NVARCHAR(MAX) NULL,
#Source NVARCHAR(MAX) NULL,
#BtId INT OUTPUT
AS
BEGIN
SET NOCOUNT ON
INSERT INTO BytegymType
VALUES (#Name, #Type, #Description, #Comment, #Source)
SET #BtId = CAST(SCOPE_IDENTITY() AS INT)
END
The second one calls the first one:
ALTER PROCEDURE [dbo].[sp_CreateMuscle]
#Name NVARCHAR(200),
#Type NCHAR(1),
#Description NVARCHAR(MAX) NULL,
#Comment NVARCHAR(MAX) NULL,
#Source NVARCHAR(MAX) NULL,
#Group NVARCHAR(20) NULL
AS
BEGIN
DECLARE #BtId int
EXEC sp_CreateBytegymType
#Name = #Name,
#Type = #Type,
#Description = #Description,
#Comment = #Comment,
#Source = #Source,
#BtId = #BtId
INSERT INTO Muscle
VALUES (#BtId, #Group)
END
I get the following error:
Msg 515, Level 16, State 2, Procedure sp_CreateMuscle, Line 20 [Batch Start Line 2]
Cannot insert the value NULL into column 'BtId'
Seems I'm not keeping the #BtId value. Do I need to put it into a new value after executing the sp_CreateBytegymType?
Also I would like to do this in a transactional manner. So if the the insert into Muscle fails, it should rollback the stored procedure insert.
You need to add OUTPUT:
exec sp_CreateBytegymType
#Name = #Name,
#Type = #Type,
#Description = #Description,
#Comment = #Comment,
#Source = #Source,
#BtId = #BtId OUTPUT;
Also prefixing user defined stored procedures with sp_ is not advised. Related article: Is the sp_ prefix still a no-no?
I tried to define following SQL Server nested cursor statement: I loop calendars and migrate them from cut_calendar to sd_calendar. Each calendar also have calendar days. They are also moved by each calendar move.
DECLARE #id NUMERIC(20)
DECLARE #sdCalendarId NUMERIC(20)
DECLARE #calendarTypId NUMERIC(5)
DECLARE #name NVARCHAR(35)
DECLARE #description NVARCHAR(255)
DECLARE #ptyId NUMERIC(20)
DECLARE #lockCode NVARCHAR(20)
DECLARE #dataOwnerId NUMERIC(20)
DECLARE #cntId NUMERIC(20)
DECLARE #nonBusinessDaysMonday CHAR(1)
DECLARE #nonBusinessDaysTuesday CHAR(1)
DECLARE #nonBusinessDaysWednesday CHAR(1)
DECLARE #nonBusinessDaysThursday CHAR(1)
DECLARE #nonBusinessDaysFriday CHAR(1)
DECLARE #nonBusinessDaysSaturday CHAR(1)
DECLARE #nonBusinessDaysSunday CHAR(1)
DECLARE #ccyId NUMERIC(20)
DECLARE #code NVARCHAR(30)
DECLARE #version NUMERIC(10)
DECLARE #seal VARCHAR(255)
DECLARE #lstUpdTs DATETIME
DECLARE #day_id NUMERIC(20)
DECLARE #day_calDate DATETIME
DECLARE #day_lockCode NVARCHAR(20)
DECLARE #day_calComment NVARCHAR(255)
DECLARE #day_dataOwnerId NUMERIC(20)
DECLARE #day_calendarId NUMERIC(20)
DECLARE #day_calRecurring CHAR(1)
DECLARE #day_version NUMERIC(10)
DECLARE #day_seal VARCHAR(255)
DECLARE #day_lstUpdTs DATETIME
DECLARE #day_sdCalendarDaysId NUMERIC(20)
DECLARE #sdCodeId NUMERIC(20)
DECLARE cursorCutoffCalendar CURSOR FOR
SELECT ID, NAME, CALENDAR_TYP_ID,DESCRIPTION,PTY_ID,LOCK_CODE,DATA_OWNER_ID,CNT_ID,NON_BUSINESS_DAYS_MONDAY,NON_BUSINESS_DAYS_TUESDAY,NON_BUSINESS_DAYS_WEDNESDAY,NON_BUSINESS_DAYS_THURSDAY,NON_BUSINESS_DAYS_FRIDAY,NON_BUSINESS_DAYS_SATURDAY,NON_BUSINESS_DAYS_SUNDAY,CCY_ID,CODE,VERSION,SEAL,LST_UPD_TS
FROM CUT_CALENDAR
WHERE ID != 1
OPEN cursorCutoffCalendar
FETCH NEXT FROM cursorCutoffCalendar INTO #id, #name, #calendarTypId, #description, #ptyId, #lockCode, #dataOwnerId, #cntId, #nonBusinessDaysMonday, #nonBusinessDaysTuesday, #nonBusinessDaysWednesday, #nonBusinessDaysThursday, #nonBusinessDaysFriday, #nonBusinessDaysSaturday, #nonBusinessDaysSunday, #ccyId, #code, #version, #seal, #lstUpdTs
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #sdCalendarId = COALESCE(MAX(ID),1) FROM SD_CALENDAR
SET #sdCalendarId = #sdCalendarId + 1
UPDATE CUT_CALENDAR_DAY
SET CALENDAR_ID = #sdCalendarId
WHERE CALENDAR_ID = #id
SELECT #sdCodeId = ID FROM SD_CALENDAR WHERE CODE = #code
IF #sdCodeId > 0
SET #code = CONCAT(#code, '_co')
ELSE
INSERT INTO SD_CALENDAR (ID, NAME, CALENDAR_ROLE_ID,DESCRIPTION,USE_IN_CUTOFF,PTY_ID,LOCK_CODE,DATA_OWNER_ID,CNT_ID,NON_BUSINESS_DAYS_MONDAY,NON_BUSINESS_DAYS_TUESDAY,NON_BUSINESS_DAYS_WEDNESDAY,NON_BUSINESS_DAYS_THURSDAY,NON_BUSINESS_DAYS_FRIDAY,NON_BUSINESS_DAYS_SATURDAY,NON_BUSINESS_DAYS_SUNDAY,CCY_ID,CODE,VERSION,SEAL,LST_UPD_TS)
VALUES(#sdCalendarId, #name, #calendarTypId,#description,1,#ptyId,#lockCode,#dataOwnerId,#cntId,#nonBusinessDaysMonday,#nonBusinessDaysTuesday,#nonBusinessDaysWednesday,#nonBusinessDaysThursday,#nonBusinessDaysFriday,#nonBusinessDaysSaturday,#nonBusinessDaysSunday,#ccyId,#code,#version,#seal,#lstUpdTs)
DECLARE cursorCutoffCalendarDays CURSOR FOR
SELECT ID, CAL_DATE, LOCK_CODE,CAL_COMMENT,DATA_OWNER_ID,CALENDAR_ID,CAL_RECURRING,VERSION,SEAL,LST_UPD_TS
FROM CUT_CALENDAR_DAY
WHERE ID != 1
OPEN cursorCutoffCalendarDays
FETCH NEXT FROM cursorCutoffCalendarDays INTO #day_id, #day_calDate, #day_lockCode, #day_calComment, #day_dataOwnerId, #day_calendarId, #day_calRecurring, #day_version, #day_seal, #day_lstUpdTs
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #day_sdCalendarDaysId = COALESCE(MAX(ID),1) FROM SD_CALENDAR_DAY
SET #day_sdCalendarDaysId = #day_sdCalendarDaysId + 1
INSERT INTO SD_CALENDAR_DAY (ID, CAL_DATE, LOCK_CODE,CAL_COMMENT,DATA_OWNER_ID,CALENDAR_ID,CAL_RECURRING,VERSION,SEAL,LST_UPD_TS)
VALUES(#day_sdCalendarDaysId, #day_calDate, #day_lockCode, #day_calComment, #day_dataOwnerId, #day_calendarId, #day_calRecurring, #day_version, #day_seal, #day_lstUpdTs)
FETCH NEXT FROM cursorCutoffCalendarDays INTO #day_sdCalendarDaysId, #day_calDate, #day_lockCode, #day_calComment, #day_dataOwnerId, #day_calendarId, #day_calRecurring, #day_version, #day_seal, #day_lstUpdTs
END
CLOSE cursorCutoffCalendarDays
DEALLOCATE cursorCutoffCalendarDays
GO
DELETE FROM CUT_CALENDAR
WHERE ID = #id
FETCH NEXT FROM cursorCutoffCalendar INTO #sdCalendarId, #name, #calendarTypId, #description, #ptyId, #lockCode, #dataOwnerId, #cntId, #nonBusinessDaysMonday, #nonBusinessDaysTuesday, #nonBusinessDaysWednesday, #nonBusinessDaysThursday, #nonBusinessDaysFriday, #nonBusinessDaysSaturday, #nonBusinessDaysSunday, #ccyId, #code, #version, #seal, #lstUpdTs
END
CLOSE cursorCutoffCalendar
DEALLOCATE cursorCutoffCalendar
GO
Now when I run this, I get following error:
SQLServerException: Incorrect syntax near 'cursorCutoffCalendarDays'.
cursorCutoffCalendarDays is the inner cursor of my statement.
Try removing GO from:
CLOSE cursorCutoffCalendarDays
DEALLOCATE cursorCutoffCalendarDays
GO
And I agree with the comment you got from GarethD, I used to write cursors like this but then I asked how to do it without the cursor and got a nice explanation
Blockquote
Remove Go from this line then try
CLOSE cursorCutoffCalendarDays
DEALLOCATE cursorCutoffCalendarDays
I'm trying to combine a result mixed with some SELECTs.
I wanted to set #result combined with the result of [proc_Get_Frame_CourseNum] procedure but It didn't work.
declare #str varchar(300)
declare #result varchar(200)
declare #temp varchar(20)
declare #i int
set #str='110,120,130,140'
set #result=''
set #temp=''
set #i=0
while #i<len(#str)/4+1
begin
set #temp=substring(#str,1,3)
set #str=substring(#str,2,len(#str))
set #result=#result+ exec [proc_Get_Frame_CourseNum] #temp
set #i=#i+1
end
select #temp
Personally, I'd make use of output variables
CREATE PROCEDURE proc_Get_Frame_CourseNum
#temp varchar(20),
#outValue varchar(50) OUTPUT
AS
BEGIN
--do stuff
--before you leave the method or do your final SELECT
SET #outValue = 'whatever your result is'
--more stuff
END
Then in your code, you just go:
DECLARE #outValue VARCHAR(20)
-- rest of your code
EXEC [proc_Get_Frame_CourseNum] #temp, #outValue OUT
SET #result = #result + #outValue
Alternatively, you could just dump the results of the SP into a temp table, then read from it into your #Result variable.
You can't interpolate the result of one procedure by appending it.
I am assuming now that [proc_Get_Frame_CourseNum] returns a scalar result.
So run exec [proc_Get_Frame_CourseNum] #temp in another line of batch (before set #result = #result + call)
Your query should look like,
declare #scalarResult = exec [proc_Get_Frame_CourseNum] #temp
set #result=#result+ #scalarResult
I have a stored procedure named insert2Newsletter with parameters
(#sex nvarchar(10),
#f_name nvarchar(50),
#l_name nvarchar(70),
#email nvarchar(75),
#ip_address nvarchar(50),
#hotelID int,
#maArt nchar(2))
I want call this stored procedure in an insert trigger. How do I retrieve the corresponding fields from inserted and how do i call insert2Newsletter within the trigger?
I tried without success:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER RA2Newsletter
ON [dbo].[Reiseagent]
AFTER INSERT
AS
DECLARE #rAgent_Name nvarchar(50),
DECLARE #rAgent_Email nvarchar(50),
DECLARE #rAgent_IP nvarchar(50),
DECLARE #hotelID int
BEGIN
SET NOCOUNT ON;
-- Insert statements for trigger here
Select #rAgent_Name=rAgent_Name, #rAgent_Email=rAgent_Email, #rAgent_IP=rAgent_IP, #hotelID=hotelID From Inserted
EXEC insert2Newsletter '','',#rAgent_Name,#rAgent_Email,rAgent_IP,#hotelID,'RA'
END
GO
thx a lot for your feedback... greetings...
I think you will have to loop over the "inserted" table, which contains all rows that were updated. You can use a WHERE loop, or a WITH statement if your primary key is a GUID. This is the simpler (for me) to write, so here is my example. We use this approach, so I know for a fact it works fine.
ALTER TRIGGER [dbo].[RA2Newsletter] ON [dbo].[Reiseagent]
AFTER INSERT
AS
-- This is your primary key. I assume INT, but initialize
-- to minimum value for the type you are using.
DECLARE #rAgent_ID INT = 0
-- Looping variable.
DECLARE #i INT = 0
-- Count of rows affected for looping over
DECLARE #count INT
-- These are your old variables.
DECLARE #rAgent_Name NVARCHAR(50)
DECLARE #rAgent_Email NVARCHAR(50)
DECLARE #rAgent_IP NVARCHAR(50)
DECLARE #hotelID INT
DECLARE #retval INT
BEGIN
SET NOCOUNT ON ;
-- Get count of affected rows
SELECT #Count = Count(rAgent_ID)
FROM inserted
-- Loop over rows affected
WHILE #i < #count
BEGIN
-- Get the next rAgent_ID
SELECT TOP 1
#rAgent_ID = rAgent_ID
FROM inserted
WHERE rAgent_ID > #rAgent_ID
ORDER BY rAgent_ID ASC
-- Populate values for the current row
SELECT #rAgent_Name = rAgent_Name,
#rAgent_Email = rAgent_Email,
#rAgent_IP = rAgent_IP,
#hotelID = hotelID
FROM Inserted
WHERE rAgent_ID = #rAgent_ID
-- Run your stored procedure
EXEC insert2Newsletter '', '', #rAgent_Name, #rAgent_Email,
#rAgent_IP, #hotelID, 'RA', #retval
-- Set up next iteration
SET #i = #i + 1
END
END
GO
I sure hope this helps you out. Cheers!
Finally ...
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[RA2Newsletter]
ON [dbo].[Reiseagent]
AFTER INSERT
AS
declare
#rAgent_Name nvarchar(50),
#rAgent_Email nvarchar(50),
#rAgent_IP nvarchar(50),
#hotelID int,
#retval int
BEGIN
SET NOCOUNT ON;
-- Insert statements for trigger here
Select
#rAgent_Name = rAgent_Name,
#rAgent_Email = rAgent_Email,
#rAgent_IP = rAgent_IP,
#hotelID = hotelID
From Inserted
EXEC insert2Newsletter
'',
'',
#rAgent_Name,
#rAgent_Email,
#rAgent_IP,
#hotelID,
'RA',
#retval
END
The following should do the trick - Only SqlServer
Alter TRIGGER Catagory_Master_Date_update ON Catagory_Master AFTER delete,Update
AS
BEGIN
SET NOCOUNT ON;
Declare #id int
DECLARE #cDate as DateTime
set #cDate =(select Getdate())
select #id=deleted.Catagory_id from deleted
print #cDate
execute dbo.psp_Update_Category #id
END
Alter PROCEDURE dbo.psp_Update_Category
#id int
AS
BEGIN
DECLARE #cDate as DateTime
set #cDate =(select Getdate())
--Update Catagory_Master Set Modify_date=''+#cDate+'' Where Catagory_ID=#id --#UserID
Insert into Catagory_Master (Catagory_id,Catagory_Name) values(12,'Testing11')
END
You pass an undefined rAgent_IP parameter in EXEC instead of the local variable #rAgent_IP.
Still, this trigger will fail if you perform a multi-record INSERT statement.