How GROUP BY with two inner join in postgresql - sql

I am new in SQL, I have a basic question. I have 3 tables and 2 inner joins.
This is my SQL code:
select c.name, case when e.time > NOW() then 'Yes' else 'No' end AS "time"
from table1 as e
INNER JOIN table2 as a on e.id = a.id
INNER JOIN table3 as c on a.id = c.id
where e.conty= 'SAD'
GROUP BY c.name;
Error: must appear in the GROUP BY clause or be used in an aggregate function

Any field you want to retrieve must be contained in the GROUP BY clause of that query. You should include "time" in the GROUP BY clause or exclude it from the query.
select c.name, case when e.time > NOW() then 'Yes' else 'No' end AS "time"
from table1 as e
INNER JOIN table2 as a on e.id = a.id
INNER JOIN table3 as c on a.id = c.id
where e.name = 'JOHN'
GROUP BY c.name, time;

Use the e.time attribute in the GROUP BY clause.
select c.name, case when e.time > NOW() then 'Yes' else 'No' end AS "time"
from table1 as e
INNER JOIN table2 as a on e.id = a.id
INNER JOIN table3 as c on a.id = c.id
where e.name = 'JOHN'
GROUP BY c.name, e.time;

I am guessing that you want aggregation -- and the maximum time:
select c.name,
(case when max(e.time) > NOW() then 'Yes' else 'No' end) AS "time"
from table1 e join
table2 a
on e.id = a.id join
table3 c
on a.id = c.id
where e.name = 'JOHN'
group by c.name;

You don't need to group by name since you select only the rows with name = 'JOHN'.
If you want to select the row with the maximum time, do this:
select
'JOHN' name,
case when max(e.time) > NOW() then 'Yes' else 'No' end AS "time"
from table1 as e
INNER JOIN table2 as a on e.id = a.id
INNER JOIN table3 as c on a.id = c.id
where e.name = 'JOHN'

Related

replace null sql with 0

Select t.a,sum(s.value) e, sum(r.value) i
CASE when e is NULL then '0' else i end
from table1 t
LEFT JOIN table2 s
ON t.name = s.in
LEFT JOIN table2 r
ON t.name = r.out
group by a
ORDER BY a
My query has error state like 42601, how can i solve this problem to replacing null values with '0'?
You cannot use the ALIAS in the same level it was created. You have to use the aggregated form:
Select t.a,
sum(s.value) e,
sum(r.value) i,
CASE when sum(s.value) is NULL then 0 else sum(r.value) end
from table1 t
LEFT JOIN table2 s ON t.name = s.in
LEFT JOIN table2 r ON t.name = r.out
group by a
ORDER BY a
Otherwise, wrap it in a subquery if you still wanted to use ALIAS
SELECT a, e, i,
CASE when e is NULL then 0 else i end
FROM
(
Select t.a,
sum(s.value) e,
sum(r.value) i
from table1 t
LEFT JOIN table2 s ON t.name = s.in
LEFT JOIN table2 r ON t.name = r.out
group by a
) subquery
ORDER BY a
you can use ISNULL
Select t.a,sum(ISNULL(s.value,0)) e, sum(r.value) i
from table1 t
LEFT JOIN table2 s
ON t.name = s.in
LEFT JOIN table2 r
ON t.name = r.out
group by a
ORDER BY a

How to get only unique row result

I have complex join query ,
Select a.date, b.Name, d.description
FROM tableA as a
INNER JOIN (SELECT Name, MAX(Time) as lastSentTime FROM tableA
GROUP BY Name) b ON a.Name = omh.Name AND b.lastSentTime = b.setTime
INNER JOIN tableD as d ON d.Id = a.id
INNER JOIN tableE as e ON e.Id = d.id
INNER JOIN tableF as f ON f.Id = a.id
WHERE a.status = 'FAILED' AND a.Class = 'Secondary' AND a.marks = e.marks
which will return data as
Date Name Discription
1/2/16 Test I am testing
1/2/16 Test I am testing
1/2/16 Test1 I am testing1
1/2/16 Test1 I am testing1
I need result as
Date Name Discription
1/2/16 Test I am testing
1/2/16 Test1 I am testing1
Try DISTINCT
Select DISTINCT a.date, b.Name, d.description
FROM tableA as a
INNER JOIN (SELECT Name, MAX(Time) as lastSentTime FROM tableA
GROUP BY Name) b ON a.Name = omh.Name AND b.lastSentTime = b.setTime
INNER JOIN tableD as d ON d.Id = a.id
INNER JOIN tableE as e ON e.Id = d.id
INNER JOIN tableF as f ON f.Id = a.id
WHERE a.status = 'FAILED' AND a.Class = 'Secondary' AND a.marks = e.marks
Maybe an entirely different approach is what you need. The join to the subquery seems very strange. Also one of your join predicates was in there where clause instead of the join.
with SortedResults as
(
Select a.date
, b.Name
, d.description
, ROW_NUMBER() over(partition by b.Name order by a.date desc) as RowNum
FROM tableA as a
INNER JOIN tableD as d ON d.Id = a.id
INNER JOIN tableE as e ON e.Id = d.id AND a.marks = e.marks
INNER JOIN tableF as f ON f.Id = a.id
WHERE a.status = 'FAILED'
AND a.Class = 'Secondary'
)
select date
, Name
, description
from SortedResults
where RowNum = 1

