Unable to JOIN and get the final query - sql

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

Related

I need to join 2 databases, with 2 tables each

Dears,
I have an SQL problem. I need to join 2 databases, with 2 tables each. I have the pictures of the tables of the databases here. Thank you very much for your helps.
With a UNION ALL you can get 1 combined resultset from 2 selects.
Then you can group that and SUM the amounts per date.
So you're probably looking for something like this:
select
q.ID,
q.Name,
nullif(sum(case when q.Date = '2018-05-01' then q.Amount end), 0) as "5/1/2018",
nullif(sum(case when q.Date = '2018-05-02' then q.Amount end), 0) as "5/2/2018"
from
(
select u1.ID, u1.Name, a1.Date, a1.Amount
from DB1.Table1 AS u1
join DB1.Table2 AS a1 on (a1.ID = u1.ID and a1.Amount is not null)
where a1.Date IN ('2018-05-01', '2018-05-02')
union all -- combines the results of the 2 selects into one resultset
select u2.ID, u2.Name, a2.Date, a2.Amount
from DB2.Table1 AS u2
join DB2.Table2 AS a2 on (a2.ID = u2.ID and a2.Amount is not null)
where a2.Date IN ('2018-05-01', '2018-05-02')
) AS q
group by q.ID, q.Name
order by q.ID;
An alternative is to JOIN them all up.
select
coalesce(a1.ID, a2.ID) as ID,
max(coalesce(u1.Name, u2.Name)) as Name,
max(case
when coalesce(a1.Date, a2.Date) = '2018-05-01'
and coalesce(a1.Amount, a2.Amount) is not null
then coalesce(a1.Amount, 0) + coalesce(a2.Amount, 0)
end) as "5/1/2018",
max(case
when coalesce(a1.Date, a2.Date) = '2018-05-02'
and coalesce(a1.Amount, a2.Amount) is not null
then coalesce(a1.Amount, 0) + coalesce(a2.Amount, 0)
end) as "5/2/2018"
from DB1.Table2 AS a1
full join DB2.Table2 AS a2 on (a2.ID = a1.ID and a2.Date = a1.Date)
left join DB1.Table1 AS u1 on (u1.ID = a1.ID)
left join DB2.Table1 AS u2 on (u2.ID = a2.ID)
where coalesce(a1.Date, a2.Date) IN ('2018-05-01', '2018-05-02')
group by coalesce(a1.ID, a2.ID)
order by coalesce(a1.ID, a2.ID);
But then note that this way, that there's an assumption that the two Table2 have a uniqueness on (ID, Date)
T-Sql test data:
declare #DB1_Table1 table (id int, Name varchar(30));
declare #DB2_Table1 table (id int, Name varchar(30));
declare #DB1_Table2 table (id int, [Date] date, Amount decimal(8,2));
declare #DB2_Table2 table (id int, [Date] date, Amount decimal(8,2));
insert into #DB1_Table1 (id, Name) values (1,'Susan'),(2,'Juan'),(3,'Tracy'),(4,'Jenny'),(5,'Bill');
insert into #DB2_Table1 (id, Name) values (1,'Susan'),(2,'Juan'),(3,'Tracy'),(4,'Jenny'),(5,'Bill');
insert into #DB1_Table2 (id, [Date], Amount) values
(1,'2018-05-01',20),(2,'2018-05-01',null),(3,'2018-05-01',30),(4,'2018-05-01',50),(5,'2018-05-01',null),
(1,'2018-05-02',15),(2,'2018-05-02',40),(3,'2018-05-02',25),(4,'2018-05-02',8),(5,'2018-05-02',null);
insert into #DB2_Table2 (id, [Date], Amount) values
(1,'2018-05-01',null),(2,'2018-05-01',15),(3,'2018-05-01',20),(4,'2018-05-01',10),(5,'2018-05-01',null),
(1,'2018-05-02',15),(2,'2018-05-02',30),(3,'2018-05-02',35),(4,'2018-05-02',null),(5,'2018-05-02',30);

