SQL Server: JOIN two different queries - sql

sql-server does not have USING function. To join two different tables with multiple select statements we use 'ON' table1.ID = Table2.ID
SELECT *
FROM
(SELECT M.ID as MAPID, M.Name, Avg(Distance) 'Avg Road length', Max(Distance)'Max Length'
FROM MAP
inner join ROAD R on M.ID = R.MapID
GROUP BY M.ID, M.Name) T1
left join
SELECT *
FROM
(SELECT select R.MapID as MAPID, R.IDFrom, R.IDTo
from ROAD R
group by R.MapID, R.IDFrom, R.IDTo) T2 ON T1.MAPID = T2.MAPID
-- using (MAPID); (wrong)

Replace
USING (MAPID)
with
ON t1.mapid = t2.mapid

Related

How to create distinct count from queries with several tables

I am trying to create one single query that will give me a distinct count for both the ActivityID and the CommentID. My query in MS Access looks like this:
SELECT
tbl_Category.Category, Count(tbl_Activity.ActivityID) AS CountOfActivityID,
Count(tbl_Comments.CommentID) AS CountOfCommentID
FROM tbl_Category LEFT JOIN
(tbl_Activity LEFT JOIN tbl_Comments ON
tbl_Activity.ActivityID = tbl_Comments.ActivityID) ON
tbl_Category.CategoryID = tbl_Activity.CategoryID
WHERE
(((tbl_Activity.UnitID)=5) AND ((tbl_Comments.PeriodID)=1))
GROUP BY
tbl_Category.Category;
I know the answer must somehow include SELECT DISTINCT but am not able to get it to work. Do I need to create multiple subqueries?
This is really painful in MS Access. I think the following does what you want to do:
SELECT ac.Category, ac.num_activities, aco.num_comments
FROM (SELECT ca.category, COUNT(*) as num_activities
FROM (SELECT DISTINCT c.Category, a.ActivityID
FROM (tbl_Category as c INNER JOIN
tbl_Activity as a
ON c.CategoryID = a.CategoryID
) INNER JOIN
tbl_Comments as co
ON a.ActivityID = co.ActivityID
WHERE a.UnitID = 5 AND co.PeriodID = 1
) as caa
GROUP BY ca.category
) as ca LEFT JOIN
(SELECT c.Category, COUNT(*) as num_comments
FROM (SELECT DISTINCT c.Category, co.CommentId
FROM (tbl_Category as c INNER JOIN
tbl_Activity as a
ON c.CategoryID = a.CategoryID
) INNER JOIN
tbl_Comments as co
ON a.ActivityID = co.ActivityID
WHERE a.UnitID = 5 AND co.PeriodID = 1
) as aco
GROUP BY c.Category
) as aco
ON aco.CommentId = ac.CommentId
Note that your LEFT JOINs are superfluous because the WHERE clause turns them into INNER JOINs. This adjusts the logic for that purpose. The filtering is also very tricky, because it uses both tables, requiring that both subqueries have both JOINs.
You can use DISTINCT:
SELECT
tbl_Category.Category, Count(DISTINCT tbl_Activity.ActivityID) AS CountOfActivityID,
Count(DISTINCT tbl_Comments.CommentID) AS CountOfCommentID
FROM tbl_Category LEFT JOIN
(tbl_Activity LEFT JOIN tbl_Comments ON
tbl_Activity.ActivityID = tbl_Comments.ActivityID) ON
tbl_Category.CategoryID = tbl_Activity.CategoryID
WHERE
(((tbl_Activity.UnitID)=5) AND ((tbl_Comments.PeriodID)=1))
GROUP BY
tbl_Category.Category;

Query for records count from shown rows

select lsd.lsd ,count(reading.infrastructure_id),type.infrastructure_type from public.cpreading_lsd lsd
left join cpreading_infrastructure infra on lsd.id = infra.lsd_id
left join public.cpreading_infrastructure_type type on type.id = infra.infrastructure_type_id
left join cpreading_cp_reading_entry reading on infra.id = reading.infrastructure_id
group by lsd.lsd,type.infrastructure_type
Make the query as an in-line view and select count(*) from the in-line view
Eg:
select count(*) from(
select lsd.lsd
,count(reading.infrastructure_id)
,type.infrastructure_type
from public.cpreading_lsd lsd
left join cpreading_infrastructure infra on lsd.id = infra.lsd_id
left join public.cpreading_infrastructure_type type on type.id = infra.infrastructure_type_id
left join cpreading_cp_reading_entry reading on infra.id = reading.infrastructure_id
group by lsd.lsd,type.infrastructure_type
)x

