sql server - setting permissions in trigger - sql

I have a part of a trigger like so -
DECLARE #isInsert TINYINT
SET #isInsert = (CASE #actionType WHEN 'I' THEN 1 ELSE 0 END)
SELECT
(CASE #isInsert WHEN 1 THEN i.groupId ELSE d.groupId END) AS groupId
INTO #tmpRecordPermissionsToCheck
FROM inserted i
FULL JOIN deleted d
ON i.userId = d.userId
AND
i.groupId = d.groupId
-- Stop everything if the user is attempting to edit something they're not entitled to...
-- special case(s): refer above for additional tblServer-specific checks required here
DECLARE #errMsg VARCHAR(255)
SELECT #errMsg = 'You do not have permission to edit permissions for group ' + IsNULL(ug.shortName, '')
FROM #tmpRecordPermissionsToCheck tmp
LEFT JOIN tblUserGroups ug
ON ug.groupId = tmp.groupId
WHERE dbo.hasAdministrativePermissionsForGroup(tmp.groupId, dbo.getCurrentUser()) = 0
IF (#errMsg IS NOT NULL)
BEGIN
RAISERROR ( #errMsg, 16, 1 )
ROLLBACK TRANSACTION
RETURN
END
I'm calling a separate function that returns a 0 or 1 bit value.
If I do select dbo.isGlobalAdministrator(dbo.getCurrentUser()) I get a 1.
How do I structure the above code so that the IF (#errMsg IS NOT NULL) can be overridden if dbo.isGlobalAdministrator(dbo.getCurrentUser()) = 1 ?

How do I structure the above code so that the IF (#errMsg IS NOT NULL) can be overridden if dbo.isGlobalAdministrator(dbo.getCurrentUser()) = 1 ?
When you say overridden,i think you want to bypass errormessage
so just add this above error message
if ( dbo.isGlobalAdministrator(dbo.getCurrentUser()) = 1)
return

Related

How to use IF within AND in T-SQL

I am trying to create a stored procedure which will use one of the optional parameters provided.
In the code below they are #nStudentId and #nStudentIds set to NULL initially. Only one of them will be sent when the proc is called. When #nStudentIds are sent they will come-in as comma separated values.
CREATE PROCEDURE [dbo].[usp_GetStudentReferrals]
(
#ProfessorId BIGINT,
#nStudentId BIGINT = NULL,
#nStudentIds NVARCHAR(999) = NULL
)
AS
BEGIN
SELECT DISTINCT SR.StudentReferralId
FROM StudentReferral SR WITH(NOLOCK)
INNER JOIN PotentialCandidate PC WITH(NOLOCK) ON PC.PotentialCandidateId = SR.StudentId
WHERE SR.ProfessorId = #nProfessorId
AND -- this is where I am not able to figure out the logic to use either #nStudentId or #nStudentIds, whichever is passed in.
END
So when #nStudentId is sent it should be this in the AND
SR.StudentId = #nStudentId
When #nStudentIds is available I can use 'IN' like so:
SR.StudentId IN (SELECT value FROM STRING_SPLIT #nStudentIds, ','))
The limitation of my knowledge of SQL shows in this IF, which obviously does not work:
AND (if(#nStudentId <> 0 AND #nStudentId <> -1 AND #nStudentId IS NULL)
SR.StudentId = #nStudentId;
else if(#nStudentIds IS NOT NULL)
SR.StudentId IN (SELECT value FROM STRING_SPLIT#nStudentIds,','))
)
Any suggestions are appreciated.
Thanks in advance.
Regards.
There's literally no need for 2 parameters here. Ideally, what you should be using is a table type parameter, as that maintains the strong typing. Then you can just JOIN to said table type parameter:
CREATE TYPE dbo.IDs AS table (ID bigint);
GO
CREATE PROC dbo.usp_GetStudentReferrals #ProfessorId bigint, #StudentIDs dbo.IDs READONLY AS
BEGIN
SELECT DISTINCT SR.StudentReferralId
FROM dbo.StudentReferral SR --WITH(NOLOCK) --Why are you using NOLOCK? You do know what it does, right?
INNER JOIN dbo.PotentialCandidate PC /*WITH(NOLOCK)*/ ON PC.PotentialCandidateId = SR.StudentId --Why are you using NOLOCK? You do know what it does, right?
INNER JOIN #StudentIDs S ON SR.StudentID = S.ID
WHERE SR.ProfessorId = #ProfessorId; --I assumed this should be #ProfessorId not #nProfessorId
END;
GO
Then you would call the procedure with something like:
DECLARE #ProfessorId bigint, #Students dbo.IDs;
SET #ProfessorId = 123456789;
INSERT INTO #Students (ID)
VALUES(987654321),(5643321987342);
EXEC dbo.usp_GetStudentReferrals #ProfessorId, #Students;
why don't you put IF before SELECT
BEGIN
if(#nStudentId <> 0 AND #nStudentId <> -1 AND #nStudentId IS NULL)
SELECT DISTINCT .....
else
SELECT DISTINCT .....
you can using split string from
link
and change this part
AND (if(#nStudentId <> 0 AND #nStudentId <> -1 AND #nStudentId IS NULL)
SR.StudentId = #nStudentId;
else if(#nStudentIds IS NOT NULL)
SR.StudentId IN (SELECT name FROM dbo.splitstring(#nStudentIds))
)

Invalid column name 'filter' error in SQL Server

I am getting an weird kind of error. I say weird because I don't understand why am I getting that error. I suppose there is syntax error but i don't exactly get what the error since it looks correct.
Error that I am getting is in a SQL Server Procedure that I have created. In the below procedure I am getting an error specifically in below part.
INSERT INTO agentids (filter, agentid)
SELECT
filter
,agentid
FROM selected_agents sa
WHERE sa.agentname = #p_agentname
AND sa.agentloginid = #p_agentloginid;
If I remove the above Insert Statement, I am able to compile the procedure. I understand that filter is in-build SQL Server variable but I have used it at other places in the procedure and it executes properly if I remove the Insert Statement part
Update Note: I missed mentioning this earlier, but if I execute this
procedure as it is "master" database it gets compiled successfully.
CREATE PROCEDURE [dbo].[getAgentLogActivity] #p_agentname NVARCHAR(50),
#p_agentloginid NVARCHAR(50),
#p_startTime DATETIME,
#p_endTime DATETIME
AS
BEGIN
DECLARE #l_event_login SMALLINT
DECLARE #l_event_logout SMALLINT
DECLARE #l_eventtype SMALLINT
DECLARE #l_reasoncode SMALLINT
DECLARE #l_agentid INT
DECLARE #l_eventdatetime DATETIME
DECLARE #l_filter BIT
DECLARE #l_mineventdatetime DATETIME
DECLARE #l_maxeventdatetime DATETIME
DECLARE #SWV_cursor_var1 CURSOR
SET #l_event_login = 1
SET #l_event_logout = 7
DELETE FROM agentids
INSERT INTO agentids (filter, agentid)
SELECT
filter
,agentid
FROM selected_agents sa
WHERE sa.agentname = #p_agentname
AND sa.agentloginid = #p_agentloginid;
DELETE FROM temp_asdr1
INSERT INTO temp_asdr1(agentid, eventtype, eventdatetime, reasoncode)
SELECT
asdr.agentid
,asdr.eventtype
,asdr.eventdatetime
,asdr.reasoncode
FROM
agentstatedetail asdr
,agentids ai
WHERE asdr.agentid = ai.agentid
AND asdr.eventdatetime BETWEEN #p_startTime AND #p_endTime
AND asdr.eventtype IN(#l_event_login,#l_event_logout)
UPDATE temp_asdr1
SET filter = (SELECT
filter
FROM agentids ai
WHERE ai.agentid = temp_asdr1.agentid)
DELETE FROM temp_asdr
--alter sequence temp_asdr_seq
SELECT
#l_mineventdatetime = min(eventdatetime)
,#l_maxeventdatetime = max(eventdatetime)
FROM temp_asdr1
WHERE filter = 1
EXECUTE dbo.sp_executesql 'l_mineventdatetime'
,#l_mineventdatetime
EXECUTE dbo.sp_executesql 'l_maxeventdatetime'
,#l_maxeventdatetime
IF ##rowcount = 0
BEGIN
SELECT
#l_mineventdatetime = NULL
,#l_maxeventdatetime = NULL
EXECUTE dbo.sp_executesql 'l_mineventdatetime'
,#l_mineventdatetime
EXECUTE dbo.sp_executesql 'l_maxeventdatetime'
,#l_maxeventdatetime
END
DELETE FROM temp_asdr1
WHERE ((eventdatetime <= l_mineventdatetime)
OR (eventdatetime >= #l_maxeventdatetime))
AND filter = 0
SET #SWV_cursor_var1 = CURSOR FOR
SELECT
agentid,
eventtype,
eventdatetime,
reasoncode,
filter
FROM temp_asdr1
ORDER BY eventdatetime
OPEN #SWV_cursor_var1
FETCH NEXT FROM #SWV_cursor_var1 INTO #l_agentid, #l_eventtype, #l_eventdatetime, #l_reasoncode, #l_filter
WHILE ##FETCH_STATUS = 0
BEGIN
-- WARNING: The INSERT statement was commented, because column name or number of supplied values does not match table definition.
-- insert into temp_asdr(agentid, eventtype, eventdatetime, reasoncode, filter) values(temp_asdr_seq.nextval,l_agentid, l_eventtype, l_eventdatetime, l_reasoncode, l_filter);
FETCH NEXT FROM #SWV_cursor_var1 INTO #l_agentid, #l_eventtype, #l_eventdatetime, #l_reasoncode, #l_filter
END
CLOSE #SWV_cursor_var1
DELETE FROM temp_asdr1
SELECT TOP 1
#l_eventtype = eventtype,
#l_eventdatetime = eventdatetime,
#l_reasoncode = reasoncode,
#l_filter = filter
FROM temp_asdr
WHERE eventdatetime = (SELECT
MIN(eventdatetime)
FROM temp_asdr)
IF ##rowcount = 0
SELECT
#l_eventtype = NULL,
#l_eventdatetime = NULL,
#l_reasoncode = NULL,
#l_filter = NULL
DELETE FROM temp_login_logout
IF (#l_eventtype = #l_event_logout)
INSERT INTO temp_login_logout (seq, logintime, op1, logouttime, reasoncode, loginfilter, logoutfilter)
VALUES (0, NULL, '<', #l_eventdatetime, NULL, #l_filter, #l_filter)
INSERT INTO temp_login_logout (seq, logintime, loginfilter)
SELECT
seq,
eventdatetime,
filter
FROM temp_asdr tasdr
WHERE eventtype = #l_event_login
UPDATE temp_login_logout
SET logouttime = (SELECT
eventdatetime
FROM temp_asdr tasdr
WHERE tasdr.eventtype = #l_event_logout
AND tasdr.seq = (temp_login_logout.seq + 1)),
logoutfilter = (SELECT
filter
FROM temp_asdr tasdr
WHERE tasdr.eventtype = #l_event_logout
AND tasdr.seq = (temp_login_logout.seq + 1)),
reasoncode = (SELECT
reasoncode
FROM temp_asdr tasdr
WHERE tasdr.eventtype = #l_event_logout
AND tasdr.seq = (temp_login_logout.seq + 1))
UPDATE temp_login_logout
SET logouttime = #p_endTime,
op2 = '>',
logoutfilter = 0
WHERE logouttime IS NULL
UPDATE temp_login_logout
SET logintime = NULL,
op1 = '<',
reasoncode = NULL
WHERE loginfilter = 0
AND logoutfilter = 1
UPDATE temp_login_logout
SET logouttime = NULL,
op2 = '>',
reasoncode = NULL
WHERE loginfilter = 1
AND logoutfilter = 0
DELETE FROM temp_login_logout
WHERE loginfilter = 0
AND logoutfilter = 0
UPDATE temp_login_logout
SET duration = dbo.datediff('ss', logintime, logouttime)
END
Can someone please help with this error.
I guess, I have understood an issue with this.
May be its a glitch or something. But here what I did was deleted the function created where I had this table variable created. And then created the Stored Procedure first and then created function.
I was able to successfully compiled.

SQL CASE wrong output

I have this weird encounter using CASE in sql 2014.
This is my query:
SELECT (CASE WHEN dbo.GetFunctionAge(C.Birthdate) = 0
THEN '' ELSE dbo.GetFunctionAge(C.Birthdate)
END) AS Age
,dbo.GetFunctionAge(C.Birthdate)
,c.Birthdate
FROM Client C
WHERE ClientID = '34d0d845-e3a6-4078-8936-953ff3378eac'
this is the output:
Here is the GetFunctionAge function if you might ask.
IF EXISTS (
SELECT *
FROM dbo.sysobjects
WHERE ID = OBJECT_ID(N'[dbo].[GetFunctionAge]') AND
xtype in (N'FN', N'IF', N'TF'))
DROP FUNCTION [dbo].[GetFunctionAge]
GO
CREATE FUNCTION [dbo].[GetFunctionAge](#BirthDate DATETIME)
RETURNS INT
AS
BEGIN
DECLARE #Age INT
IF(#BirthDate = '1753-01-01 00:00:00.000')
BEGIN
SET #Age = 0
END
ELSE
BEGIN
SET #Age = DATEDIFF(hour,#BirthDate,GETDATE())/8766
END
RETURN #Age
END
GO
Question:
Why is Column Age in my output is 0which should be ''?
I added (No column name) to show that its output is 0 so my expected output base from my case condition is '' not 0
I didn't receive any error regarding inconsistency of data so why is case behaving like that?
Thanks for those who could clarify this to me.
SELECT
(CASE
WHEN a.ageint = 0 THEN ''
ELSE cast(a.ageint as varchar(3))
END) AS Age
, a.ageint
, c.Birthdate
FROM Client as C
CROSS APPLY (
SELECT
ISNULL(dbo.GetFunctionAge(C.Birthdate), 0) AS ageint
) AS a
WHERE ClientID = '34d0d845-e3a6-4078-8936-953ff3378eac'
;
You can cast it into varchar so you can return ' '.
SELECT (CASE WHEN dbo.GetFunctionAge(C.Birthdate) = 0
THEN '' ELSE Cast(dbo.GetFunctionAge(C.Birthdate) as varchar(5))
END) AS Age
,dbo.GetFunctionAge(C.Birthdate)
,c.Birthdate
FROM Client C
WHERE ClientID = '34d0d845-e3a6-4078-8936-953ff3378eac'
But If you wish to remain your Age column in data type int.
You could just use NULL instead of ' '

Stored Procedure to check the existence of email in tables

I am new to SQL stored procedures. I need to write a SQL to check a email exists in multiple tables. If a email contains in First Table it returns true and should not execute the rest. Like wise if not I need to check the second table and if i found return true. Finally if i found in last Table I need to return true and else i need to return false.
I am stuck in achieving this. I tried like this. Gives me syntax errors. Please share me a solution for this.
USE Users_UserDetials;
GO
CREATE PROCEDURE Users.GetUserPermissions
#userEmail nvarchar(50),
#areaId nvarchar(10),
#villageCode nvarchar(10)
AS
SET NOCOUNT ON;
IF EXISTS (SELECT 1 FROM Users.GlobalUsers AS GU
WHERE GU.UserEmail = #userEmail)
ELSE
IF EXISTS (SELECT 1 FROM Users.AreaSpecificUsers AS AU
WHERE AU.UserEmail = #userEmail)
ELSE
IF EXISTS (SELECT 1 FROM Users.VillageSpecificUsers AS VU
WHERE VU.UserEmail = #userEmail)
ELSE
'0'
GO
USE Users_UserDetials;
GO
CREATE PROCEDURE Users.GetUserPermissions
#userEmail nvarchar(50),
#areaId nvarchar(10),
#villageCode nvarchar(10)
AS
SET NOCOUNT ON;
IF EXISTS (SELECT 1 FROM Users.GlobalUsers AS GU
WHERE GU.UserEmail = #userEmail)
BEGIN
SELECT 1
END
ELSE
IF EXISTS (SELECT 1 FROM Users.AreaSpecificUsers AS AU
WHERE AU.UserEmail = #userEmail)
BEGIN
SELECT 1
END
ELSE
IF EXISTS (SELECT 1 FROM Users.VillageSpecificUsers AS VU
WHERE VU.UserEmail = #userEmail)
BEGIN
SELECT 1
END
ELSE
BEGIN
SELECT 0
END
END

Less expensive query?

I have a stored procedure that returns an integer 1 or 0 depending on specific criteria. It currently uses three select statements and it will be used heavily by multiple users across multiple locations. There has to be a more efficient way of doing this.
In short the query checks first to see if all checklist items on an order are completed (a separate table), then it checks to see if a field named BreakOutGuest (a bit field) is a 1 or 0. Depending on that result it checks to see if the total guest count is greater than 0 and the order total is zero. It returns the one or zero on all this criteria. Is there a more efficient way to do this? A temp table so I only have to hit the actual tables once? Below is the code.
#ORDERID INT
AS
BEGIN
DECLARE #AUTO_CLOSE INT
SET NOCOUNT ON;
--If all checklist items are marked complete move on, if not set #AUTO_CLOSE=0
IF NOT EXISTS(SELECT ORDERID FROM dbo.orderchecklistitems WHERE OrderID=#ORDERID AND CompletedON IS NULL)
BEGIN
--if BreakOutGuestFees is 1 only sum Guest_Count_1 + Guest_Count_2
IF EXISTS(SELECT * FROM dbo.Orders WHERE (GuestCount_1 + GuestCount_2)>1 AND OrderTotal=0 AND BreakoutGuestFees=1)
BEGIN
SET #AUTO_CLOSE=1
END
ELSE
SET #AUTO_CLOSE=0
--if BreakOutGuestFees is 0 only consider Guest_Count_1
IF EXISTS(SELECT * FROM dbo.Orders WHERE (GuestCount_1)>1 AND OrderTotal=0 AND BreakoutGuestFees=0)
BEGIN
SET #AUTO_CLOSE=1
END
ELSE
SET #AUTO_CLOSE=0
END
ELSE
SET #AUTO_CLOSE=0
END
If am not wrong you can combine two if clause into single if clause by using AND , OR logic. Try this.
IF NOT EXISTS(SELECT ORDERID
FROM dbo.orderchecklistitems
WHERE OrderID = #ORDERID
AND CompletedON IS NULL)
BEGIN
IF EXISTS(SELECT *
FROM dbo.Orders
WHERE ( ( GuestCount_1 + GuestCount_2 > 1
AND BreakoutGuestFees = 1 )
OR ( BreakoutGuestFees = 0
AND GuestCount_1 > 1 ) )
AND OrderTotal = 0
AND OrderID = #ORDERID)
SET #AUTO_CLOSE=1
ELSE
SET #AUTO_CLOSE=0
END
ELSE
SET #AUTO_CLOSE=0
You can perform your selection check with only one query
SELECT
(SELECT sum(1) FROM dual WHERE EXISTS (SELECT ORDERID FROM dbo.orderchecklistitems WHERE OrderID=#ORDERID AND CompletedON IS NULL)),
(SELECT sum(1) FROM dual WHERE EXISTS (SELECT 1 FROM dbo.Orders WHERE (GuestCount_1 + GuestCount_2)>1 AND OrderTotal=0 AND BreakoutGuestFees=1)),
(SELECT sum(1) FROM dual WHERE EXISTS (SELECT 1 FROM dbo.Orders WHERE (GuestCount_1)>1 AND OrderTotal=0 AND BreakoutGuestFees=0))
INTO
result1, result2, result3
from dual
then check results
DELCARE #AUTO_CLOSE INT = 0
IF NOT EXISTS(SELECT ORDERID
FROM dbo.orderchecklistitems
WHERE OrderID = #ORDERID
AND CompletedON IS NULL)
BEGIN
SET #AUTO_CLOSE =
(
SELECT
CASE
WHEN (GuestCount_1 + GuestCount_2 > 1) AND BreakoutGuestFees = 0 THEN 1
WHEN (GuestCount_1 > 1 ) AND BreakoutGuestFees = 1 THEN 1
ELSE 0 END
FROM dbo.orders
WHERE OrderTotal = 0 AND OrderID = #orderID
)
END