Wrong behaviour with left outer join? - sql

SQL Fiddle : http://sqlfiddle.com/#!2/49db7/2
create table EmpDetails
(
emp_code int,
e_type varchar(10)
);
insert into EmpDetails values (100,'A');
insert into EmpDetails values (101,'D');
insert into EmpDetails values (102,'A');
insert into EmpDetails values (103,'D');
create table QDetails
(
id int,
emp_code int,
dn_num int
);
insert into QDetails values (1,100,NULL);
insert into QDetails values (2,101,4343);
insert into QDetails values (3,101,4343);
insert into QDetails values (4,103,NULL);
insert into QDetails values (5,103,NULL);
insert into QDetails values (6,100,NULL);
select * from EmpDetails
select * from QDetails
-- expected result
1 100 NULL
6 100 NULL
2 101 4343
3 101 4343
--When e_type = A it should include rows from QDetails doesn't matter dn_num is null or not null
--but when e_type = D then from QDetails it should include only NOT NULL values should ignore null
select e.emp_code, e.e_type, q.dn_num from empdetails e left join qdetails q
on e.emp_code = q.emp_code and (e.e_type = 'D' and q.dn_num is not null)
--Above query I tried includes 103 D NULL which I don't need and exclueds 6 100 NULL which i need.

I am not sure why you are using left join here.
You can get the results you specified with inner join
select
e.emp_code
,e.e_type
,q.dn_num
from
empdetails e
inner join qdetails q on e.emp_code = q.emp_code
where
e.e_type = 'A'
or (e.e_type = 'D' and q.dn_num is not null)
order by
e.emp_code
,e.e_type
The left join would be used if you also wanted to list records from empdetails table that have no match in qdetails

Your problem is your q.dn_num is not null condition, it is specifically excluding those records that you state that you want. Removing that should fix it.
select e.emp_code, e.e_type, q.dn_num
from empdetails e
left join qdetails q
on e.emp_code = q.emp_code
WHERE (e.e_type = 'D' and q.db_num is not null)
OR e.e_type = 'A'
Additionally, it is a general convention to use your join to specify only the join criteria and your where clause to filter (there are reasons why you may not want to do this, but depends on your query).
Writing your queries as above may make them easier to read later on.

SELECT e.emp_code,
e.e_type,
q.dn_num
FROM empdetails e
LEFT JOIN qdetails q
ON e.emp_code = q.emp_code
WHERE (
e.e_type = 'A' OR
(
e.e_type = 'D' AND
q.dn_num is not null
)
) AND q.id is not null
SQL Fiddle Demo

You need to implement the logic correctly. Your conditions mention 'A', but that is not in the conditions.
Then, you don't need a left join. You don't want emp_code = 102. This has no matches, so presumably it drops out.
The following seems to implement the logic:
select e.emp_code, e.e_type, q.dn_num , q.id
from empdetails e join
qdetails q
on e.emp_code = q.emp_code
where (e.e_type = 'D' and q.dn_num is not null) or
e.e_type = 'A';

This is the correct query.
select q.id,e.emp_code,q.dn_num
from empdetails e join qdetails q
on e.emp_code = q.emp_code
where (e.e_type = 'D' and q.dn_num is not null) or e.e_type = 'A' order by e.e_type;

Related

How to add a temp table in SQL server