Error on using union clause in cte sql query

I'm trying to do following but getting an max recursive error. Can someone please help?
Sample code to demonstrate what I'm trying to achieve:
DECLARE #SecurityMaster AS TABLE
(
ID INT,
SecurityAlias INT,
LegNumber INT
)
INSERT INTO #SecurityMaster
SELECT 12829, 3030106, NULL
UNION ALL
SELECT 12829, 3030107, 1
SELECT * FROM #SecurityMaster;
WITH CTE1 (ID, SecurityAlias, LegNumber)
AS
(
SELECT S.ID, S.SecurityAlias, S.LegNumber
FROM #SecurityMaster S
WHERE S.LegNumber IS NOT NULL
UNION ALL
select s.ID, s.SecurityAlias, s.LegNumber
from #SecurityMaster S inner join CTE1 c on s.ID = c.ID
where s.LegNumber is NULL
)
SELECT *
FROM CTE1;
Result I'm expecting:
ID SecurityAlias LegNumber
-----------------------------------------
12829 3030107 1
12829 3030106 NULL
Your questionis difficult to understand, but will this work for you?
select s.ID, s.SecurityAlias, s.LegNumber
from #SecurityMaster S
where s.LegNumber is NULL
And s.id in (SELECT f.ID
FROM #SecurityMaster f
WHERE f.LegNumber IS NOT NULL)

Wrong behaviour with left outer join?

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;

extract data from two tables in a relationship, but have the data in one table only appear once

I have two tables that I need to pull data from, 'Table A' and 'Table B'. There is a a 1:M relationship between 'Table A' and 'Table B', with A.IDNumber as a Foreign Key in 'Table B'.
What I want to do is to extract the values from Table A once, and the corresponding values from 'Table B' without repeating the 'Table A' data.
What would my query look like to do this? To help, let's say I want the following values from 'Table A': A.IDNumber, A.Amount, and from 'TableB' values B.IDNumber, B.Address, B.State, B.City, B.State, B.Zip.
Thanks for any help with this!
You can use the query below. Here's a working SQL Fiddle
SELECT CASE WHEN RN=1 THEN IDNumber END IDNumber,
CASE WHEN RN=1 THEN Amount END Amount,
Address, City, State, Zip
FROM
(
SELECT A.IDNumber, A.Amount,
B.Address, B.City, B.STATE, B.Zip,
RN = Row_number() over (partition BY A.IDNumber
ORDER BY B.IDNumber)
FROM tableA A
LEFT JOIN tableB B ON A.IDNumber = B.IDNumber
) X
ORDER BY IDNumber, RN
It gives this output
IDNumber Amount ADDRESS CITY STATE ZIP
1 200.1 1 Public Road Gotham AX 19281
(null) (null) Secret Batcave Gotham AX 19281
(null) (null) Overseas Hideaway Unspecified ?? n/a
2 312.45 John Woo Lane Trespass TX 12345
(null) (null) Address City State Sq-123
When given this sample table
CREATE TABLE TableA(
IDNumber int, Amount money)
CREATE TABLE TableB(
IDNumber int,
Address varchar(max),
City varchar(max),
State varchar(max),
Zip varchar(max))
INSERT TableA SELECT
1,200.10 union all select
2,312.45
INSERT TableB SELECT
1, '1 Public Road', 'Gotham', 'AX', '19281' union all select
1, 'Secret Batcave', 'Gotham', 'AX', '19281' union all select
1, 'Overseas Hideaway', 'Unspecified', '??', 'n/a' union all select
2, 'John Woo Lane', 'Trespass', 'TX', '12345' union all select
2, 'Address', 'City', 'State', 'Sq-123'
So you do not repeat values, use DISTINCT on your query
select **DISTINCT** A.IDNumber, A.Amount, and from 'TableB' values B.IDNumber, B.Address, B.State, B.City, B.State, B.Zip from TableA A, TableB B where A.IDNumber = B.IDNumber
What you are saying is that you want the fields from Table A only on the first row of results from B.
The way you do this depends on the database. Here is an approach that will work with most databases:
with b as (
select b.*,
row_number() over (partition by b.a_idnumber order by b.idnumber) as seqnum
from tableb
)
select (case when b.seqnum = 1 then a.idnumber end) as IdNumber,
(case when b.seqnum = 1 then a.amount end) as Amount,
b.*
from tablea a join
b
on a.idnumber = b.a_idnumber
order by a.idnumber, b.seqnum

