SQL query handling three tables - sql

I want to compile the data for reporting purpose, using php communicating with postgres,
I have three tables
product_status:
status_code | value
------------|------
1 | a
2 | b
product_child:
code| ID | status_code
----|----|------------
X | 1 | 1
X | 2 | 1
X | 3 | 2
Y | 1 | 2
Y | 2 | 2
Z | 1 | 1
product_master:
code|description(and some other columns not relevent)
X | la
Y | alb
Z | lab
In the end I want basically a table like this which i'll display
| total child | status a | status b
bla | 3 | 2 | 1
alb | 2 | 0 | 2
lab | 1 | 1 | 0
I have tried
SELECT s.value, count(s.value)
FROM product_child p, product_status s
WHERE
p.product_status = s.status_code
and p.product_code = get_product_code('Sofa (1-seater) J805')
group by
s.value
it gives we grouping for particular code but I want this flipped and appended in front of distinct product_codes

do you mean like this?
select pm.description,
count(pc.code) total,
count(case when ps.value = 'A' then ps.value else null end) statusA,
count(case when ps.value = 'B' then ps.value else null end) statusB
from product_master pm join product_child pc on pm.code = pc.code
join product_status ps on pm.status_code = ps.status_code
group by pm.description

Related

select records where condition is true in one record

I need to select cid, project, and owner from rows in the table below where one or more rows for a cid/project combination has an owner of 1.
cid | project | phase | task | owner
-----------------------------------
1 | 1 | 1 | 1 | 1
1 | 1 | 1 | 2 | 2
1 | 1 | 1 | 3 | 2
2 | 1 | 1 | 1 | 1
2 | 1 | 1 | 2 | 1
3 | 1 | 1 | 3 | 2
My output table should look like the this:
cid | project | phase | task | owner
-----------------------------------
1 | 1 | 1 | 1 | 1
1 | 1 | 1 | 2 | 2
1 | 1 | 1 | 3 | 2
2 | 1 | 1 | 1 | 1
2 | 1 | 1 | 2 | 1
The below query is what I came up with. It does seem to test okay, but my confidence is low. Is the query an effective way to solve the problem?
select task1.cid, task1.project, task1.owner
from
(select cid, project, owner from table) task1
right join
(select distinct cid, project, owner from table where owner = 1) task2
on task1.cid = task2.cid and task1.project = task2.project
(I did not remove the phase and task columns from the sample output so that it would be easier to compare.)
You can simply use a IN clause
select cid, project, owner
from table
where cid in (select distinct id from table where owner = 1)
or a inner join with a subquery
select a.cid, a.project, a.owner
from table a
INNER JOIN ( select distinct cid , project
from table where owner = 1
) t on t.cid = a.cid and t.project = a.project

Best Hive SQL query for this