I am trying to add a temp table to my query so that I can query that temp table, I have searched the internet but I couldn't get a solution.
this is my query
;WITH cte AS (
SELECT ID, g.Name
FROM game.Game g WITH(NOLOCK
WHERE ID IN (SELECT Data FROM system.Split(1, ','))
UNION ALL
SELECT g.ID, g.Name
FROM game.Game g WITH(NOLOCK)
JOIN cte ON g.ParentID = cte.ID
)
SELECT c.ID,
c.Name
FROM cte c
INNER JOIN list.Type gt WITH(NOLOCK) ON c.TypeId = gt.TypeID
WHERE c.ID NOT IN (SELECT Data FROM system.Split(1, ','))
AND c.ID IN (SELECT ID FROM game.code WITH(NOLOCK)
WHERE ID = c.ID
AND StatusCode IN ('OP', 'CL', 'SU')
AND isDisplay = 'True'
AND GETDATE() BETWEEN DisplayStart AND DisplayEnd
AND GETDATE() < ISNULL(ResultDateTime, ResultExpected)
)
which gives me the following when I run it
ID | Name
1111 | BaseBall
2222 |BasketBall
45896 |Relay
now I tried to create a temp table as follows
Create Table #temp(
ID int,
Name varchar
)
;WITH cte AS (
SELECT ID, g.Name
FROM game.Game g WITH(NOLOCK)
WHERE ID IN (SELECT Data FROM system.Split(1, ','))
UNION ALL
SELECT g.ID, g.Name
FROM game.Game g WITH(NOLOCK)
JOIN cte ON g.ParentID = cte.ID
)
insert into #temp // i wanted to set these values in the temp table
SELECT c.ID,
c.Name
FROM cte c
INNER JOIN list.Type gt WITH(NOLOCK) ON c.TypeId = gt.TypeID
WHERE c.ID NOT IN (SELECT Data FROM system.Split(1, ','))
AND c.ID IN (SELECT ID FROM game.code WITH(NOLOCK)
WHERE ID = c.ID
AND StatusCode IN ('OP', 'CL', 'SU')
AND isDisplay = 'True'
AND GETDATE() BETWEEN DisplayStart AND DisplayEnd
AND GETDATE() < ISNULL(ResultDateTime, ResultExpected)
)
every time I try to store this information in the temp table it gives me an error 'Column name or number of supplied values does not match table definition.' But I only have two values in. What am I doing wrong that I cant see?
First, why not just use select into?
IF OBJECT_ID('TempDB..#temp') IS NOT NULL
BEGIN
DROP TABLE #temp
END
select c.ID, c.Name
into #temp
from . . .
Then you don't need to define #temp as a table.
Next, your definition is bad, because Name has only one character. This would be fixed with select into.
However, I don't know why you are getting the particular error you are getting. The numbers of columns appears to match.

Unable to JOIN and get the final query

I'm having this following situation for which i'm unable to form a sql query. Please help me with this.
create table student(
studentName varchar(50)
);
Insert into student values('abc');
Insert into student values('mnop');
Insert into student values('xyz');
Insert into student values('pqrs');
create table workAssigned (
topic varchar(50),
creator varchar(50),
reviewer varchar(50),
creationCount decimal(4,2)
reviewCount decimal(4,2)
);
insert into workAssigned values('algebra','abc','mnop',1.25,0.75);
insert into workAssigned values('geometry','mnop','xyz',1.5,0.25);
insert into workAssigned values('algorithms','mnop','xyz',1.5,1.5);
insert into workAssigned values('derivative','xyz','abc',0.25,1);
final output reqiured is:
StudentName NumberOfWorkDone Effort
abc 2 2.25
mnop 3 3.75
xyz 3 2
pqrs NUll NULL
Where NumberOfWorkDone is SUM of creator and Reviewer, and
Effort is SUM of creationCount and reviewCount
You can try using Group By, Join and CASE with Aggregate functions,
SELECT studentName,
SUM(CASE WHEN W.creator = S.studentName OR S.studentName = W.reviewer THEN 1 ELSE NULL END ) AS NumberOfWorkDone,
SUM(CASE WHEN W.creator = S.studentName THEN W.creationCount WHEN S.studentName = W.reviewer THEN W.REVIEWCOUNT ELSE NULL END) AS Efforts
FROM student S
LEFT JOIN workAssigned W
ON S.studentName = W.creator OR S.studentName = W.reviewer
GROUP BY studentName
I have added NULL into Case statement for else part as your output was showing NULL but I think it would be better if you would replace that with 0.
Select studentName,NumberOfWorkDone,Effort
From student as A
Left Join
(
Select creator,count(creator) as NumberOfWorkDone,sum(creationCount) as Effort
From
(
Select creator,creationCount
from workAssigned as A
Union all
Select reviewer,reviewCount from workAssigned
)as A
Group by creator
)as B
On A.studentName=B.creator
select * from
(select count(col_X) as F, col_X
from
(select creator as col_X from workAssigned
UNION ALL
select reviewer as col_X from workAssigned) AS A
group by col_X) as E
left join
(select A, sum(B)
from
(select creator as A, creationCount as B
from workAssigned
UNION ALL
select revieweras A, reviewCount as B
from workAssigned) as C
group by A) as D
on E.F = D.A

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.

