SQL Join two query - sql

I need some help combining these two queries so I can get this in one single view.
Query 1
select t.*, n.caption, n.description
from (
select NodeID,
count(distinct cpuindex) as number_of_cpu,
case
When count(distinct cpuindex) < 8 THEN 1
Else count(distinct cpuindex)/8
End AS number_of_cores
from CPUMultiLoad_Detail (nolock) where nodeid in (select nodeid from nodesdata)
group by NodeID
) as t
inner join NodesData as n (nolock) on n.nodeid = t.nodeid
where n.description NOT Like '%Windows%'
order by n.description
Query 2
SELECT D.Environment, B.Name, C.Caption, A.ComponentStatisticData, A.ErrorMessage
FROM [APM_CurrentStatistics] A, APM_Application B, NodesData C
join NodesCustomProperties D on D.NodeID= C.NodeID
WHERE
A.ApplicationID=B.ID AND
A.NodeID=C.NodeID AND
B.Name IN ('Oracle Database Licensing')
I want to join first query and second query so I have CPU Information and Licensing Information in same table. How do I join both query? We can use common key Nodes.NodeID to join and not sure how. Any help will be greatly appreciated.

Consider joining the inner aggregate subquery of first query which holds distinct NodeID to the second query using a CTE. Additionally, use explicit JOIN(current standard in SQL) and heed bad habits to kick : using table aliases like (a, b, c) and use more informative table aliases.
WITH agg AS
(
select NodeID,
count(distinct cpuindex) as number_of_cpu,
case
when count(distinct cpuindex) < 8 THEN 1
else count(distinct cpuindex) / 8
end AS number_of_cores
from CPUMultiLoad_Detail
where nodeid in (select nodeid from nodesdata)
group by NodeID
)
SELECT cp.Environment, app.Name, n.Caption,
cs.ComponentStatisticData, cs.ErrorMessage,
agg.NodeID, agg.number_of_cpu, agg.number_of_cores, n.description
FROM APM_CurrentStatistics cs
INNER JOIN APM_Application app
ON cs.ApplicationID = app.ID
AND app.Name IN ('Oracle Database Licensing')
INNER JOIN NodesData n
ON cs.NodeID = n.NodeID
AND n.description NOT LIKE '%Windows%'
INNER JOIN NodesCustomProperties cp
ON cp.NodeID = n.NodeID
INNER JOIN agg
ON cs.NodeID = agg.NodeID
ORDER BY n.description

Related

Replace correlated subquery with CTE and JOIN

I am trying to rewrite a query which has a correlated subquery, the idea is to replace it with a CTE and join it later.
I have three tables, tbl_transaction, tbl_beneficiaries and tbl_reg_countries. The current (in short) SQL looks like the following.
SELECT
t.USER_ID,
t.TRANSACTION
FROM tbl_transactions t
JOIN tbl_beneficiaries b ON b.ID = t.USER_ID
WHERE b.COUNTRY NOT IN (
SELECT rc.country
FROM tbl_reg_countries rc
WHERE rc.id = t.USER.ID)
My goal is to query only those transactions for each user where the transaction happens outside of the registered countries. So a user may registered X,Y,Z country but had business with Q. In that case only Q should be returned. How could this be replaced with a CTE/JOIN?
I assume both tbl_beneficiaries.COUNTRY and tbl_reg_countries.COUNTRY are not nullable. You can use a LEFT JOIN with NULL test to detect never matching rows
SELECT
t.USER_ID,
t.TRANSACTION
FROM tbl_transactions t
JOIN tbl_beneficiaries b ON b.ID = t.USER_ID
LEFT JOIN tbl_reg_countries rc ON rc.id = t.USER_ID AND b.COUNTRY = rc.country
WHERE rc.country IS NULL
I would try rewriting query with "with"
Like this:
With a As
(Select
Distinct rc.country
From tbl_reg_countries rc
Inner Join tbl_transactions t on rc.id = t.USER.ID
)
Select
t.USER_ID,
t.TRANSACTION
From tbl_transactions t
Inner Join tbl_beneficiaries b On b.ID = t.USER_ID
Where b.COUNTRY Not In (select * from a)

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;

Nesting queries on JOINS and top1 with ties

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.

Limiting result sets by future date - SQL

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

SQL Join two query results

First SQL Query (Total Memroy)
SELECT
Nodes.NodeID AS NodeID, Nodes.TotalMemory AS TotalMemory, Nodes.Caption AS NodeName
FROM
(Nodes INNER JOIN Volumes ON (Nodes.NodeID = Volumes.NodeID))
Second SQL Query (Number of CPU on nodes)
SELECT N.Caption, COUNT(DISTINCT CPUIndex)
FROM CPUMultiLoad_Detail CPU WITH(NOLOCK)
JOIN Nodes N ON CPU.NodeID = N.NodeID
GROUP BY
N.Caption
Order By
N.Caption
I want to join first query and second query so i have both Total memory and Number of CPU on node in same table. How do i join both query? we can use common key Nodes.NodeID to join but how?
In the general case just use a join and a CTE
WITH PartOne AS
(
SELECT N.NodeID, COUNT(DISTINCT CPU.Index) as [Count]
FROM CPUMultiLoad_Detail CPU WITH(NOLOCK)
JOIN Nodes N ON CPU.NodeID = N.NodeID
GROUP BY N.Caption
)
SELECT Nodes.NodeID
Nodes.TotalMemory ,
Nodes.Caption AS NodeName,
PartOne.[Count]
FROM Nodes
INNER JOIN Volumes ON Nodes.NodeID = Volumes.NodeID
JOIN PartOne ON PartOne.NodeID = Nodes.NodeID
This particular case can also be done in one query like this:
SELECT Nodes.NodeID
Nodes.TotalMemory ,
Nodes.Caption AS NodeName,
COUNT(DISTINCT CPU.Index) OVER (PARTITION BY Nodes.Caption ORDER BY Nodes.Caption) AS [Count]
FROM Nodes
JOIN Volumes ON Nodes.NodeID = Volumes.NodeID
JOIN CPUMultiLoad_Detail CPU ON CPU.NodeID = Nodes.NodeID
For the same situation i used the Temp Table
SELECT ..... FROM.... INTO #Temp1
GO
SELECT ..... FROM.... INTO #Temp2
GO
SELECT ..... FROM #Temp1, #Temp2
WHERE #Temp1.NodeID = #Temp2.NodeID
Remember to Drop the Temp Tables like This:
DROP Table #Temp1
DROP Table #Temp2
"With" comes in help to have a clean query:
WITH CPUOnNodes AS (
SELECT N.NodeID, N.Caption, COUNT(DISTINCT CPUIndex)
FROM CPUMultiLoad_Detail CPU WITH(NOLOCK)
JOIN Nodes N ON CPU.NodeID = N.NodeID
GROUP BY N.NodeID, N.Caption
Order By N.Caption
)
SELECT N.NodeID, N.TotalMemory, N.Caption NodeName
FROM Nodes N
INNER JOIN Volumes V ON N.NodeID = V.NodeID
INNER JOIN CPUOnNodes C ON N.NodeID = C.NodeID
SELECT t1.col2,t2.col3 FROM (SELECT NodeID col1,TotalMemory col2,Caption col3 FROM Nodes)t1 join
(SELECT NodeID col1,Caption col2,COUNT(DISTINCT CPUIndex) col3 FROM CPUMultiLoad_Detail CPU WITH(NOLOCK) GROUP BY Caption Order By Caption)t2 ON t1.col1=t2.col1