Why can I not do a full outer join

I have a db2 query and I realized today I need to expand that query.
My table's already pretty complicated with joins, so I don't really want to add a union query. I want to do a full outer join.
At the moment, it's showing
SELECT
a.id
,a.city
,a.state
,case when a.thing = b.thing then a.thing else b.thing end
,sum( case when c.thing = 'thing' then 1 else 0 end)
,b.id
,b.name
FROM
a
INNER JOIN b -- I want to change this to FULL OUTER JOIN
ON a.id = b.id
LEFT JOIN c
ON a.id = c.id
LEFT JOIN (d
INNER JOIN e
ON d.id = e.id
)
WHERE
--logic
GROUP BY
--for the aggregate functions
ORDER BY
--logic
Can someone tell me when I try to do a full outer join, it says 'Full Outer Join is not supported for this query'? And how would I overcome that?
I think it's because of the other left joins.
It may not be able to combine the outer join with the left joins. You may have to make the outer join a subquery (also added some missing aliases and an ON clause):
SELECT
ab.a_id
,ab.city
,ab.state
,ab.thing
,sum( case when c.thing = 'thing' then 1 else 0 end)
,ab.b_id
,ab.name
FROM
(
SELECT
a.id a_id
,a.city
,a.state
,case when a.thing = b.thing then a.thing else b.thing end thing
,b.id b_id
,b.name
FROM
a
FULL OUTER JOIN b
ON a.id = b.id
) ab
LEFT JOIN c
ON ab.id = c.id
LEFT JOIN (d
INNER JOIN e
ON d.id = e.id
) f
ON ...
WHERE
--logic
GROUP BY
--for the aggregate functions
ORDER BY
--logic

I am trying to subquery with Left outer join and its giving me error. can some one take a look? Please

In this query other than 5 join tables i am trying to use 6th table "Days" to compare value with three tables in joins. but it give me error that i cant use subquery in joins.
select
a.ID, a.Name, a.AMT, b.Address, c.Date, c.Pay, d.Check
from
Table1 a
left outer join Table2 b on a.ID = b.ID
left outer join Table3 c on a.ID = c.ID and c.Date= (select Derived_date from Days where TODAY_DATE = TO_DATE(SYSDATE, 'YYYY/MM/DD'))
left outer join Table4 d on a.ID = d.ID and d.Date= (select Derived_date from Days where TODAY_DATE = TO_DATE(SYSDATE, 'YYYY/MM/DD'))
left outer join Table5 e on a.ID = e.ID and e.Date= (select Derived_date from Days where TODAY_DATE = TO_DATE(SYSDATE, 'YYYY/MM/DD'))
Trying to use a subselect in an ON clause isn't going to work to well. You'd need to JOIN back to it like you would any other table. Since your subselect is the same for every single JOIN, I'd put that in a (temp?) table first so you can JOIN to it normally and not have to SELECT the same data three times.
CREATE TABLE Derived_Dates AS SELECT Derived_date FROM Days WHERE TODAY_DATE = TO_DATE(SYSDATE, 'YYYY/MM/DD')
SELECT a.ID, a.Name, a.AMT, b.Address, c.Date, c.Pay, d.Check
FROM Table1 a LEFT OUTER JOIN Table2 b on a.ID = b.ID
LEFT OUTER JOIN Table3 c ON a.ID = c.ID
LEFT OUTER JOIN Table4 d ON a.ID = d.ID
LEFT OUTER JOIN Table5 e ON a.ID = e.ID
INNER JOIN Dervied_date dt ON c.Date = dt.Derived_date
AND d.Date = dt.Derived_date
AND e.Date = dt.Derived_date
Here's how you can do it with your subselect:
SELECT a.ID, a.Name, a.AMT, b.Address, c.Date, c.Pay, d.Check
FROM Table1 a LEFT OUTER JOIN Table2 b on a.ID = b.ID
LEFT OUTER JOIN Table3 c ON a.ID = c.ID
LEFT OUTER JOIN Table4 d ON a.ID = d.ID
LEFT OUTER JOIN Table5 e ON a.ID = e.ID
INNER JOIN (SELECT Derived_date FROM Days WHERE TODAY_DATE = TO_DATE(SYSDATE, 'YYYY/MM/DD')) dt ON c.Date = dt.Derived_date
AND d.Date = dt.Derived_date
AND e.Date = dt.Derived_date
Instead of JOINing back to your derived dates, you could also just use a WHERE clause. You have some options, and you might want to make some changes for your particular implementation, but this is more or less how I'd approach this.