i have 2 table something like this. i'm running a hive query and windows function seems pretty limited in hive.
Table dept
id | name |
1 | a |
2 | b |
3 | c |
4 | d |
Table time (build with heavy load query so it's make a very slow process if i need to join to another newly created table time.)
id | date | first | last |
1 | 1992-01-01 | 1 | 1 |
2 | 1993-02-02 | 1 | 2 |
2 | 1993-03-03 | 2 | 1 |
3 | 1993-01-01 | 1 | 3 |
3 | 1994-01-01 | 2 | 2 |
3 | 1995-01-01 | 3 | 1 |
i need to retrieve something like this :
SELECT d.id,d.name,
t.date AS firstdate,
td.date AS lastdate
FROM dbo.dept d LEFT JOIN dbo.time t ON d.id=t.id AND t.first=1
LEFT JOIN time td ON d.id=td.id AND td.last=1
How the most optimized answer ?
GROUP BY operation that will be done in a single map-reduce job
select id
,max(name) as name
,max(case when first = 1 then `date` end) as firstdate
,max(case when last = 1 then `date` end) as lastdate
from (select id
,null as name
,`date`
,first
,last
from time
where first = 1
or last = 1
union all
select id
,name
,null as `date`
,null as first
,null as last
from dept
) t
group by id
;
+----+------+------------+------------+
| id | name | firstdate | lastdate |
+----+------+------------+------------+
| 1 | a | 1992-01-01 | 1992-01-01 |
| 2 | b | 1993-02-02 | 1993-03-03 |
| 3 | c | 1993-01-01 | 1995-01-01 |
| 4 | d | (null) | (null) |
+----+------+------------+------------+
select d.id
,max(d.name) as name
,max(case when t.first = 1 then t.date end) as 'firstdate'
,max(case when t.last = 1 then t.date end) as 'lastdate'
from dept d left join
time t on d.id = t.id
where t.first = 1 or t.last = 1
group by d.id

Return all rows from a table and indicate with a new column whether they exist or not in another table

If I have 2 tables:
TABLE_SEARCHFIELDS:
FieldID | FieldName
--------------------
1 | MyField1
2 | MyField2
3 | MyField3
4 | MyField4
5 | MyField5
and
TABLE_CUSTOMSEARCHFIELDS:
UserID | FieldID
--------------------
1 | 1
1 | 2
1 | 5
2 | 2
2 | 4
2 | 5
and I would like to return all of the Searchfields from the first table, but would also like indicated whether that Searchfield is active for a particular user.
E.g. I want to query UserID = 1 and get the result:
FieldID | FieldName | Active
------------------------------
1 | MyField1 | 1
2 | MyField2 | 1
3 | MyField3 | 0
4 | MyField4 | 0
5 | MyField5 | 1
What is the best way to achieve this?
I would do this using exists:
select sf.*,
(case when exists (select 1
from customsearchfields csf
where csf.userid = 1 and csf.fieldid = sf.fieldid
)
then 1 else 0
end) as Active
from searchfields sf;
Assuming you have no duplicate rows, you can also do this using a left join:
select sf.*, (case when csf.userid is not null then 1 else 0 end) as Active
from searchfields sf left join
customsearchfields csf
on csf.userid = 1 and csf.fieldid = sf.fieldid;

Efficent way to generate a summery table in SQL. Please see explanation

I am very new to sql.I need some help in generating summery information
MemberTable
MonthID | UserID | TeamID
-----------------------------
1 | 1 | 1
1 | 2 | 1
1 | 3 | 1
1 | 4 | 1
1 | 5 | 2
1 | 6 | 2
1 | 7 | 2
AND
ReportTable
ID* | MonthID | UserID | IsSend
-----------------------------------
1 | 1 | 2 | False
2 | 1 | 3 | True
3 | 1 | 5 | True
I want to generate a summery like the following
TeamID | Total Count | Send Count | Not Send Count
-----------------------------------------------------------
1 | 4 | 1 | 3
2 | 3 | 1 | 2
Total Count : No of users in a team
Send Count : Total User in a team with IsSend = True
Not Send Count : Total Count - Send Count
What would be the efficent way?
Give this a try:
select mt.teamId, count(*) totalCount,
count(case when rt.isSend = 'True' then 1 end) sendCount,
count(case when rt.isSend != 'True' then 1 end) notSendCount
from memberTable mt
join reportTable rt on mt.userId = rt.userId
group by mt.teamId
Note that your expected result does not reflect your data. The result based on your data should be:
+--------+------------+-----------+--------------+
| TEAMID | TOTALCOUNT | SENDCOUNT | NOTSENDCOUNT |
+--------+------------+-----------+--------------+
| 1 | 2 | 1 | 1 |
| 2 | 1 | 1 | 0 |
+--------+------------+-----------+--------------+
select MT.TeamID,
count(distinct MT.UserID) as "Total Count",
count(distinct case when RT.IsSend = 1 then MT.UserID end) as "Send Count",
count(distinct MT.UserID) - count(distinct case when RT.IsSend = 1 then MT.UserID end) as "Not Send Count"
from MemberTable as MT
left outer join ReportTable as RT
on MT.MonthID = RT.MonthID and
MT.UserID = RT.UserID
group by MT.TeamID
Result:
TeamID Total Count Send Count Not Send Count
----------- ----------- ----------- --------------
1 4 1 3
2 3 1 2
Try here: https://data.stackexchange.com/stackoverflow/query/66347
Without havign the tables to try this on, I can't check that this will work, but this shoul get you most of the way:
SELECT TeamID, count(userID) as "Total count", Sum(IsSend) as "Send Count" FROM MemberTable JOIN ReportTable ON UserID GROUP BY TeamID;

Is it possible to select multiple conditional counts across three tables in a single SQL query?

My SQL-fu is too weak for this, and I'm not even sure it's possible in a single SQL call.
Given I have the following tables:
PARTNER
+----+--------+
| id | name |
+----+--------+
| 1 | bloggs |
| 2 | jones |
PARTNER MANAGER
+----+--------------+------+
| id | partner_id | name |
+----+--------------+------+
| 1 | 1 | fred |
| 2 | 2 | dave |
COMPANY
+----+--------------------+--------+----------+
| id | partner_manager_id | name | active |
+----+--------------------+--------+----------+
| 1 | 1 | comp1 | true |
| 2 | 1 | comp2 | false |
| 3 | 2 | comp3 | true |
| 4 | 2 | comp4 | true |
| 5 | 2 | comp5 | true |
| 6 | 2 | comp6 | true |
I'd like to output the following in a single SQL call:
+--------------+--------------------+----------------------+
| partner_name | n_active_companies | n_inactive_companies |
+--------------+--------------------+----------------------+
| bloggs | 1 | 1 |
| jones | 4 | 0 |
I can join the three tables using two LEFT JOINs but how I can aggregate the counts (with or without the WHERE clause) is eluding me.
Am I barking up the wrong tree, so to speak?
This gets you most of the way there:
SELECT
partner_manager_id,
SUM(CASE WHEN active THEN 1 ELSE 0 END) AS n_active_companies,
SUM(CASE WHEN active THEN 0 ELSE 1 END) AS n_inactive_companies
FROM COMPANY
GROUP BY partner_manager_id
The rest of your question is basically asking how to join this result to the remaining tables. As you point out, to do this use JOINs.
SELECT
PARTNER.name,
T1.n_active_companies,
T1.n_inactive_companies
FROM
PARTNER
LEFT JOIN PARTNER_MANAGER ON partner_id = PARTNER.id
LEFT JOIN
(
SELECT
partner_manager_id,
SUM(CASE WHEN active THEN 1 ELSE 0 END) AS n_active_companies,
SUM(CASE WHEN active THEN 0 ELSE 1 END) AS n_inactive_companies
FROM COMPANY
GROUP BY partner_manager_id
) T1
ON T1.partner_manager_id = PARTNER_MANAGER.id
select p.name "Partner Name"
, c1.cnt "n_active_companies"
, c2.cnt "n_inactive_companies"
from partner p
, (select partner_manager_id id, count(partner_manager_id) cnt from company where active = 'true' group by partner_manager_id) c1
, (select partner_manager_id id, count(partner_manager_id) cnt from company where active = 'false' group by partner_manager_id) c2
where c1.id = p.id
and c2.id = p.id
select p.name as 'partner_name',
sum(case when active then 1 else 0) as 'n_active_companies',
sum(case when active then 0 else 1) as 'n_inactive_companies'
from COMPANY c
join PARTNER_MANAGER pm on c.partner_manager_id = pm.id
join PARTNER p on pm.partner_id = p.id
group by p.name