Same Query with MINUS and NOT IN Clause returning Different result set. Please explain why this different result sets

Here i am having same queries one with MINUS and one with NOT IN both queries returning different result set.
Query with NOT IN Clause
SELECT DISTINCT ebdf.business, ebdf.data_source, ebdf.frequency,
c.case_symbol
FROM etl_mgr.etl_bus_datasrc_frequencies#etlmgr_srv_ubatchh_lx ebdf INNER JOIN etl_mgr.etl_rulesets#etlmgr_srv_ubatchh_lx er
ON ( ebdf.business = er.business
AND ebdf.data_source = er.data_source
AND ebdf.frequency = er.frequency
)
LEFT OUTER JOIN etl_mgr.etl_db_output_fact_rules#etlmgr_srv_ubatchh_lx r
ON er.ruleset_id = r.ruleset_id
LEFT OUTER JOIN etl_mgr.etl_db_output_fact_cases#etlmgr_srv_ubatchh_lx c
ON r.db_output_fact_rule_id =
c.db_output_fact_rule_id
WHERE (ebdf.business,
ebdf.data_source,
ebdf.frequency,
c.case_symbol
) NOT IN (
SELECT c.business_unit_key, e.data_source_key,
f.data_frequency_key,
g.data_source_subset
FROM npdreportmanager_appsetup.tb_module_summary_schema a INNER JOIN npdreportmanager_appsetup.tb_module b
ON a.module = b.module
INNER JOIN npdreportmanager_appsetup.tb_business_unit c
ON b.business_unit_id = c.business_unit_id
INNER JOIN npdreportmanager_appsetup.tb_summary_source_type d
ON a.summary_source_type_id =
d.summary_source_type_id
INNER JOIN npdreportmanager_appsetup.tb_data_source e
ON d.data_source_id = e.data_source_id
INNER JOIN npdreportmanager_appsetup.tb_data_frequency f
ON d.data_frequency_id =
f.data_frequency_id
LEFT OUTER JOIN npdreportmanager_appsetup.tb_data_source_subset g
ON d.data_source_subset_id =
g.data_source_subset_id)
Same Query With MINUS Puzzled why not returning the same out put :
SELECT DISTINCT ebdf.business, ebdf.data_source, ebdf.frequency,
c.case_symbol
FROM etl_mgr.etl_bus_datasrc_frequencies#etlmgr_srv_ubatchh_lx ebdf INNER JOIN etl_mgr.etl_rulesets#etlmgr_srv_ubatchh_lx er
ON ( ebdf.business = er.business
AND ebdf.data_source = er.data_source
AND ebdf.frequency = er.frequency
)
LEFT OUTER JOIN etl_mgr.etl_db_output_fact_rules#etlmgr_srv_ubatchh_lx r
ON er.ruleset_id = r.ruleset_id
LEFT OUTER JOIN etl_mgr.etl_db_output_fact_cases#etlmgr_srv_ubatchh_lx c
ON r.db_output_fact_rule_id =
c.db_output_fact_rule_id
MINUS
SELECT c.business_unit_key, e.data_source_key, f.data_frequency_key,
g.data_source_subset
FROM npdreportmanager_appsetup.tb_module_summary_schema a INNER JOIN npdreportmanager_appsetup.tb_module b
ON a.module = b.module
INNER JOIN npdreportmanager_appsetup.tb_business_unit c
ON b.business_unit_id = c.business_unit_id
INNER JOIN npdreportmanager_appsetup.tb_summary_source_type d
ON a.summary_source_type_id = d.summary_source_type_id
INNER JOIN npdreportmanager_appsetup.tb_data_source e
ON d.data_source_id = e.data_source_id
INNER JOIN npdreportmanager_appsetup.tb_data_frequency f
ON d.data_frequency_id = f.data_frequency_id
LEFT OUTER JOIN npdreportmanager_appsetup.tb_data_source_subset g
ON d.data_source_subset_id = g.data_source_subset_id
NOT NULL is sensitive to null values, it does not compare null values hence ignores it. In contrast, MINUS is insensitive to null values. Check the example given below
SQL> create table test1 (c1 number(9), c2 varchar2(10));
Table created.
SQL> insert all
2 into test1 values (1, 'XYZ')
3 into test1 values (2, null)
4 into test1 values (4, null)
5 into test1 values (null, 'ABC')
6 select * from dual;
4 rows created.
SQL> create table test2 (c1 number(9), c2 varchar2(10));
Table created.
SQL> insert all
2 into test2 values (1, 'XYZ')
3 into test2 values (2, null)
4 into test2 values (3, 'GHI')
5 into test2 values (null, 'ABC')
6 into test2 values (5, null)
7 select * from dual;
5 rows created.
SQL> select * from test2 where (c1, c2) not in (select c1, c2 from test1);
C1 C2
---------- ----------
3 GHI
SQL> select * from test2 minus select * from test1;
C1 C2
---------- ----------
3 GHI
5
SQL>
Row 5, NULL was ignored by NOT NULL but was considered by MINUS. In fact NOT NULL ignored row 2, null and null, ABC, but since they are also present in test1, it seems to be logical although ignored. This can be tested by issuing select * from test2 where (c1, c2) in (select c1, c2 from test1);
i modified the query and able to get the right answer this time. thanks to everyone for the prompt response.
SELECT * FROM( SELECT DISTINCT ebdf.business || ebdf.data_source || ebdf.frequency ||c.case_symbol As D1,ebdf.business, ebdf.data_source, ebdf.frequency,
c.case_symbol
FROM etl_mgr.etl_bus_datasrc_frequencies#etlmgr_srv_ubatchh_lx ebdf INNER JOIN etl_mgr.etl_rulesets#etlmgr_srv_ubatchh_lx er
ON ( ebdf.business = er.business
AND ebdf.data_source = er.data_source
AND ebdf.frequency = er.frequency
)
LEFT OUTER JOIN etl_mgr.etl_db_output_fact_rules#etlmgr_srv_ubatchh_lx r
ON er.ruleset_id = r.ruleset_id
LEFT OUTER JOIN etl_mgr.etl_db_output_fact_cases#etlmgr_srv_ubatchh_lx c
ON r.db_output_fact_rule_id =
c.db_output_fact_rule_id) tst WHERE tst.D1 NOT IN
(
SELECT c.business_unit_key || e.data_source_key || f.data_frequency_key || g.data_source_subset as D1
FROM npdreportmanager_appsetup.tb_module_summary_schema a INNER JOIN npdreportmanager_appsetup.tb_module b
ON a.module = b.module
INNER JOIN npdreportmanager_appsetup.tb_business_unit c
ON b.business_unit_id = c.business_unit_id
INNER JOIN npdreportmanager_appsetup.tb_summary_source_type d
ON a.summary_source_type_id = d.summary_source_type_id
INNER JOIN npdreportmanager_appsetup.tb_data_source e
ON d.data_source_id = e.data_source_id
INNER JOIN npdreportmanager_appsetup.tb_data_frequency f
ON d.data_frequency_id = f.data_frequency_id
LEFT OUTER JOIN npdreportmanager_appsetup.tb_data_source_subset g
ON d.data_source_subset_id = g.data_source_subset_id

MSSQL Inner Join on Concatenated Column

I'm not a DBA so please don't yell at me. Trying to do an inner join and Group By using a concatenated column. The ON statement is producing a syntax error. I do not have access to the original tables and am trying to normalize this into another table, I know its ugly. Not overly worried about performance, just need to work. Cant use functions either.
SELECT DISTINCT A.[carrier_code],[carrier_name], [carrier_grouping], A.[collector_name], [dataset_loaded], [docnum], [envoy_payer_id], [loc], [market], [master_payor_grouping], [plan_class], [plan_name], A.[resp_ins],A.[resp_ind], A.[resp_payor_grouping], A.[Resp_Plan_Type], A.[rspphone], A.[state], A.[sys],A.[resp_ins]+A.[resp_payor_grouping]+A.[carrier_code]+A.[state]+A.[Collector_Name] as ExtId
FROM [Table1] A
INNER JOIN
(SELECT [resp_ins]+[resp_payor_grouping]+[carrier_code]+[state]+[Collector_Name] as Extid
FROM [Table1]
WHERE [resp_ind] = 'Insurance'
GROUP BY [resp_ins]+[resp_payor_grouping]+[carrier_code]+[state]+[Collector_Name]) B
ON A.[resp_ins]+A.[resp_payor_grouping]+A.[carrier_code]+A.[state]+A.[Collector_Name] = B.[resp_ins]+B.[resp_payor_grouping]+B.[carrier_code]+B.[state]+B.[Collector_Name];
My ON and Group By statements are eventually the primary key in new table.
Your alias B hasn't columns as you mentioned. It has just on column Extid.
SELECT DISTINCT A.[carrier_code],[carrier_name], [carrier_grouping], A.[collector_name], [dataset_loaded], [docnum], [envoy_payer_id], [loc], [market], [master_payor_grouping], [plan_class], [plan_name], A.[resp_ins],A.[resp_ind], A.[resp_payor_grouping], A.[Resp_Plan_Type], A.[rspphone], A.[state], A.[sys],A.[resp_ins]+A.[resp_payor_grouping]+A.[carrier_code]+A.[state]+A.[Collector_Name] as ExtId
FROM [Table1] A
INNER JOIN
(SELECT [resp_ins]+[resp_payor_grouping]+[carrier_code]+[state]+[Collector_Name] as Extid
FROM [Table1]
WHERE [resp_ind] = 'Insurance'
GROUP BY [resp_ins]+[resp_payor_grouping]+[carrier_code]+[state]+[Collector_Name]) B
ON A.[resp_ins]+A.[resp_payor_grouping]+A.[carrier_code]+A.[state]+A.[Collector_Name] = B.Extid;
Try this, I didn't put all the column in result, you can manage yourself.
select A.*
from
(
select [carrier_code],[carrier_name], [sys],[resp_ins]+[resp_payor_grouping]+[carrier_code]+[state]+[Collector_Name] as ExtId
FROM [Table1]
) A
inner join
(
select distinct Extid
from
(
SELECT [resp_ins]+[resp_payor_grouping]+[carrier_code]+[state]+[Collector_Name] as ExtId
FROM [Table1]
WHERE [resp_ind] = 'Insurance'
) ins
) B on (A.ExtId = B.ExtId)
You don't need to concatenate the values - you can GROUP BY and JOIN on multiple columns.
SELECT DISTINCT
...
FROM
[Table1] A
INNER JOIN
(
SELECT
[resp_ins],
[resp_payor_grouping],
[carrier_code],
[state],
[Collector_Name]
FROM
[Table1]
WHERE
[resp_ind] = 'Insurance'
GROUP BY
[resp_ins],
[resp_payor_grouping],
[carrier_code],
[state],
[Collector_Name]
) B
ON
(
A.[resp_ins] = B.[resp_ins]
Or
(A.[resp_ins] Is Null And B.[resp_ins] Is Null)
)
And
(
A.[resp_payor_grouping] = B.[resp_payor_grouping]
Or
(A.[resp_payor_grouping] Is Null And B.[resp_payor_grouping] Is Null)
)
And
(
A.[carrier_code] = B.[carrier_code]
Or
(A.[carrier_code] Is Null And B.[carrier_code] Is Null)
)
And
(
A.[state] = B.[state]
Or
(A.[state] Is Null And B.[state] Is Null)
)
And
(
A.[Collector_Name] = B.[Collector_Name]
Or
(A.[Collector_Name] Is Null And B.[Collector_Name] Is Null)
)
;