SQL Multiple Joins not working as expected

I have following query not working when I try to join all 4 tables (It is taking over an hour to run, I have to eventually kill the query without any data being returned).
It works when Table 1,2 & 3 are joined AND Then If I try Table 1,2 & 4 join but not when I attempt to join all 4 tables below.
Select * From
(Select
R.ID, R.MId, R.RId, R.F_Name, R.F_Value, FE.FullEval, M.Name, RC.CC
FROM Table1 as R
Inner Join Table2 FE
ON R.ID = FE.RClId and R.MId = FE.MId and R.RId = FE.RId
Inner Join Table3 as M
ON R.MId = M.MId and FE.MId = M.MId
Inner Join Table4 as RC
ON R.RId = RC.RId and FE.RId = RC.RId and FE.Date = RC.Date
) AS a
NOTE:
1) RId is not available in table3.
2) MId is not available in table4.
Thanks for help.
Since you mentioned that you don't have permission to view the query plan, try breaking down into each table join. You can also check which table join is taking time to retrieve records. From there, you can investigate the data why it's taking time. It may be because of non-availability of column keys in Table 3 and Table 4?
WITH Tab1_2 AS
(SELECT r.ID, r.MId, r.RId, r.F_Name, r.F_Value, fe.FullEval, fe.date
FROM Table1 as r
INNER JOIN Table2 fe
ON r.ID = fe.RClId
AND r.MId = fe.MId
AND r.RId = fe.RId
WHERE ... -- place your conditions if any
),
Tab12_3 AS
(SELECT t12.*, m.Name
FROM Tab1_2 t12
INNER JOIN Table3 as m
ON t12.MId = m.MId
WHERE ... -- place your conditions if any
),
Tab123_4 AS
(SELECT t123.ID, t123.MId, t123.RId, t123.F_Name, t123.F_Value, t123.FullEval, rc.CC
FROM Tab12_3 t123
INNER JOIN Table4 as rc
ON t123.RId = rc.RId
AND t123.Date = rc.Date
WHERE ... -- place your conditions if any
)
SELECT *
FROM Tab123_4 t1234

FULL OUTER JOIN in oracle

