Why doesn't a where condition work correctly? - sql

I have this procedure and it should return records based on give dates and few other inputs. First it places a branch_ID in a temp table #branches and then pick that branch_ID from temp table but it returns records for all branches not only for the one that has been picked. Why ? But when i put static Branch_ID i.e. 3 then it picks for that.
ALTER PROCEDURE [dbo].[usp_RejectedFiles]
(
#FromDate SMALLDATETIME,
#ToDate SMALLDATETIME,
#OfficeID INT=0,
#Type INT=0
)
AS
BEGIN
DECLARE #Branches TABLE
(
BranchID INT
)
IF #Type = 1
BEGIN
INSERT INTO #Branches SELECT BranchID From vw_OrganizationTree WHERE OrganizationID = #OfficeID
END
IF #Type = 2
BEGIN
INSERT INTO #Branches SELECT BranchID From vw_OrganizationTree WHERE CompanyID = #OfficeID
END
IF #Type = 3
BEGIN
INSERT INTO #Branches SELECT BranchID From vw_OrganizationTree WHERE BranchID = #OfficeID
END
SELECT C.CompanyName,B.BranchName,E.EmployerName,FE.EmployeeUniqueID,pcr.EmployerUniqueID,
FE.IncomeFixedComponent,FE.IncomeVariableComponent,
S.StatusDescription, FE.IsRejected, FE.ID 'EdrID'
From File_EdrEntries FE JOIN PAFFiles pe ON pe.ID = FE.PAFFile_ID
inner join File_PCREntries pcr on pe.ID=pcr.PAFFile_ID
JOIN Employers E ON E.EmployerID = pcr.EmployerUniqueID
JOIN Branches B ON B.BranchID = E.Branch_ID JOIN companies C ON C.COMPANYID = B.COMPANY_ID
JOIN Statuses S ON S.StatusID = FE.Status_ID
where fe.IsRejected=1
AND E.Branch_id = (Select Branch_ID from #Branches)
END

Note :Please confirm that it is not typo
The Problem with the column Name i.e Column Name declare in #Branches table is different than the used in where clause.
Column Name in #Branches table
DECLARE #Branches TABLE
(
BranchID INT
)
And in where clause
...
AND E.Branch_id = (Select Branch_ID from #Branches)
There may be possibility that #Branches table may have multiple rows so instead of comparing equality you should use IN of EXISTS
AND E.Branch_id IN (Select BranchID from #Branches)

Rather than using this temp table, you should be able to compose everything into a single query:
...
JOIN Statuses S ON S.StatusID = FE.Status_ID
where fe.IsRejected=1
AND EXISTS (
SELECT * FROM vw_OrganizationTree v
WHERE v.BranchID = e.BranchID AND
(#Type = 1 and v.OrganizationID = #OfficeID) or
(#Type = 2 and v.CompanyID = #OfficeID) or
(#Type = 3 and v.BranchID = #OfficeID)
)
And as JaydipJ alludes to, the reason why your current code isn't working is because here:
AND E.Branch_id = (Select Branch_ID from #Branches)
There is no column called Branch_ID in the #Branches table. So it becomes a reference to a column in the outer query (if there were more than one such column, it would generate an error). And so it has effectively become:
AND E.Branch_id = E.Branch_ID
Which is why it returns all rows. This is why it's always a good idea to use prefixed column names when using subqueries. This:
AND E.Branch_id = (Select x.Branch_ID from #Branches x)
Would have generated an error about a non-existent column and given a clue to why it wasn't working.

Related

SQL - After insert Same Table

So I understand recursive triggers. Got to be careful of deadlocks etc. However this is only after an insert not after insert and update. Also, I have an audit trigger table that I am updating to make sure all is well. And querying after to double check. All looks fine but no update happens.
if exists (select 'a' from sys.triggers where name = 'invoicememologic')
begin
drop trigger invoicememologic
end
go
create trigger invoicememologic
on transactiontable
after insert
as
begin
declare #inum varchar(1000)
select #inum = min(transactioninvnum)
from
(select transactioninvnum
from inserted i
inner join project p on left(i.projectid, charindex(':', i.projectid)) = p.projectid
where right(i.projectid, 1) <> ':'
and abs(p.UseProjectMemoOnInv) = 1
group by transactioninvnum) b
while #inum is not null
begin
declare #rCount int
select #rCount = count(*)
from transactiontable
where TransactionInvNum = #inum
if #rCount = 1
begin
declare #tid varchar(100)
select #tid = transactionid
from transactiontable
where TransactionInvNum = #inum
declare #pmemo varchar(MAX)
select #pmemo = p.projectMemo
from transactiontable tt
inner join project p on left(tt.projectid, charindex(':', tt.projectid)) = p.projectid
where transactionInvNum = #inum
insert into audittrigger
values (#pmemo, #tid)
update transactiontable
set transactionmemo2 = #pmemo
where ltrim(rtrim(transactionid)) = ltrim(rtrim(#tid))
end
select #inum = min(transactioninvnum)
from
(select transactioninvnum
from inserted i
inner join project p on left(i.projectid, charindex(':', i.projectid)) = p.projectid
where abs(transactionjointinv) = 1
and right(i.projectid, 1) <> ':'
and abs(p.UseProjectMemoOnInv) = 1
group by transactioninvnum ) a
where transactioninvnum > #inum
end
end
Reason for trigger. 1 Invoice can be multiple rows in the database. 3 rows. So it only should update any one of the 3 rows. Doesn't matter. And it must grab the memo from the parent project of the phases that are being inserted into the database. hence the inner join on the left with charindex.
So I check the audit table. All looks well there. MEMO is there and the transactionid is there. I query after the trigger fires. TransactionID exists in the transactiontable but the memo2 is not being updated.
TransactionMemo2 is type of ntext. I thought it might be varchar with a direct update command will fail. I tried to update manually through setting a var as the text string and call the update manually with the transactionid being required. all worked fine. I am lost

Stored procedure for finding out if student is eligible for course with pre reqs

I have this stored procedure for a course registration system I am working on. My intention is to return a value of -1 if the query returns a course which a student has not taken according to the course pre requisites.
The pre req table only has two columns; CourseID being the course and PreReqCourse_ID being the required course for that specified course. If the student has taken all pre req courses then it should return a value of 1. I keep getting a value of -1 even when I run the query for a student who has taken the required pre req courses. Any help would be much appreciated!
CREATE PROCEDURE CheckPreReq
#StudentID INT,
#CourseID INT
AS
DECLARE #theCount INT
IF EXISTS (SELECT *
FROM PreReq
INNER JOIN Student_History ON (PreReq.Course_ID = #CourseID)
WHERE Student_History.Course_ID != PreReq.PreReqCourse_ID
AND Student_History.Student_ID = #StudentID)
BEGIN
SET #theCount =-1
END
ELSE
BEGIN
SET #theCount = 1
END
RETURN #theCount
Would something like this work?
DECLARE #PreReqsTotal tinyint
DECLARE #PreReqsFulfilled tinyint
-- Count pre-req courses.
SELECT #PreReqsTotal = COUNT(*)
FROM PreReq
WHERE [CourseID] = #CourseId
-- Count how many fulfilled by student.
SELECT #PreReqsFulfilled = count(*)
FROM Student_History hist
JOIN PreReq pre
on hist.Course_ID = pre.PreReqCourse_ID
WHERE pre.CourseID = #CourseID
and hist.Student_ID = #StudentID
RETURN CASE WHEN #PreReqsTotal = #PreReqsFulfilled THEN 1 ELSE -1 END
...or something like this:
IF EXISTS
(
SELECT blah.*
FROM
(
SELECT pre.*
,[PreFulfilled] = CASE WHEN hist.Course_ID is null THEN 0 ELSE 1 END
FROM PreReq pre
LEFT JOIN
Student_History hist
on pre.PreReqCourse_ID = hist.Course_ID
and hist.Student_ID = #StudentID
WHERE pre.CourseID = #CourseID
) blah
WHERE blah.[PreFulfilled] = 0 -- Unfulfilled PreReq.
)
BEGIN
RETURN -1 -- Has an unfulfilled PreReq.
END
RETURN 1 -- No unfulfilled PreReqs.
You should JOIN the PreReq table with the Student_History on the the PreReq.PreReqCourse_ID and Student_History.CourseID columns (take a look at my example). Then your SP should work.
--create tmp example tables
IF OBJECT_ID('tempdb..#PreReq') IS NOT NULL DROP TABLE #PreReq
CREATE TABLE #PreReq(
CourseID int,
PreReqCourse_ID int
)
--insert Course 3 which depends on Course 2 and 1 in #PreReq
INSERT INTO #PreReq
values(3,2),(3,1)
IF OBJECT_ID('tempdb..#Student_History') IS NOT NULL DROP TABLE #Student_History
CREATE TABLE #Student_History(
CourseID int not null,
StudentID int not null
);
--insert Student 1 who has visited Course 1 and 2
insert into #Student_History
VALUES(1,1),(2,1)
--declare variables
DECLARE #CourseID AS INT = 3
,#StudentID AS INT = 1
--COUNT on how many Courses #CourseID depends
,#necessaryCourses AS INT
--COUNT on how many Courses the Student has taken
,#countTakenCourses AS INT
,#theCount AS INT
SET #necessaryCourses = (SELECT count(*) FROM #PreReq WHERE CourseID = #CourseID);
SET #countTakenCourses = (
SELECT count(*)
FROM #PreReq p
--JOIN with Student_History to check if the student has visited the necessary course
JOIN #Student_History h on p.PreReqCourse_ID = h.CourseID
WHERE p.CourseID = #CourseID AND h.StudentID = #StudentID
)
IF #necessaryCourses = #countTakenCourses
BEGIN
set #theCount = 1
END
ELSE
BEGIN
set #theCount = -1
END
SELECT #theCount AS theCount

Why my query isn't showing correct results?

I have many tables but for instance let's consider 2 tables i.e. Employees and FileEntries. I am picking these fields from both tables EmployeeID,FileStatus,FileName,EmployeeName.
These both tables have 1 common field i.e. EmployeeID. FileEntries can have EmployeeID being present even if it's not in Employees table. So i want to pick all records from both tables but a new field should show 'NotRegistered' if it is not in Employees table.
)
#EmployeeID int
)
Alter PROCEDURE [dbo].[Modify_RejectedFiles] -- '2015-01-06 07:41:00', '2015-01-06 07:41:00',1,3,'','20001018783815'
(
#FromDate SMALLDATETIME,
#ToDate SMALLDATETIME,
#OfficeID INT=0, --it represents id of a company/branch/organization being logged in
#Type INT=0, --it represents type of a user being logged in i.e. 1=orgranization, 2=company, 3=branch
#EmployerUniqueID VARCHAR(15)='',
#EmployeeUniqueID VARCHAR(15)=''
)
AS
BEGIN
DECLARE #Branches TABLE
(
BranchID INT
)
IF #Type = 1 --Organization
BEGIN
INSERT INTO #Branches
SELECT BranchID From vw_OrganizationTree WHERE OrganizationID = #OfficeID --inserts 3 always because we got only 1 organization i.e. 3
END
IF #Type = 2 --Company
BEGIN
INSERT INTO #Branches
SELECT BranchID From vw_OrganizationTree WHERE CompanyID = #OfficeID --inserts 3 always because we got only 1 company i.e. 3
END
IF #Type = 3 -- i.e. Branch
BEGIN
INSERT INTO #Branches
SELECT BranchID From vw_OrganizationTree WHERE BranchID = #OfficeID
END
Declare #IsRegistered varchar(20)= 'Registered'
If ((Select count(*) from RegisteredEmployees where EmployeeUniqueID= #EmployeeUniqueID) <1)
Begin
Set #IsRegistered = 'Not Yet'
End
Select distinct FE.EmployeeUniqueID, RE.EmployeeName, Empr.EmployerName, Br.BranchName,
FE.IsRejected, FE.RejectedFileCreationDateTime
From
File_EDREntries FE
left Join
RegisteredEmployees RE
ON FE.EmployeeUniqueID = RE.EmployeeUniqueID
left Join Employers Empr
ON RE.Employer_ID = Empr.ID
left Join Branches Br
ON Br.BranchID = Empr.Branch_ID
WHERE
FE.IsRejected = 1 --20017128203780
AND Empr.Branch_ID in (Select BranchID from #Branches)
Use Case when RE.EmployeeUniqueID is null then 'Not Yet' else 'Registered' End in your final select Query

SQL WHERE ... IN clause with possibly null parameter

I am having some problems with my WHERE clause (using SQL 2008) . I have to create a stored procedure that returns a list of results based on 7 parameters, some of which may be null. The ones which are problematic are #elements, #categories and #edu_id. They can be a list of ids, or they can be null. You can see in my where clause that my particular code works if the parameters are not null. I'm not sure how to code the sql if they are null. The fields are INT in the database.
I hope my question is clear enough. Here is my query below.
BEGIN
DECLARE #elements nvarchar(30)
DECLARE #jobtype_id INT
DECLARE #edu_id nvarchar(30)
DECLARE #categories nvarchar(30)
DECLARE #full_part bit
DECLARE #in_demand bit
DECLARE #lang char(2)
SET #jobtype_id = null
SET #lang = 'en'
SET #full_part = null -- full = 1, part = 0
SET #elements = '1,2,3'
SET #categories = '1,2,3'
SET #edu_id = '3,4,5'
select
jobs.name_en,
parttime.fulltime_only,
jc.cat_id category,
je.element_id elem,
jt.name_en jobtype,
jobs.edu_id minEdu,
education.name_en edu
from jobs
left join job_categories jc
on (jobs.job_id = jc.job_id)
left join job_elements je
on (jobs.job_id = je.job_id)
left join job_type jt
on (jobs.jobtype_id = jt.jobtype_id)
left join education
on (jobs.edu_id = education.edu_id)
left join
(select job_id, case when (jobs.parttime_en IS NULL OR jobs.parttime_en = '') then 1 else 0 end fulltime_only from jobs) as parttime
on jobs.job_id = parttime.job_id
where [disabled] = 0
and jobs.jobtype_id = isnull(#jobtype_id,jobs.jobtype_id)
and fulltime_only = isnull(#full_part,fulltime_only)
-- each of the following clauses should be validated to see if the parameter is null
-- if it is, the clause should not be used, or the SELECT * FROM ListToInt... should be replaced by
-- the field evaluated: ie if #elements is null, je.element_id in (je.element_id)
and je.element_id IN (SELECT * FROM ListToInt(#elements,','))
and jc.cat_id IN (SELECT * FROM ListToInt(#categories,','))
and education.edu_id IN (SELECT * FROM ListToInt(#edu_id,','))
order by case when #lang='fr' then jobs.name_fr else jobs.name_en end;
END
Something like
and (#elements IS NULL OR je.element_id IN
(SELECT * FROM ListToInt(#elements,',')))
and (#categories IS NULL OR
jc.cat_id IN (SELECT * FROM ListToInt(#categories,',')))
....
should do the trick
je.element_id IN (SELECT * FROM ListToInt(#elements,',')) OR #elements IS NULL
that way for each one
Have you tried explicitly comparing to NULL?
and (#elements is null or je.element_id IN (SELECT * FROM ListToInt(#elements,','))
And so on.

SQL Server Update trigger for bulk updates

Below is a SQL Server 2005 update trigger. For every update on the email_subscriberList table where the isActive flag changes we insert an audit record into the email_Events table. This works fine for single updates but for bulk updates only the last updated row is recorded. How do I convert the below code to perform an insert for every row updated?
CREATE TRIGGER [dbo].[Email_SubscriberList_UpdateEmailEventsForUpdate_TRG]
ON [dbo].[Email_subscriberList]
FOR UPDATE
AS
DECLARE #CustomerId int
DECLARE #internalId int
DECLARE #oldIsActive bit
DECLARE #newIsActive bit
DECLARE #email_address varchar(255)
DECLARE #mailinglist_name varchar(255)
DECLARE #email_event_type varchar(1)
SELECT #oldIsActive = isActive from Deleted
SELECT #newIsActive = isActive from Inserted
IF #oldIsActive <> #newIsActive
BEGIN
IF #newIsActive = 1
BEGIN
SELECT #email_event_type = 'S'
END
ELSE
BEGIN
SELECT #email_event_type = 'U'
END
SELECT #CustomerId = customerid from Inserted
SELECT #internalId = internalId from Inserted
SELECT #email_address = (select email from customer where customerid = #CustomerId)
SELECT #mailinglist_name = (select listDescription from Email_lists where internalId = #internalId)
INSERT INTO Email_Events
(mailshot_id, date, email_address, email_event_type, mailinglist_name)
VALUES
(#internalId, getDate(), #email_address, #email_event_type,#mailinglist_name)
END
example
untested
CREATE TRIGGER [dbo].[Email_SubscriberList_UpdateEmailEventsForUpdate_TRG]
ON [dbo].[Email_subscriberList]
FOR UPDATE
AS
INSERT INTO Email_Events
(mailshot_id, date, email_address, email_event_type, mailinglist_name)
SELECT i.internalId,getDate(),c.email,
case i.isActive when 1 then 'S' else 'U' end,e.listDescription
from Inserted i
join deleted d on i.customerid = d.customerid
and i.isActive <> d.isActive
join customer c on i.customerid = c.customerid
join Email_lists e on e.internalId = i.internalId
Left outer joins, for in case there are no related entries in customer or email_Lists (as is possible in the current code) -- make them inner joins if you know there will be data present (i.e. foreign keys are in place).
CREATE TRIGGER [dbo].[Email_SubscriberList_UpdateEmailEventsForUpdate_TRG]
ON [dbo].[Email_subscriberList]
FOR UPDATE
AS
INSERT INTO Email_Events
(mailshot_id, date, email_address, email_event_type, mailinglist_name)
select
i.InternalId
,getdate()
,cu.Email
,case i.IsaActive
when 1 then 'S'
else 'U'
end
,el.ListDescription
from inserted i
inner join deleted d
on i.CustomerId = d.CustomerId
and i.IsActive <> d.IsActive
left outer join Customer cu
on cu.CustomerId = i.CustomerId
left outer join Email_Lists el
on el.InternalId = i.InternalId
Test it well, especially for concurrency issues. Those joins within the trigger make me nervous.