Case or If, What to choose in SQL

How can i manage this query. I want to have only one person in the query. If there is an id in empId column, then the name of him. Otherwise the name of the boss.
Product empId teamId
----------------------
A 1 3
B 2 4
C 3
D 2 3
E 4
User Table
Id Name
-----------
1 Jim
2 Carrey
3 Bill
4 Clinton
Team Table
Team_Id BossId
-----------
3 3
4 4
The result should look like:
Product user.name
-----------------
A Jim
B Carrey
C Bill
D Carrey
E Clinton
Use CASE or the COALESCE() function:
SELECT
x.Product
, COALESCE(emp.Name, boss.Name) AS Name
FROM
TableX AS x
LEFT JOIN
User AS emp
ON emp.Id = x.empId
LEFT JOIN
User AS boss
ON boss.Id = x.bossId
Updated:
SELECT
x.Product
, COALESCE(emp.Name, boss.Name) AS Name
FROM
TableX AS x
LEFT JOIN
User AS emp
ON emp.Id = x.empId
LEFT JOIN
Team As t
JOIN
User AS boss
ON boss.Id = t.bossId
ON t.team_Id = x.teamId
Something like this:
SELECT
Table1.Product,
CASE
WHEN Table1.empId IS NULL
THEN Boss.name
ELSE Emp.name
END
FROM
Table1
LEFT JOIN [User] AS Emp
ON Emp.Id =Table1.empId
LEFT JOIN Team
ON Team.Team_Id =Table1.teamId
LEFT JOIN [User] AS Boss
ON Boss.Id=Team.BossId
SELECT Y.Product, U.Name
FROM YourTable AS Y
JOIN Users AS U ON Y.empId = U.Id
UNION
SELECT Y.Product, U.Name
FROM YourTable AS Y
JOIN Team AS T ON Y.teamId = T.Team_Id
JOIN Users AS U ON T.BossId = U.Id
WHERE Y.empId IS NULL;
-- SET search_path='tmp';
DROP TABLE tmp.products;
CREATE TABLE products
( product CHAR(1)
, emp_id INTEGER
, team_id INTEGER
);
INSERT INTO products(product,emp_id,team_id)
VALUES ('A',1,3), ('B',2,4), ('C',NULL,3), ('D',2,3), ('E',NULL,4);
DROP TABLE tmp.names;
CREATE TABLE names
(id INTEGER
, zname varchar
);
INSERT INTO names(id,zname)
VALUES ( 1, 'Jim') ,( 2, 'Carrey') ,( 3, 'Bill') ,( 4, 'Clinton') ;
DROP TABLE tmp.teams;
CREATE TABLE teams
( team_id INTEGER NOT NULL
, boss_id INTEGER NOT NULL
);
INSERT INTO teams(team_id,boss_id) VALUES ( 3,4) , (4,4);
WITH lutser(prod,id,team) AS
(
SELECT k1.product AS prod
, k1.emp_id AS id
, k1.team_id AS team
FROM tmp.products k1
UNION
SELECT k2.product AS prod
, t.boss_id AS id
, k2.team_id AS team
FROM tmp.products k2
JOIN tmp.teams t ON t.team_id = k2.team_id
WHERE k2.emp_id IS NULL
)
SELECT l.prod
, l.id
, l.team
, n.zname
FROM lutser l
JOIN names n ON n.id = l.id
;
extra bonus point for a recursive version of this CTE ...