I am trying to use the result of the below SQL query-1 such that I can make another JOIN on this with my second query result to retrieve Fundsrc on the common ID - Project.
QUERY 1-
SELECT top 1 with ties
t.project, r.rel_value AS "FundSrc" ,r.date_to
from atsproject t
LEFT OUTER JOIN aglrelvalue r ON(t.client=r.client AND r.rel_attr_id='ZB18' AND r.attribute_id='B0' AND t.project=r.att_value)
WHERE r.date_To > '04/30/2020' and status='n'
ORDER BY row_number() over (partition by t.project order by t.project, r.rel_value)
I cannot put the JOIN inside the above query as it will mess with the result. Instead, if I can do a nesting on this then I think that should solve the issue.
My second query is -
SELECT
t.project,t.work_order as activity, r1.labor_funding_source2_fx AS "Designated Labour Funding"
FROM atsworkorder t
LEFT OUTER JOIN afxactlaborfund r1 ON( t.work_order = r1.dim_value AND t.client = r1.client AND r1.attribute_id = 'BF')
WHERE t.client='PC' and t.status = 'N'
The Output should be -
t.project,t.work_order from query 2 + Fundsrc from Query 1, with the common id on Project ID.
Any suggestions on this is highly appreciated.
You can wrap 'subqueries' in parenthesis and then join them.
Can you try this?:
SELECT *
FROM (
SELECT top 1 with ties t.project,
r.rel_value AS "FundSrc",
r.date_to
FROM atsproject t
LEFT OUTER JOIN aglrelvalue r
ON t.client=r.client
AND r.rel_attr_id='ZB18'
AND r.attribute_id='B0'
AND t.project=r.att_value
WHERE r.date_To > '04/30/2020' and status='n'
ORDER BY row_number() over (partition by t.project order by t.project, r.rel_value)
) AS TABLE_1
LEFT JOIN
(
SELECT t.project,
t.work_order as activity,
r1.labor_funding_source2_fx AS "Designated Labour Funding"
FROM atsworkorder t
LEFT OUTER JOIN afxactlaborfund r1
ON t.work_order = r1.dim_value
AND t.client = r1.client
AND r1.attribute_id = 'BF'
WHERE t.client='PC' and t.status = 'N'
) AS TABLE_2
ON TABLE_1.PROJECT = TABLE2.PROJECT
I am pretty sure an ORDER BY clause will not work within a subquery. Thus, this should probably work:
SELECT *
FROM (
SELECT t.project,
r.rel_value AS "FundSrc",
r.date_to,
row_number() over (partition by t.project order by t.project, r.rel_value) AS MY_RANKING
FROM atsproject t
LEFT OUTER JOIN aglrelvalue r
ON t.client=r.client
AND r.rel_attr_id='ZB18'
AND r.attribute_id='B0'
AND t.project=r.att_value
WHERE r.date_To > '04/30/2020' and status='n'
) AS TABLE_1
LEFT JOIN
(
SELECT t.project,
t.work_order as activity,
r1.labor_funding_source2_fx AS "Designated Labour Funding"
FROM atsworkorder t
LEFT OUTER JOIN afxactlaborfund r1
ON t.work_order = r1.dim_value
AND t.client = r1.client
AND r1.attribute_id = 'BF'
WHERE t.client='PC' and t.status = 'N'
) AS TABLE_2
ON TABLE_1.PROJECT = TABLE2.PROJECT
WHERE TABLE_1.MY_RANKING = 1
Note: On your formatting, wrap words within ` when they refer to code. They will look like this.
Wrap blocks of code within three of those (three at the beginning and at the end). It will look like the blocks of code above.
Related
I have two query to combine two results into one. However; my challenge is to get the second query look into the first query if it doesn't exist in the first query.
I changed my post to the actual query
SELECT Name.CO_ID, Name.FULL_NAME, Name.ID, rpt.date AS StartDate,
vw_Coords.TARGET_ID AS CoordID, vw_RegDirs.TARGET_ID AS
RDID
FROM Name INNER JOIN
Tops_Profile ON dbo.Name.ID = Tops_Profile.ID left
outer JOIN
vw_mz_rpt_leader_log rpt ON Name.CO_ID = rpt.ID LEFT
OUTER JOIN
vw_RegDirs ON Name.CO_ID = vw_RegDirs.CHAPTER LEFT
OUTER JOIN
vw_Coords ON Name.CO_ID = vw_Coords.CHAPTER LEFT OUTER
JOIN
Tops_Chapter ON Tops_Chapter.ID = Name.CO_ID
WHERE (Name.MEMBER_TYPE = 'm') AND (Tops_Profile.LDR = '1') and
LOG_TEXT like '%LEADER Change%'
union
SELECT Name.CO_ID, Name.FULL_NAME, Name.ID,
YEAR(dbo.Tops_Chapter.PST_DATE_LEAD) AS StartDate,
vw_Coords.TARGET_ID AS CoordID, vw_RegDirs.TARGET_ID AS
RDID
FROM Name INNER JOIN
Tops_Profile ON Name.ID = Tops_Profile.ID left outer
JOIN
vw_mz_rpt_leader_log rpt ON Name.CO_ID = rpt.ID LEFT
OUTER JOIN
vw_RegDirs ON Name.CO_ID = vw_RegDirs.CHAPTER LEFT
OUTER JOIN
vw_Coords ON Name.CO_ID = vw_Coords.CHAPTER LEFT OUTER
JOIN
Tops_Chapter ON Tops_Chapter.ID = Name.CO_ID
WHERE (Name.MEMBER_TYPE = 'm') AND (Tops_Profile.LDR = '1')
the scope is if the record exists in the first query don't bring it from second query.
Here's a quick and dirty way...
select *
from
(select id, Name, log.Date
from Name
inner join Log on Name.id = log.id
where log.text_log like '%Leader%'
union
select id, Name, Profile.Date
from Name
inner join profile on Name.id = profile.id
where profile.Leader = '1') d
order by row_number() over(partition by x.id order by x.Date asc)
Note, this doesn't care where John came from, it's simply finding the first occurrence based on the date which seems to be what you want.
You have altered your request. Suddenly both queries select from the same tables and a UNION (or UNION ALL for that matter) doesn't seem a good solution anymore.
There are very few differences between the two queries even. And looking at the whole it boils down to: select records for member_type = 'm' and tp.ldr = 1 and then keep only one record per name, preferredly one with log_text like '%LEADER Change%'. This is mere ranking, as already shown in my other answer. You only need one query to select all records in question and use TOP (1) WITH TIES to keep the best matches per name.
select top(1) with ties
n.co_id,
n.full_name,
n.id,
case when log_text like '%LEADER Change%' then rpt.date else year(tc.pst_date_lead) end
as startdate,
c.target_id as coordid,
rd.target_id as rdid
from name n
inner join tops_profile tp on n.id = tp.id
left outer join vw_mz_rpt_leader_log rpt on n.co_id = rpt.id
left outer join vw_regdirs rd on n.co_id = rd.chapter
left outer join vw_coords c on n.co_id = c.chapter
left outer join tops_chapter tc on tc.id = n.co_id
where n.member_type = 'm'
and tp.ldr = 1
order by row_number() over (
partition by n.id
order by case when log_text like '%LEADER Change%' then 1 else 2 end);
As you said you just want only one record per name, I am using ROW_NUMBER. If you want more, use RANK instead.
It's not clear why you are joining the tops_chapter table. Is log_text a column in that table? (You should use a table qualifier for this column in your query.) If it isn't, then the join is superfluous and you can remove it from your query.
Use row_number and select id's with least date
with cte as
(select id, Name, log.Date
from Name
inner join Log on Name.id = log.id
where log.text_log like '%Leader%'
union all
select id, Name, Profile.Date as log.date
from Name
inner join profile on Name.id = profile.id
where profile.Leader = '1'
) , ct1 as (select id,name,log.date, ROW_NUMBER() over (partition by id order by log.date) rn from cte )
select id,name,log.date from ct1 where rn = 1
where profile.Leader = '1'
and id not in ( select Name.id
from Name
inner join Log
on Name.id = log.id
where log.text_log like '%Leader%' )
You can use NOT EXISTS in the second query to filter out already existing Name records:
select id, Name, log.Date
from Name
inner join Log on Name.id = log.id
where log.text_log like '%Leader%'
union
select n1.id, n1.Name, Profile.Date
from Name as n1
inner join profile on n1.id = profile.id
where profile.Leader = '1' and
not exists (select 1
from Name as n2
inner join Log on n2.id = Log.id
where Log.text_log like '%Leader%' and
n2.id = n1.id and n2.name = n1.name)
The query below finds logdate and profiledate for each name. If there is a logdate, the logdate will be diplayed else the profile date will be displayed. If both don't exist the Name won't be displayed.
select id, Name, coalesce(log.Date,profile.date)
from Name
left join Log on Name.id = log.id and log.text_log like '%Leader%'
left join profile on Name.id = profile.id and profile.Leader = '1'
where coalesce(log.Date,profile.date) is not null
You can add a rank to your two queries. Then per ID you keep the record(s) with the better rank (using ORDER BY with TOP (1) WITH TIES).
select top(1) with ties
id, name, date
from
(
select n.id, n.name, log.date, 1 as rnk
from name n
inner join log on name.id = log.id
where log.text_log like '%Leader%'
union all
select n.id, n.name, profile.date, 2 as rnk
from name n
inner join profile on name.id = profile.id
where profile.leader = '1'
) data
order by rank() over (partition by id order by rnk);
I have a database structure (ER diagram below) that has three level of hierarchical data and the fourth level of optional data.
If I write a query to get de-normalized data of three levels - level 1 to level 3 with sample data across three tables shown as below:
When queried, this layout of the data is very straight forward and as expected as below:
Upon running the below query, I get the following output (And I have tried various combinations by clubbing the set of L1 to L4 and moving one L4 out as a another query and then joining the set L1 - L4 etc.) - again this is on the expected lines.
SELECT [Group].GroupId, [Group].GroupName, Category.CategoryId, Category.CategoryName, RLI.RLIId, RLI.RLIText, Comment.CommentId, Comment.CommentText, ManagementResponse.ManagementResponseId,
ManagementResponse.ManagementResponseTest
FROM Category INNER JOIN
[Group] ON Category.GroupId = [Group].GroupId INNER JOIN
RLI ON Category.CategoryId = RLI.CategoryId LEFT OUTER JOIN
ManagementResponse ON RLI.RLIId = ManagementResponse.RLIId LEFT OUTER JOIN
Comment ON RLI.RLIId = Comment.RLIId
However, I need data in the following format - and this is what I am unable to figure out how to get (I don't want the level 4 data to repeat as I add additional level 4 data via left outer joins):
This query will give you the final output:
WITH CommentAndResponse AS (
SELECT Comment.CommentId,
Comment.CommentText,
ManagementResponse.ManagementResponseId,
ManagementResponse.ManagementResponseTest,
COALESCE(Comment.RLIId, ManagementResponse.RLIId) AS RLIId
FROM (
(SELECT Comment.CommentId,
Comment.CommentText,
Comment.RLIId,
ROW_NUMBER() OVER (PARTITION BY Comment.RLIId ORDER BY Comment.CommentId) AS CommentRowNumber
FROM Comment) AS Comment
FULL JOIN
(SELECT ManagementResponse.ManagementResponseId,
ManagementResponse.ManagementResponseTest,
ManagementResponse.RLIId,
ROW_NUMBER() OVER (PARTITION BY ManagementResponse.RLIId ORDER BY ManagementResponse.ManagementResponseId) AS ManagementResponseRowNumber
FROM ManagementResponse) AS ManagementResponse
ON Comment.CommentRowNumber = ManagementResponse.ManagementResponseRowNumber AND Comment.RLIId = ManagementResponse.RLIId )
)
SELECT [Group].GroupId, [Group].GroupName, Category.CategoryId, Category.CategoryName, RLI.RLIId, RLI.RLIText, CommentAndResponse.CommentId, CommentAndResponse.CommentText, CommentAndResponse.ManagementResponseId, CommentAndResponse.ManagementResponseTest
FROM [Category]
INNER JOIN [Group] ON Category.GroupId = [Group].GroupId
INNER JOIN [RLI] ON Category.CategoryId = RLI.CategoryId
LEFT OUTER JOIN [CommentAndResponse] ON RLI.RLIId = CommentAndResponse.RLIId
You need to specify that Comment.CommentId is equal to ManagementResponse.ManagementResponseId or either is null. That can be part of a JOIN or a separate WHERE
SELECT [Group].GroupId, [Group].GroupName, Category.CategoryId, Category.CategoryName, RLI.RLIId, RLI.RLIText, Comment.CommentId, Comment.CommentText, ManagementResponse.ManagementResponseId,
ManagementResponse.ManagementResponseTest
FROM [Category]
INNER JOIN [Group] ON Category.GroupId = [Group].GroupId
INNER JOIN [RLI] ON Category.CategoryId = RLI.CategoryId
LEFT OUTER JOIN [ManagementResponse] ON RLI.RLIId = ManagementResponse.RLIId
LEFT OUTER JOIN [Comment] ON RLI.RLIId = Comment.RLIId
WHERE ManagementResponse.ManagementResponseId = Comment.CommentId OR ManagementResponse.ManagementResponseId IS NULL OR Comment.CommentId IS NULL
This assumes that those IDs begin equal is the relationship you want to model. The example data seems to show this, but it could be a coincidence of how you assembled the example. Alternatively, if there is no relationship between Comment and ManagementResponse besides RLIId, something like
WITH CommentAndResponse AS (
SELECT Comment.CommentId, Comment.CommentText, ManagementResponse.ManagementResponseId, ManagementResponse.ManagementResponseTest,
COALESCE(Comment.RLIId, ManagementResponse.RLIId) AS RLIId,
ROW_NUMBER() OVER (ORDER BY Comment.CommentId, ManagementResponse.ManagementResponseId, PARTITION BY Comment.RLIId, ManagementResponse.RLIId) AS rn
FROM Comment
FULL JOIN ManagementResponse ON Comment.RLIId = ManagementResponse.RLIId)
SELECT [Group].GroupId, [Group].GroupName, Category.CategoryId, Category.CategoryName, RLI.RLIId, RLI.RLIText, CommentAndResponse.CommentId, CommentAndResponse.CommentText, CommentAndResponse.ManagementResponseId, CommentAndResponse.ManagementResponseTest
FROM [Category]
INNER JOIN [Group] ON Category.GroupId = [Group].GroupId
INNER JOIN [RLI] ON Category.CategoryId = RLI.CategoryId
LEFT OUTER JOIN [CommentAndResponse] ON RLI.RLIId = CommentAndResponse.RLIId AND CommentAndResponse.rn = 1
I have my initial statement which is :
SELECT TEAM.ID PKEY_SRC_OBJECT,
TEAM.MODF_DAT UPDATE_DATE,
TEAM.MODF_USR UPDATED_BY,
PERSO.FIRST_NAM FISRT_NAME
FROM TEAM
LEFT OUTER JOIN PERSO ON (TEAM.ID=PERSO.TEAM_ID)
I want to calculate some "flags" and return them in my initial statement.
There are 3 flags which can be calculated like this :
1) Flag ISMASTER:
SELECT Count(*)
FROM TEAM_TEAM_REL A, TEAM B
WHERE B.PARTY_PTY_ID = A.RLTD_TEAM_ID
AND CODE = 'Double';
2) Flag ISAGENT:
SELECT Count(*)
FROM TEAM_ROL_REL A, TEAM B
WHERE B.PARTY_PTY_ID = A.TEAM_ID;
3) Flag NUMPACTS:
SELECT Count(*)
FROM TEAM_ROL_REL A,
TEAM_ROL_POL_REL B,
PERSO_POL_STA_REL C,
TEAM D
WHERE A.ROL_CD IN ('1','2')
AND A.T_ROL_REL_ID = B.P_ROL_REL_ID
AND B.P_POL_ID = C.P_POL_ID
AND C.STA_CD = 'A'
AND D.PARTY_PTY_ID = A.TEAM_ID;
To try to achieve this, I've updated my initial statement like this :
WITH ABC AS (
SELECT TEAM.ID PKEY_SRC_OBJECT,
TEAM.MODF_DAT UPDATE_DATE,
TEAM.MODF_USR UPDATED_BY,
PERSO.FIRST_NAM FISRT_NAME
FROM TEAM
LEFT OUTER JOIN PERSO ON (TEAM.ID=PERSO.TEAM_ID)
)
SELECT ABC.*, MAST.ISMASTER, AGENT.ISAGENT, PACTS.NUMPACTS FROM ABC
LEFT OUTER JOIN (
select
RLTD_TEAM_ID,
Count(RLTD_TEAM_ID) OVER (PARTITION BY RLTD_TEAM_ID) as ISMASTER
FROM TEAM_TEAM_REL
WHERE CODE = 'Double'
) MAST
ON ABC.PKEY_SRC_OBJECT = MAST.RLTD_TEAM_ID
LEFT OUTER JOIN (
select
TEAM_ID,
Count(TEAM_ID) OVER (PARTITION BY TEAM_ID) as ISAGENT
FROM TEAM_ROL_REL
) AGENT
ON ABC.PKEY_SRC_OBJECT = AGENT.TEAM_ID
LEFT OUTER JOIN (
select
TEAM_ID,
Count(TEAM_ID) OVER (PARTITION BY TEAM_ID) as NUMPACTS
FROM TEAM_ROL_REL, TEAM_ROL_POL_REL, PERSO_POL_STA_REL
WHERE TEAM_ROL_REL.ROL_CD IN ('1','2')
AND TEAM_ROL_REL.T_ROL_REL_ID = TEAM_ROL_POL_REL.P_ROL_REL_ID
AND TEAM_ROL_POL_REL.P_POL_ID = PERSO_POL_STA_REL.P_POL_ID
AND PERSO_POL_STA_REL.STA_CD = 'A'
) PACTS
ON ABC.PKEY_SRC_OBJECT = PACTS.TEAM_ID;
For the two first flags (ISMASTER and ISAGENT) I get the result in less than 1min, but for the last flag (NUMPACTS) it runs few minutes without provide any result.
I think my statement is too heavy, maybe I should do it in a totally different way.
I think you have perhaps over complicated things.
You could do this (assuming I have understood your requirements correctly) like so:
WITH ttr AS (SELECT rltd_team_id,
COUNT(*) is_master
FROM team_team_rel
AND CODE = 'Double'
GROUP BY rltd_team_id),
trr AS (SELECT team_id,
COUNT(*) is_agent
FROM team_rol_rel
GROUP BY team_id)
pacts AS (SELECT trr1.team_id,
COUNT(*) num_pacts
FROM team_rol_rel trr1
INNER JOIN team_rol_pol_rel trpr ON (trr1.t_rol_rel_id = trpr.p_rol_rel_id)
INNER JOIN perso_pol_sta_rel ppsr ON (trpr.p_pol_id = ppsr.p_pol_id
WHERE trr1.rol_cd IN ('1', '2')
AND ppsr.st_cd = 'A'
GROUP BY trr1.team_id)
SELECT t.id pkey_src_object,
t.modf_dat update_date,
t.modf_usr updated_by,
p.first_nam first_name,
ttr.is_master,
trr.is_agent,
pacts.num_pacts
FROM team t
LEFT OUTER JOIN perso p ON t.id = p.team_id
LEFT OUTER JOIN ttr ON t.party_pty_id = ttr.rltd_team_id
LEFT OUTER JOIN trr ON t.party_pty_id = trr.team_id
LEFT OUTER JOIN pacts ON t.pkey_src_object = pacts.team_id;
N.B. untested, since you didn't provide any test data.
The Query below produces a record for each Entry in the SP_ScheduleEvent Table.
SELECT m.MaterialId, m.MaterialTitle, se.EventDateTime, c.ChannelName
FROM GB_Material m
LEFT OUTER JOIN SP_ScheduleEvent se on se.MaterialName = m.MaterialName
INNER JOIN SP_Schedule s on s.ScheduleID = se.ScheduleID
INNER JOIN GB_Channel c on c.ChannelID = s.ChannelID
WHERE LOWER(m.MaterialName) like '%foo%' OR LOWER(m.MaterialTitle) like '%foo%'
I want to limit the result set by the nearest future EventDateTime.
So per material name i would like to see one EventDateTime, which should be the nearest future date to the current time.
And lastly, a record may not exist in the SP_ScheduleEvent table for a particular materialname, in which case there should be null returned for the EventDateTime column
SQLFiddle
How would i go about doing this?
First, your LEFT JOIN is immaterial, because the subsequent joins make it an INNER JOIN. Either use LEFT JOIN throughout the FROM statement or switch to INNER JOIN.
I think you can use ROW_NUMBER():
SELECT t.*
FROM (SELECT m.MaterialId, m.MaterialName, m.MaterialTitle, se.EventDateTime,
ROW_NUMBER() over (PARTITION BY m.MaterialId OVER se.EventDateTime DESC) as seqnum
FROM GB_Material m INNER JOIN
SP_ScheduleEvent se
on se.MaterialName = m.MaterialName INNER JOIN
SP_Schedule s
on s.ScheduleID = se.ScheduleID INNER JOIN
GB_Channel c
on c.ChannelID = s.ChannelID
WHERE se.EventDateTime > getdate() AND
(LOWER(m.MaterialName) like '%foo%' OR LOWER(m.MaterialTitle) like '%foo%')
) t
WHERE seqnum = 1
ORDER BY se.EventDateTime;
Use the ROW_NUMBER() function:
WITH cte AS (
SELECT m.MaterialId, m.MaterialTitle, se.EventDateTime, c.ChannelName,
ROW_NUMBER() OVER (PARTITION BY m.MaterialId ORDER BY EventDateTime ASC) AS rn
FROM GB_Material m
LEFT OUTER JOIN SP_ScheduleEvent se on se.MaterialName = m.MaterialName
LEFT OUTER JOIN SP_Schedule s on s.ScheduleID = se.ScheduleID
LEFT OUTER JOIN GB_Channel c on c.ChannelID = s.ChannelID
WHERE LOWER(m.MaterialName) like '%foo%' OR LOWER(m.MaterialTitle) like '%foo%'
AND se.EventDateTime > GETDATE()
)
SELECT * FROM cte
WHERE rn=1
I'm trying to fetch data for my forum's index. Fetching a list of all the boards, the number of threads in that board, and the number of posts for each of those threads in that board.
SELECT
board.*,
IFNULL(a.thread_count, 0) AS thread_count,
b.post_count
FROM
(SELECT * FROM r_forum_boards ORDER BY position) board
LEFT OUTER JOIN
(SELECT r_forum_threads.board, r_forum_threads.id,
COUNT(r_forum_threads.id) AS thread_count
FROM r_forum_threads) a
ON board.id = a.board
LEFT OUTER JOIN
(SELECT r_forum_posts.thread_id, COUNT(*) AS post_count
FROM r_forum_posts) b
ON b.thread_id = a.id
The problem is that post_count is returning NULL. I've tried a few different variations of this, but none of them are working.
I'm guessing from the IFNULL that your SQL is MySQL-flavored. In that case, you can use COUNT DISTINCT to simplify things.
SELECT
board.id,
COUNT(DISTINCT r_forum_threads.id) AS thread_count,
COUNT(r_forum_posts.id) AS post_count
FROM board
LEFT OUTER JOIN r_forum_threads ON board.id = r_forum_threads.board
LEFT OUTER JOIN r_forum_posts ON r_forum_posts.thread_id = r_forum_threads.id
GROUP BY board.id
ORDER BY board.position
Depending on how much of board.* you actually need, either add columns to the SELECT and GROUP or use this as a subquery to join back to board.
Try putting in a GROUP clause:
LEFT OUTER JOIN
(SELECT r_forum_threads.board, r_forum_threads.id, COUNT(r_forum_threads.id) AS thread_count FROM r_forum_threads GROUP BY r_forum_threads.id) a
ON board.id = a.board
LEFT OUTER JOIN
(SELECT r_forum_posts.thread_id, COUNT(*) AS post_count FROM r_forum_posts GROUP BY r_forum_posts.thread_id) b ON b.thread_id = a.id
See if that does the trick.
Perhaps because you are missing the Group By clause in your subqueries? In addition, you do not need the first subquery.
Select board...
, Coalesce(a.thread_count, 0) AS thread_count
, b.post_count
From r_forum_boards
Left Join (
Select r_forum_threads.board
, r_forum_threads.id
, Count(r_forum_threads.id) AS thread_count
From r_forum_threads
Group By r_forum_threads.board
, r_forum_threads.id
) a
On a.board = board.id
Left Join (
Select r_forum_posts.thread_id
, Count(*) AS post_count
From r_forum_posts
Group By r_forum_posts.thread_id
) As b
On b.thread_id = a.id
Order By r_forum_boards.position
You might consider changing the query slightly to make it easier to test:
Select board...
, Coalesce(a.thread_count, 0) AS thread_count
, A.post_count
From r_forum_boards
Left Join (
Select r_forum_threads.board
, r_forum_threads.id
, Count(r_forum_threads.id) AS thread_count
, Posts.post_count
From r_forum_threads
Left Join (
Select r_forum_posts.thread_id
, Count(*) AS post_count
From r_forum_posts
Group By r_forum_posts.thread_id
) As Posts
On Posts.thread_id = r_forum_threads.Id
Group By r_forum_threads.board
, r_forum_threads.id
) As A
On A.board = board.id
Order By r_forum_boards.position
In this way, you can run the single inner query and ensure you A. get results and B. get values for post_count.
The problem I see is that you're trying to get 2 related but slightly conflicting pieces of data, and probably 2 queries will get you what you need.
You first need a query to get the board names and the number of threads in each board.
Select Board.*, GroupThread.threadCount
FROM r_forum_boards Board
INNER JOIN (Select board_id, count(*) as threadCount from r_forum_threads group by board_id) GroupThread ON Board.board_id = GroupThread.board_id
Second, for each thread, you need the posts, which are calculated in basically the same way:
Select Thread.*, GroupPosts.postCount
FROM r_forum_threads Thread
INNER JOIN (Select thread_id, count(*) as postCount from r_forum_posts group by thread_id) GroupPosts ON Thread.board_id = GroupPosts.thread_id
In each of these cases, you look at the parent object, and count the children.