I just noticed FULL OUTER JOIN is not working in Oracle.
Other queries work fine but when I fire the query with Full outer join, it takes time and gets disconnected throwing the error.
ORA-03113: end-of-file on communication channel
RIGHT OUTER JOIN and LEFT OUTER JOIN works fine.
What can be alternative for the query below where I am using full outer join to get all records ?
select * from
(
select
FTM_OFFICE_ID,
NVL(SUM(FTD_NRS_AMOUNT),0) as TOTAL
from FMS_TRANS_DTL
inner join FMS_TRANS_MST ON FMS_TRANS_MST.FTM_TRANS_MST_ID = FMS_TRANS_DTL.FTD_TRANS_MST_ID
inner join FMS_FC_VOUCHER_CONFIG ON FMS_FC_VOUCHER_CONFIG.FFVC_VOUCHER_ID = FMS_TRANS_MST.FTM_VOUCHER_ID
where FFVC_ACCOUNT_TYPE = 3 and FTM_FISCAL_YEAR='2066/67'
and FTD_ACC_ID in (select distinct FDP_DHARAUTI_C_ACC_ID from FMS_DHARAUTI_PARAMETER where FDP_FISCAL_YEAR='2066/67' )
/*and FTD_ACC_ID in (591)*/
group by FTM_OFFICE_ID
) T1
full outer join
(
select
FTM_OFFICE_ID,
NVL(SUM(FTD_NRS_AMOUNT),0) as TOTAL
from FMS_TRANS_DTL
inner join FMS_TRANS_MST ON FMS_TRANS_MST.FTM_TRANS_MST_ID = FMS_TRANS_DTL.FTD_TRANS_MST_ID
inner join FMS_FC_VOUCHER_CONFIG ON FMS_FC_VOUCHER_CONFIG.FFVC_VOUCHER_ID = FMS_TRANS_MST.FTM_VOUCHER_ID
where FFVC_ACCOUNT_TYPE = 3 and FTM_FISCAL_YEAR='2066/67'
/*and FTD_ACC_ID in (592)*/
and FTD_ACC_ID in
(select distinct FDP_DHARAUTI_L_ACC_ID from FMS_DHARAUTI_PARAMETER where FDP_FISCAL_YEAR='2066/67' )
group by FTM_OFFICE_ID
) T2
on T1.FTM_OFFICE_ID=T2.FTM_OFFICE_ID
/*
The no. of rows that T1 can have can be different that no. of rows T2 can have.
Its not necessary any OFFICE_ID must have amount under any FTD_ACC_ID.
*/
Just noticed that if I remove the sub query in condition for FTD_ACC_ID, the query runs perfectly. Why ?
workaround based on your query + followup comments is:
alter session set "_optimizer_cost_based_transformation"=off;
eg:
SQL> alter session set "_optimizer_cost_based_transformation"=off;
Session altered.
or in the sql as a hint
/*+ opt_param('_optimizer_cost_based_transformation', 'off')
eg
select /*+ opt_param('_optimizer_cost_based_transformation', 'off') */ * from
(
select FTM_OFFICE_ID,
you're possibly hitting bug:
BUG 4204383: ORA-7445[KKQTNLOCBK] USING QUERY WITH SUBQUERY AND FULL OUTER JOIN
which has patched available only on 10.2.0.2 onwards (fixed fully in 10.2.0.4).
FULL OUTER JOIN is supported just fine in Oracle.
The error you're experiencing sounds like an Oracle bug, or possible some form of corruption. You should find an error recorded in the alert.log whenever an ORA-03113 occurs.
Typically if you receive this error it's because the background oracle system process for that session has died (which is almost always due to an Oracle internal error).
This is a problem for your friendly local DBA.
If indeed (for whatever reason) a full outer join doesn't work for you, use
-- all rows present in both t1 and t2
select * from t1 inner join t2
union all
-- all rows present in t1 but not in t2
select * from t1 left outer join t2 where t2.pk is null
union all
-- all rows present in t2 but not in t1
select * from t1 right outer join t2 where t1.pk is null
instead of
select * from t1 full outer join t2
This will return the same result.
You can try this query:
SELECT
FTM_OFFICE_ID,
NVL(SUM(FTD_NRS_AMOUNT),0) AS TOTAL
FROM FMS_TRANS_DTL
INNER JOIN FMS_TRANS_MST ON FMS_TRANS_MST.FTM_TRANS_MST_ID = FMS_TRANS_DTL.FTD_TRANS_MST_ID
INNER JOIN FMS_FC_VOUCHER_CONFIG ON FMS_FC_VOUCHER_CONFIG.FFVC_VOUCHER_ID = FMS_TRANS_MST.FTM_VOUCHER_ID
WHERE FFVC_ACCOUNT_TYPE = 3 AND FTM_FISCAL_YEAR='2066/67'
AND FTD_ACC_ID IN (
SELECT DISTINCT FDP_DHARAUTI_C_ACC_ID FROM FMS_DHARAUTI_PARAMETER WHERE FDP_FISCAL_YEAR='2066/67'
UNION
SELECT DISTINCT FDP_DHARAUTI_L_ACC_ID FROM FMS_DHARAUTI_PARAMETER WHERE FDP_FISCAL_YEAR='2066/67'
)
GROUP BY FTM_OFFICE_ID
Looks like the only thing different is separate totals for FTD_ACC_ID values of 105 and 110. One approach would be to use CASE statements to total those separately.
select
FTM_OFFICE_ID,
NVL(SUM(CASE FTD_ACC_ID WHEN 105 THEN FTD_NRS_AMOUNT ELSE 0 END),0) as TOTAL_105,
NVL(SUM(CASE FTD_ACC_ID WHEN 110 THEN FTD_NRS_AMOUNT ELSE 0 END),0) as TOTAL_110,
from FMS_TRANS_DTL
inner join FMS_TRANS_MST ON FMS_TRANS_MST.FTM_TRANS_MST_ID = FMS_TRANS_DTL.FTD_TRANS_MST_ID
inner join FMS_FC_VOUCHER_CONFIG ON FMS_FC_VOUCHER_CONFIG.FFVC_VOUCHER_ID = FMS_TRANS_MST.FTM_VOUCHER_ID
where FFVC_ACCOUNT_TYPE = 3 and FTM_FISCAL_YEAR='2066/67'
and FTD_ACC_ID in (105,110)
group by FTM_OFFICE_ID
Use UNION instead of FULL OUTER JOIN in your query like this
select * from
(
select
FTM_OFFICE_ID,
NVL(SUM(FTD_NRS_AMOUNT),0) as TOTAL
from FMS_TRANS_DTL
inner join FMS_TRANS_MST ON FMS_TRANS_MST.FTM_TRANS_MST_ID = FMS_TRANS_DTL.FTD_TRANS_MST_ID
inner join FMS_FC_VOUCHER_CONFIG ON FMS_FC_VOUCHER_CONFIG.FFVC_VOUCHER_ID = FMS_TRANS_MST.FTM_VOUCHER_ID
where FFVC_ACCOUNT_TYPE = 3 and FTM_FISCAL_YEAR='2066/67'
and FTD_ACC_ID = 105
group by FTM_OFFICE_ID ) T1 union (select FTM_OFFICE_ID,
NVL(SUM(FTD_NRS_AMOUNT),0) as TOTAL
from FMS_TRANS_DTL
inner join FMS_TRANS_MST ON FMS_TRANS_MST.FTM_TRANS_MST_ID = FMS_TRANS_DTL.FTD_TRANS_MST_ID
inner join FMS_FC_VOUCHER_CONFIG ON FMS_FC_VOUCHER_CONFIG.FFVC_VOUCHER_ID = FMS_TRANS_MST.FTM_VOUCHER_ID
where FFVC_ACCOUNT_TYPE = 3 and FTM_FISCAL_YEAR='2066/67'
and FTD_ACC_ID = 110
group by FTM_OFFICE_ID )T2

JOIN / LEFT JOIN conflict in SQL Server

I have a tricky query. I need to select all recent versions of 2 types of members of administrator groups. Here is the query:
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
This query will return all the administrator groups. The next step will be getting the members of these groups. Since I have 2 types of memberships (Explicit, Computed), I will have to use a LEFT JOIN to make sure that I am not excluding any rows.
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
-- The JOIN bellow can be excluded but it is here just to clarify the architecture
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
LEFT JOIN tblGroup_ComputedMember cm ON refMem.ObjectUID = cm.GroupObjectID
LEFT JOIN tblGroup_ExplicitMember em ON refMem.ObjectUID = em.GroupObjectID
The last piece in the puzzle is to get the latest version of each member. For that I will have to use JOIN to exclude older versions:
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ComputedMember
GROUP BY ObjectID
) MostRecentCM ON MostRecentCM.MaxId = cm.Id
and
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ExplicitMember
GROUP BY ObjectID
) MostRecentEM ON MostRecentEM.MaxId = em.Id
The full query will be:
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
LEFT JOIN tblGroup_ComputedMember cm ON refMem.ObjectUID = cm.GroupObjectID
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ComputedMember
GROUP BY ObjectID
) MostRecentCM ON MostRecentCM.MaxId = cm.Id
LEFT JOIN tblGroup_ExplicitMember em ON refMem.ObjectUID = em.GroupObjectID
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ExplicitMember
GROUP BY ObjectID
) MostRecentEM ON MostRecentEM.MaxId = em.Id
The issue is clear: The 2 JOIN to exclude old versions are also applied to the select statement and clearly no rows are returned. What would be the best solution to escape such situation and to return the intended values?
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
LEFT JOIN (
select GroupObjectID, ID, max(ID) over (partition by ObjectID) as maxID
from tblGroup_ComputedMember
) cm ON refMem.ObjectUID = cm.GroupObjectID and cm.ID = cm.maxID
LEFT JOIN (
select GroupObjectID, ID, max(ID) over (partition by ObjectID) as maxID
from tblGroup_ExplicitMember
) em ON refMem.ObjectUID = em.GroupObjectID and em.ID = em.maxID
where cm.ID = cm.MaxID
What about using LEFT join in your last two joins?
LEFT JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ComputedMember
GROUP BY ObjectID
) MostRecentCM ON MostRecentCM.MaxId = cm.Id
And then in Where clause filter values as:
WHERE MostRecentCM.MaxId IS NOT NULL
OR
MostRecentEM.MaxId IS NOT NULL