Combining 3 separate sql queries into one result

So I have three sql queries requesting 3 different things
but I want to be able to combine them into 1 table so that each query appears in each column
these are the queries:
select b.name, count(*)
from account a join branch b
on a.open_branch_id = b.branch_id
group by b.name;
select b.name, count(*)
from employee e join branch b
on e.assigned_branch_id = b.branch_id
group by b.name;
select b.name, count(*)
from customer c join branch b
on c.city = b.city
group by b.name;
i don't know how to combine them so query 1 will appear in 1 column, query 2 in the 2nd column, and query 3 in the third column.
Anyone have any ideas?
Thanks
If the name column is going to have the same values, you can join them like this. From your query however, it seems that the names you are showing are of branches, employees and customers.
select b.name as Name, count(*) as [Count] into #Result1 from account a join branch b on a.open_branch_id = b.branch_id group by b.name;
select b.name as Name, count(*) as [Count] into #Result2 from employee e join branch b on e.assigned_branch_id = b.branch_id group by b.name;
select b.name as Name, count(*) as [Count] into #Result3 from customer c join branch b on c.city = b.city group by b.name;
select r1.name,
r1.[Count],
r2.[Count],
r3.[Count],
from #Result1 as r1
left join #Result2 as r2 on r1.name = r2.name
left join #Result3 as r3 on r1.name = r3.name
drop table #Result1
drop table #Result2
drop table #Result3
If I'm understanding your question, you want to join your results based on your name field from each query? Assuming each have the same names, you can do this with JOINs and subqueries. Here is a simplified version (replace the subqueries with yours above):
select t1.name, t1.cnt,
t2.name as t2name, t2.cnt as t2cnt,
t3.name as t3name, t3.cnt as t3cnt
from
(select name, count(1) cnt
from t1
group by name) t1 join
(select name, count(1) cnt
from t2
group by name) t2 on t1.name = t2.name join
(select name, count(1) cnt
from t3
group by name) t3 on t1.name = t3.name
SQL Fiddle Demo
Edit, given your comments, it appears this is what you might be looking for:
select b.name,
a.acctcnt, e.empcnt, c.citycnt
from branch b
left join (
select count(1) acctcnt, open_branch_id
from account
group by open_branch_id
) a on a.open_branch_id = b.branch_id
left join (
select count(1) empcnt, assigned_branch_id
from employee
group by assigned_branch_id
) e on e.assigned_branch_id = b.branch_id
left join (
select count(1) citycnt, city
from customer
group by city
) c on c.city = b.city
More Fiddle
You could do it like this (SQL Server 2005 and up):
SELECT
B.Name,
B.OtherColumnsIfYouLike,
ACount = IsNull(ACount, 0),
ECount = IsNull(E.ECount, 0),
CCount = IsNull(C.CCount, 0)
FROM
dbo.Branch B
OUTER APPLY (
SELECT ACount = Count(*)
FROM dbo.Account A
WHERE B.Branch_ID = A.Open_Branch_ID
) A
OUTER APPLY (
SELECT ECount = Count(*)
FROM dbo.Employee E
WHERE B.Branch_ID = E.Assigned_Branch_ID
) E
OUTER APPLY (
SELECT CCount = Count(*)
FROM dbo.Customer C
WHERE B.City = C.City
) C
;
Any query you use needs to pay attention to whether there may be no results at all for that branch name. Using INNER JOIN (or just JOIN) will exclude these instead of properly showing 0.
Using your existing queries intact will work like the following, but won't perform as well:
SELECT
Name = Coalesce(A.Name, E.Name, C.Name),
ACount = IsNull(ACount, 0),
ECount = IsNull(E.ECount, 0),
CCount = IsNull(C.CCount, 0)
FROM
(
select b.name, ACount = Count(*)
from account a join branch b on a.open_branch_id = b.branch_id
group by b.name
) A
FULL JOIN (
select b.name, ECount = Count(*)
from employee e join branch b on e.assigned_branch_id = b.branch_id
group by b.name
) E ON A.Name = E.Name
FULL JOIN (
select b.name, CCount = Count(*)
from customer c join branch b on c.city = b.city group by b.name
) C ON IsNull(A.Name, E.Name) = C.Name
;
I think this is the fastest:
with a as
(
select open_branch_id as b_id, count(*) as a_count
from account a
group by open_branch_id
), e as
(
select assigned_branch_id as b_id, count(*) as e_count
from employee e
group by assigned_branch_id
), c as
(
select b.branch_id as b_id, count(*) as c_count
from customer c join branch b
on c.city = b.city
group by b.name
)
select b.name, a.a_count, e.e_count, c.c_count
from branch b
left join a on a.b_id = b.branch_id
left join e on e.b_id = b.branch_id
left join c on c.b_id = b.branch_id
order by b.name