Comparing data between two tables without except operator when having null values in fields - sql

I have this query in SQL Server which will give me the difference between two tables
SELECT * FROM dbo.emp
except
SELECT * FROM #temp1
and I get the proper result with only one record (which is correct)
But when I use a left outer join
SELECT emp.* FROM emp
LEFT JOIN #temp1 ON emp.empid = #temp1.empid
and
emp.firstname = #temp1.firstname
AND emp.lastname = #temp1.lastname
and emp.salary = #temp1.salary
and emp.dob = #temp1.dob
WHERE #temp1.empid IS NULL;
I get 39 records. Why the difference? I have mentioned all the columns in my join condition.
I know how to do this via where clause but my intention is to learn why the outer join is not working. Basically what is it that I am doing wrong
The below code works
SELECT dbo.emp.* FROM dbo.emp
JOIN #temp1 ON emp.empid = #temp1.empid
where
emp.firstname <> #temp1.firstname
or emp.lastname <> #temp1.lastname
or emp.salary <> #temp1.salary
or emp.dob <> #temp1.dob;

The outer join is presumably not working because some of the fields have NULL values.
You can emulate the except using union all and group by:
SELECT emp.*
FROM ((select 'emp' as which, empid, firstname, lastname, salary, dob
from emp
) union all
(select 'temp', empid, firstname, lastname, salary, dob
from #temp1
)
) t
group by empid, firstname, lastname, salary, dob
having sum(case when which = 'temp' then 1 else 0 end) = 0;
EDIT:
You can do this with a join using more complex conditions:
SELECT emp.*
FROM emp LEFT JOIN
#temp1
ON (emp.empid = #temp1.empid or coalesce(emp.empid, #temp1.empid) is null) and
(emp.firstname = #temp1.firstname or coalesce(emp.firstname, #temp1.firstname) is null) and
(emp.lastname = #temp1.lastname or coalesce(emp.lastname, #temp1.lastname) is null) and
(emp.salary = #temp1.salary or coalesce(emp.salary, #temp1.salary) is null) and
(emp.dob = #temp1.dob or or coalesce(emp.dob, #temp1.dob ) is null)
WHERE #temp1.empid IS NULL;

Related

adding alias name in where condition of sql query

I have a query like this
SELECT
employee_tbl.emp_maxid,
emp_name AS 'Employee Name',
Designation_tbl.Des_Name AS Designation,
emp_LabourID,
emp_IBAN,
emp_monthlysalary AS Salary,
0 AS commission,
ISNULL(emp_monthlysalary - sum(S.Paid), emp_monthlysalary) AS Total
FROM dbo.employee_tbl
INNER JOIN dbo.Designation_tbl
ON Designation_tbl.Des_id = employee_tbl.Des_id
LEFT JOIN SalaryProcessLog_tbl S
ON S.emp_maxid = employee_tbl.emp_maxid
WHERE (emp_deleted = 0
OR emp_deleted IS NULL)
AND employee_tbl.emp_maxid NOT IN (SELECT
emp_maxid
FROM SalaryProcessLog_tbl
WHERE Balance = 0)
group by employee_tbl.emp_maxid,dbo.employee_tbl.emp_name,Designation_tbl.Des_Name,
employee_tbl.emp_LabourID, emp_IBAN,emp_monthlysalary
my out put getting like this
in my query i want to add filter result by
Where Total <> 0.. how i can do the same?
Any help is very appriciable
Wrap your query up in a derived table. Add Total condition to outer query's WHERE.
select *
from
(
SELECT
employee_tbl.emp_maxid,
emp_name AS 'Employee Name',
Designation_tbl.Des_Name AS Designation,
emp_LabourID,
emp_IBAN,
emp_monthlysalary AS Salary,
0 AS commission,
ISNULL(emp_monthlysalary - sum(S.Paid), emp_monthlysalary) AS Total
FROM dbo.employee_tbl
INNER JOIN dbo.Designation_tbl
ON Designation_tbl.Des_id = employee_tbl.Des_id
LEFT JOIN SalaryProcessLog_tbl S
ON S.emp_maxid = employee_tbl.emp_maxid
WHERE (emp_deleted = 0
OR emp_deleted IS NULL)
AND employee_tbl.emp_maxid NOT IN (SELECT
emp_maxid
FROM SalaryProcessLog_tbl
WHERE Balance = 0)
group by employee_tbl.emp_maxid,dbo.employee_tbl.emp_name,Designation_tbl.Des_Name,
employee_tbl.emp_LabourID, emp_IBAN,emp_monthlysalary
) dt
WHERE Total <> 0
To filter grouping results you should use HAVING.
SELECT
employee_tbl.emp_maxid,
emp_name AS 'Employee Name',
Designation_tbl.Des_Name AS Designation,
emp_LabourID,
emp_IBAN,
emp_monthlysalary AS Salary,
0 AS commission,
ISNULL(emp_monthlysalary - sum(S.Paid), emp_monthlysalary) AS Total
FROM dbo.employee_tbl
INNER JOIN dbo.Designation_tbl
ON Designation_tbl.Des_id = employee_tbl.Des_id
LEFT JOIN SalaryProcessLog_tbl S
ON S.emp_maxid = employee_tbl.emp_maxid
WHERE (emp_deleted = 0
OR emp_deleted IS NULL)
AND employee_tbl.emp_maxid NOT IN (SELECT
emp_maxid
FROM SalaryProcessLog_tbl
WHERE Balance = 0)
group by employee_tbl.emp_maxid,dbo.employee_tbl.emp_name,Designation_tbl.Des_Name,
employee_tbl.emp_LabourID, emp_IBAN,emp_monthlysalary
HAVING
ISNULL(emp_monthlysalary - sum(S.Paid), emp_monthlysalary) <> 0

How to write one CASE function two THEN method at the same time END AS Two NEW column depend on THEN action

SELECT Emp.IntegrationFieldOne AS LocationCode, Emp.EmployeeId,
Emp.FirstName + ' '+ Emp.LastName as 'EmployeeName',
CASE WHEN ( (ORSet.Rate) =1.5 ) THEN
Sum(OT.Minutes)
END AS '1.5HRSMinutes',
CASE WHEN( ORSet.Rate =2 ) THEN
Sum(OT.Minutes)
END AS '2HRSMinutes'
FROM [CemexDB_CP_Test].[TimeAttendance].[OvertimeTransaction] OT
INNER JOIN [HumanResource].[Employee] Emp ON OT.EmployeeId = Emp.EmployeeId
INNER JOIN [CemexDB_CP_Test].[TimeAttendance].[OvertimeRateSettingDetail]
ORSet ON ORSet.OvertimeRateSettingId= OT.OvertimeType
GROUP BY Emp.EmployeeId,Emp.FirstName,Emp.LastName,Emp.IntegrationFieldOne,ORSet.Rate[!
This is Output picture click it]1
This is the out put but i want same row depend same id. but here each id has 2
row how to handle it
I think you want conditional aggregation:
SELECT Emp.IntegrationFieldOne AS LocationCode, Emp.EmployeeId,
Emp.FirstName + ' '+ Emp.LastName as EmployeeName,
SUM(CASE WHEN ORSet.Rate = 1.5 THEN OT.Minutes END) AS [1.5HRSMinutes],
SUM(CASE WHEN ORSet.Rate = 2 THEN OT.Minutes END) AS [2HRSMinutes]
FROM [CemexDB_CP_Test].[TimeAttendance].[OvertimeTransaction] OT INNER JOIN
[HumanResource].[Employee] Emp
ON OT.EmployeeId = Emp.EmployeeId INNER JOIN
[CemexDB_CP_Test].[TimeAttendance].[OvertimeRateSettingDetail]
ORSet
ON ORSet.OvertimeRateSettingId= OT.OvertimeType
GROUP BY Emp.EmployeeId, Emp.FirstName, Emp.LastName, Emp.IntegrationFieldOne;

count after join on multiple tables and count of multiple column values

Please help me with below problem.
table 1 employee details
emp name empno.
---------------------------------
John 1234
Joe 6789
table 2 employee assignment
empno assignmentstartdate assignmentenddate assignmentID empassignmentID
-----------------------------------------------------------------------------
1234 01JAN2017 02JAN2017 A1 X1
6789 01jan2017 02JAN2017 B1 Z1
table 3 employee assignment property
empassignmentID assignmentID propertyname propertyvalue
-------------------------------------------------------------------
X1 A1 COMPLETED true
X1 A1 STARTED true
Z1 B1 STARTED true
Z1 B1 COMPLETED false
Result wanted: (count of completed and started for each employee)
emp name emp no. COMPLETED STARTED
------------------------------------------
John 1234 1 1
Joe 6789 0 1
Currently with my query it is not putting count correctly for propertyvalue if I run for one employee it works correctly but not for multiple employees.
Please help.
SELECT empno ,
empname ,
(SELECT COUNT(A.propertyvalue)
FROM employeedetails C ,
employees_ASSIGNMENT RCA,
employee_assignment_property A
WHERE TRUNC(startdate) >= '14jun2017'
AND TRUNC(endate) <= '20jun2017'
AND RCA.empno = C.empno
AND RCA.empassignmetid = A.empassignmetid
AND rca.EMPNO IN ('1234','6789')
AND RCA.assignmentid = A.assignmentid
AND A.Name = 'COMPLETED'
AND A.propertyvalue = 'true') ,
(SELECT COUNT(A.propertyvalue)
FROM employeedetails C ,
employees_ASSIGNMENT RCA,
employee_assignment_property A
WHERE TRUNC(startdate) >= '14jun2017'
AND TRUNC(endate) <= '20jun2017'
AND RCA.empno = C.empno
AND RCA.empassignmetid = A.empassignmetid
AND rca.EMPNO IN ('1234','6789')
AND RCA.assignmentid = A.assignmentid
AND A.Name = 'STARTED'
AND A.propertyvalue = 'true')FROM employeedetails WHERE EMPNO IN
('1234','6789') GROUP BY C.empno ,
C.EMPNAME
I think you are simply looking for this:
SELECT DET.empname
, COUNT(CASE WHEN PROP.propertyname = 'COMPLETED' THEN 1 END) COMP_COUNT
, COUNT(CASE WHEN PROP.propertyname = 'STARTED' THEN 1 END) START_COUNT
FROM employeedetails DET
INNER JOIN employees_ASSIGNMENT ASS
ON ASS.empno = DET.empno
INNER JOIN employee_assignment_property PROP
ON PROP.empassignmentID = ASS.empassignmentID
AND PROP.assignmentID = ASS.assignmentID
GROUP BY DET.empname
Just add a WHERE clause if you need one.
if you want you result as a query without CTEs this should work:
select empName,
empNo,
(select employee_details.empNo, count(employee_assignment.assId)
from employee_details as t1
join employee_assignment on (t1.empno = employee_assignment.empno)
join employee_assignment_property on (employee_assignment.assId = employee_assignment_property.assId)
where employee_assignment.ptop = 'COMPLETED'
and t.empNo = t1.empNo
group by t1.empNo ) as [COMPLETED],
(select employee_details.empNo, count(employee_assignment.assId)
from employee_details as t1
join employee_assignment on (t1.empno = employee_assignment.empno)
join employee_assignment_property on (employee_assignment.assId = employee_assignment_property.assId)
where employee_assignment.ptop = 'STARTED'
and t.empNo = t1.empNo
group by t1.empNo ) as [STARTED],
from employee_details as t
If you don't want to do a dirty query composed of subqueries, you can try creating a view (if your database permits it).
What does it mean : I'll be useless in front of this. In summary, a view is a temporary table.
Hope this helps
this should work using CTEs:
Using Common Table Expressions
with numComplet()
as
(
select tbl1.empNo, count(tbl2.assId)
from tbl1
join tbl2 on (tbl1.empno = tbl2.empno)
join tbl3 on (tbl2.assId = tbl3.assId)
where tbl2.ptop = 'COMPLETED'
group by tbl1.empNo
),
with numStarted()
as
(
select tbl1.empNo, count(tbl2.assId)
from tbl1
join tbl2 on (tbl1.empno = tbl2.empno)
join tbl3 on (tbl2.assId = tbl3.assId)
where tbl2.ptop = 'STARTED'
group by tbl1.empNo
)
select *
from tbl1
join numComplet on (tbl1.empNo = numComplet.empNo)
join numStarted on (tbl1.empNo = numStarted.empNo)
I put down table names as tbl[1|2|3]

SQL Where in for Many to Many Join Table

I have the following (moderately epic query) which I have been writing
Select *
from
(Select
Salutation,
FirstName, LastName, FullName,
PhotoUrl, CountryCode, Email, Birthday,
Gender, HomePhone, M.MemberId, IDType, JoinDate,
HomeLocation, HomeLocationId,
Region.Name as RegionName,
M.MembershipId,
coalesce(case
when Package.PackageIsReoccuring = 1 then 'Recurring'
when Package.PackageIsSession = 1 then 'Paid In Full'
when membership.TotalPrice = 0 then 'Free'
when Package.PackagePayInFull = 1 then 'Paid In Full'
end, 'N/A') as PackageTerm,
coalesce(PackageType.Name, 'N/A') as PackageType,
coalesce(membershipstate.name, 'N/A') as MembershipState,
MembershipStartDate =
case
when membership.StartDate IS NULL
then ''
else CONVERT(varchar(50),membership.StartDate)
end,
MembershipEndDate =
case
when membership.EndDate IS NULL
then ''
else CONVERT(varchar(50),membership.EndDate)
end,
Region.Id as RegionId
from
(select
AspNetUsers.Salutation,
AspNetUsers.FirstName, AspNetUsers.LastName,
CONCAT (AspNetUsers.FirstName, ' ', AspNetUsers.LastName) as FullName,
AspNetUsers.PhotoUrl, AspNetUsers.CountryCode, AspNetUsers.Email,
AspNetUsers.Birthday, AspNetUsers.Gender,
AspNetUsers.HomePhone as HomePhone,
Member.Id as MemberId, Member.IDType, Member.JoinDate,
HomeLocation.Name as HomeLocation,
HomeLocation.Id as HomeLocationId,
(case when (select top 1 id from membership where membership.memberid = Member.id and (membership.membershipstateid = 1 or membership.membershipstateid = 6)) IS NULL Then (select top 1 id from membership where membership.memberid = Member.id order by membership.enddate desc) ELSE (select top 1 id from membership where membership.memberid = Member.id and (membership.membershipstateid = 1 or membership.membershipstateid = 6)) END) as MembershipId
from
AspNetUsers
join
Member on AspNetUsers.id = Member.aspnetuserid
join
Location as HomeLocation on Member.HomeLocationId = HomeLocation.id) as M
left join
Membership on M.MembershipId = Membership.Id
left join
Package on Membership.packageid = Package.Id
left join
PackageType on Package.packagetypeid = PackageType.Id
left join
MembershipState on Membership.membershipstateid = MembershipState.Id
left join
Region on Membership.RegionId = Region.Id) as Result
order by
Result.LastName desc
I have a final join table which I want to use which is a many-to-many relationship on Region. Region has a Join Table (RegionLocations) which is a join between Region and Locations.
With my query below I would like to get all results where the HomeLocationId = 2 OR he has a LocationId (from RegionLocations) which also contains 2. The RegionId is a nullable value and isn't always populated.
How can I get this? Do I need to return values into a CSV? This final hurdle is a battle..
Thanks
You could extend this:
left join
Region on Membership.RegionId = Region.Id) as Result
to this:
left join
Region on Membership.RegionId = Region.Id
where M.HomeLocationId = 2
or Region.Id in (select RegionId from RegionLocation where LocationId = 2)
) as Result
Some other remarks about your query:
The fields MembershipStartDate and MembershipEndDate can be evaluated more concisely as:
COALESCE(CONVERT(varchar(50),membership.StartDate), '') as MembershipStartDate,
COALESCE(CONVERT(varchar(50),membership.EndDate), '') as MembershipEndDate,
The inner field MembershipId is defined with three sub-queries in a case when, which can be shortened to just one query. It uses in instead of an or condition, and puts it in the order by clause in a way that gets the priority right:
(select top 1 id
from membership
where membership.memberid = Member.id
order by case when membership.membershipstateid in (1,6) then 0 else 1 end,
membership.enddate desc
) as MembershipId
Finally, if you just have an outer query that performs a select * from (...) order by, then why not skip that outer query and perform that order by on the inner query direcly?

can we have CASE expression/case result as a join table name in oracle

I have 3 tables say Employee, Permanent_Emp and Contract_Emp
SELECT E.EMP_NO,
E.NAME,
JET.EMP_TYPE,
JET.DATE_JOINED
FROM Employee E
LEFT OUTER JOIN
/* Here Join Table Name(JET) it can be Permanent_Emp or Contract_Emp
which i want as a result of my case expression. */
ON (some condition here) ORDER BY E.EMP_NO DESC
case expression:
CASE
WHEN (E.EMP_TYPE_CODE >10 )
THEN
Permanent_Emp JET
ELSE
Contract_Emp JET
END
Note: table and column names are just for an example to understand requirement.
how can i have join table name from a case expression?
Something like this (although without a description of your tables, the exact join conditions or any sample data its hard to give a more precise answer):
SELECT E.EMP_NO,
E.NAME,
COALESCE( P.EMP_TYPE, C.EMP_TYPE ) AS EMP_TYPE
COALESCE( P.DATE_JOINED, C.DATE_JOINED ) AS DATE_JOINED
FROM Employee E
LEFT OUTER JOIN
Permanent_Emp P
ON ( E.EMP_TYPE_CODE > 10 AND E.EMP_NO = P.EMP_NO )
LEFT OUTER JOIN
Contract_Emp C
ON ( E.EMP_TYPE_CODE <= 10 AND E.EMP_NO = C.EMP_NO )
ORDER BY
E.EMP_NO DESC
use your case in select and join both tables
as
SELECT case when 1 then a.column
when 2 then b.column
end
from table c
join table a
on 1=1
join table2 b
on 1=1
but you cant use case while joining. its better to join both tables and in select use case statement with conditions as per your requirement
There is no way to conditionally add tables to a query in static SQL. If the relevant columns in Permanent_Emp and Contract_Emp are roughly equivalent, you could use a union in a sub-query.
SELECT *
FROM employee e
JOIN
(SELECT employee_id, relevant_column, 'P' AS source_indicator
FROM permanent_emp
UNION ALL
SELECT employee_id, relevant_column, 'C' AS source_indicator
FROM contract_emp) se
ON e.employee_id = se.employee_id
AND ( (e.emp_type_code > 10 AND source_indicator = 'P')
OR (e.emp_type_code <= 10 AND source_indicator = 'C'))
Using Alan's query as a starting point you can still use a case statement, just move it to the join condition:
SELECT *
FROM employee e
JOIN (
SELECT employee_id
, relevant_column
, 'P' AS source_indicator
FROM permanent_emp
UNION ALL
SELECT employee_id
, relevant_column
, 'C' AS source_indicator
FROM contract_emp
) se
ON se.employee_id = e.employee_id
and se.source_indicator = case when e.emp_type_code > 10
then 'P'
else 'C'
end
The only difference between this query and Allan's is the use of a case statement instead of an or statement.