How to combine those three SQL queries - sql

How to combine this three queries without giving me the same output ?
The first query is :
select
vwemployee.directorateName,
count(vwemployeeCourse.employeeId) as t1
from
vwemployee, vwemployeeCourse
where
vwemployee.directorateName = vwemployeeCourse.directorateName
group by
vwemployee.directorateName
This is the second query :
select
vwemployee.directorateName,
count(vwemployee.directorateName) as t2
from
vwemployee, employeeCourse
where
vwemployee.Id = employeeCourse.employeeId
group by
vwemployee.directorateName
This is the third query :
select
vwemployeeCourse.directorateName, sum(vwCourse.cost) as t3
from
vwemployeeCourse, vwCourse
where
vwemployeeCourse.courseId = vwCourse.Id
group by
vwemployeeCourse.directorateName
I will be using the combined query to generate a report
the t1 column should display how many courses this specific directorate took
the t2 column should display how many employee's under this directorate took this courses
the t3 column should display how much the courses cost for every directorate
So the total columns of the table of the combined query should be 4 columns
FYI: some nice people here helped me to combine the first two queries but it was not sample at all and i didn't succeed to add the third query to them since I am a beginner so please help me with a full simple query to understand it for future references

I think you are looking for something like this. We can achieve this using NESTED CTEs. You can see here I have created 3 nested CTEs, and in the end I have used all the three CTEs to get your result.
with cte1 as
(
select vwemployee.directorateName , count(vwemployeeCourse.employeeId) as t1
from vwemployee , vwemployeeCourse
where vwemployee.directorateName = vwemployeeCourse.directorateName
GROUP BY vwemployee.directorateName
)
,cte2 as
(
select vwemployee.directorateName , count(vwemployee.directorateName) as t2
from vwemployee , employeeCourse
where vwemployee.Id = employeeCourse.employeeId
GROUP BY vwemployee.directorateName
)
,cte3 as
(
select vwemployeeCourse.directorateName , sum(vwCourse.cost) as t3
from vwemployeeCourse , vwCourse
where vwemployeeCourse.courseId = vwCourse.Id
group by vwemployeeCourse.directorateName
)
select cte1.directorateName, cte1.t1, cte2.t2, cte3.t3
from
cte1 inner join cte2
on cte1.directorateName = cte2.directorateName
inner join cte3 on
cte2.directorateName = cte3.directorateName

First, you should be using explicit JOIN syntax. Simple rule: Never use commas in the FROM clause.
Then, given the three queries as written, with no other information, I think I would go for full outer join or union all with aggregation:
with ec as (
select e.directorateName, count(ec.employeeId) as t1
from vwemployee e join
vwemployeeCourse ec
on e.directorateName = ec.directorateName
group by e.directorateName
),
ed as (
select e.directorateName, count(ec.directorateName) as t2
from vwemployee e join
vwemployeeCourse ec
on e.id = ec. employeeId
group by e.directorateName
),
cc as (
select ec.directorateName, sum(c.cost) as t3
from vwemployeeCourse ec join
vwCourse c
ec.courseId = c.Id
group by ec.directorateName
)
select directoratename,
coalesce(t1, 0) as t1,
coalesce(t2, 0) as t2,
coalesce(t3, 0) as t3
from ((select directoratename, t1, null as t2, null as t3 from ec)
union all
(select directoratename, null as t1, t2, null as t3 from ed)
union all
(select directoratename, null as t1, null as t2, t3 from cc)
) t;
Having said that, I don't think this query can actually do anything useful. Joining two tables on two different keys, and then aggregating by the same key (as for ec and ed) is not usually done. If this doesn't produce the results you want, then ask another question, provide sample data, desired results, and a SQL Fiddle.

Related

SQL Multiple INNER JOINS In One Select-Statement

I am using this code for inventory management system, in which i want to retrieve stock in hand from four tables. i have tried with two table and got accurate result as i need it.please help me out.
Table Schema
Productmastertb
prod_id,
Product_name
salesdetailstb
sales_id,
Prod_id,
Prod_qty
estimatedetailstb
est_id,
Prod_id,
Prod_qty
Purchasedetailstb
est_id,
Prod_id,
Prod_qty
Query example (working):
SELECT
productmastertb.prod_id,
productmastertb.prod_name,
sum(estimatedetailstd.prod_qty) as Est_qty
FROM
productmaster
INNER JOIN
estimatedetailstb ON productmastertb.prodid = estimatedetails.prodid
GROUP BY
productmastertb.prod_id, productmastertb.prod_name
Similarly I have to retrieve sum of salesdetailstb.qty and purchasedetailstb.qty
Thanks in advance
You want to summarize across different "dimensions" -- that is tables. One good approach is to aggregate before doing the JOINs. Or to use subqueries. Here is the latter approach:
SELECT pm.prod_id, pm.prod_name,
(SELECT SUM(ed.prod_qty)
FROM estimatedetailstb as ed
WHERE ed.prodid = ed.prodidas
) as Est_qty,
(SELECT SUM(sd.prod_qty)
FROM salesdetailstb as sd
WHERE sd.prodid = pm.prodidas
) as Sales_qty,
(SELECT SUM(pd.prod_qty)
FROM purchasedetailstb as pd
WHERE pd.prodid = pm.prodid
) as Sales_qty
FROM productmaster pm;
This will give you all products, even those missing from one or more of the other tables.
You can add multiple joins.
SELECT t1.id, t4.name, count(t4.name)
FROM Table1 AS t1
INNER JOIN Table2 AS t2 -- the AS statement renames the table within
-- this query to t2. Columns from this table can be used
-- as t2.columnname. This needs to be done when you have
-- columns with the same name in different tables.
ON t1.id = t2.id
INNER JOIN Table3 as t3
ON t1.id = t3.id
INNER JOIN Table4 as t4
ON t3.name = t4.name
GROUP BY t1.id, t4.name

Count records only from left side of a LEFT JOIN

I'm building an Access query with a LEFT JOIN that, among other things, counts the number of unique sampleIDs present in the left table of the JOIN, and counts the aggregate number of specimens (bugs) present in the right table of the JOIN, both for a given group of samples (TripID). Here's the pertinent chunk of SQL code:
SELECT DISTINCT t1.TripID, COUNT(t1.SampleID) AS Samples, SUM(t2.C1 + t2.C2)
AS Bugs FROM tbl_Sample AS t1
LEFT JOIN tbl_Bugs AS t2 ON t1.SampleID = t2.SampleID
GROUP BY t1.TripID
The trouble I'm having is that COUNT(t1.SampleID) is not giving me my desired result. My desired result is the number of unique SampleIDs present in t1 for a given TripID (let's say 7). Instead, what I get seems to be the number of rows in t2 for which the SampleID is contained within the given TripID group (let's say 77). How can I change this SQL query to get the desired number (7, not 77)?
just take the aggregate sum first on t2, then join with t2 like this:
SELECT t1.TripID, COUNT(t1.SampleID) AS Samples, SUM(t3.Bugs) as Bugs
FROM tbl_Sample AS t1
LEFT Join (
SELECT t2.SampleID, SUM(t2.C1 + t2.C2) as Bugs
FROM tbl_Bugs as t2
GROUP BY SampleID) AS t3 ON t1.SampleID = t3.SampleID
GROUP BY t1.TripID
This is a tricky query, because you have different hierarchies. Here is one method:
select s.tripid, count(*) as numsamples,
(select sum(b2.c1 + b2.c2)
from bugs b join
tbl_sample s2
on s2.sampleid = b.sampleid
where s2.tripid = s.tripid
) as numbugs
from tbl_sample s
group by s.tripid
You included a DISTINCT with a Group By. This is removing duplicates twice, which is unnecessarily complex. You can get rid of the DISTINCT.
I would have the count separate from what is going on in the group by.
SELECT dT.TripID
,(SELECT COUNT(DISTINCT(SampleID))
FROM Bugs B
WHERE B.TripID = dT.TripID
) AS [Samples]
,dT.Bugs
FROM (
SELECT t1.TripID
,SUM(t2.C1 + t2.C2) AS Bugs
FROM tbl_Sample AS t1
LEFT JOIN tbl_Bugs AS t2 ON t1.SampleID = t2.SampleID
GROUP BY t1.TripID
) AS dT

Cross join on a group based on the condition in SQL Server

I have Item and Exam tables -
My desire result -
I tried a lot but I am unable to join Exam table to Item table based on Code group.
Is it possible to cross join or any other join for these two tables to get the desire result?
You can try this
SELECT A.Code, i.Item, A.Exam
FROM
(
SELECT Code,e.Exam
FROM Item i
CROSS JOIN Exam e
GROUP BY Code,e.Exam
) A
LEFT JOIN Item i ON i.Code= A.Code AND i.Exam = A.Exam
I don't see a way around generating the missing data. The calendar table approach would be to cross join all codes with all exams. Then, left join this table to Item and order to get the result you want:
WITH cte AS (
SELECT *
FROM (SELECT DISTINCT Code FROM Item) AS C
CROSS JOIN Exam
)
SELECT
t1.Code,
t2.Item,
t1.Exam
FROM cte t1
LEFT JOIN Item t2
ON t1.Code = t2.Code AND
t1.Exam = t2.Exam
ORDER BY
t1.Code,
CASE WHEN t2.Item IS NOT NULL THEN 0 ELSE 1 END,
t1.Exam
Demo here:
Rextester
This should produce what you need. I am using UNION to combine CROSS JOIN and item table and then group by to ensure NULLs are removed.
SELECT code, max(item) as item, exam
FROM
(SELECT distinct i.code, null as item, e.exam FROM exam e cross join item i
union all
SELECT code, item, exam
FROM item) u
group by code, exam
order by code, exam

selecting records from main table and count of each row in another table

I have 2 table in my database that tables are in relationship with foreign key
I want to select all records from main table and then select count of each row in another table than have same ID from main table I tried to create a select query but it is not work correctly
this query return all records from main table + count of all records from next table(not count of each row in relationship)
SELECT tblForumSubGroups_1.id, tblForumSubGroups_1.GroupID,
tblForumSubGroups_1.SubGroupTitle, tblForumSubGroups_1.SubGroupDesc,
(SELECT COUNT(dbo.tblForumPosts.id) AS Expr1
FROM dbo.tblForumSubGroups INNER JOIN dbo.tblForumPosts ON
dbo.tblForumSubGroups.id = dbo.tblForumPosts.SubGroupID) AS Expr1
FROM dbo.tblForumSubGroups AS tblForumSubGroups_1 INNER JOIN
dbo.tblForumPosts AS tblForumPosts_1 ON tblForumSubGroups_1.id
= tblForumPosts_1.SubGroupID
SELECT tblForumSubGroups_1.id, tblForumSubGroups_1.GroupID, tblForumSubGroups_1.SubGroupTitle, tblForumSubGroups_1.SubGroupDesc,
COUNT(tblForumPosts_1.id) AS Expr1
FROM dbo.tblForumSubGroups AS tblForumSubGroups_1
INNER JOIN dbo.tblForumPosts AS tblForumPosts_1 ON tblForumSubGroups_1.id = tblForumPosts_1.SubGroupID
GROUP BY tblForumSubGroups_1.id, tblForumSubGroups_1.GroupID, tblForumSubGroups_1.SubGroupTitle, tblForumSubGroups_1.SubGroupDesc
I would suggest cross apply as you can do a lot more things with it ...
SELECT t1.id,
t1.GroupID,
t1.SubGroupTitle,
t1.SubGroupDesc,
t2.val
FROM dbo.tblForumSubGroups AS t1
cross apply (SELECT COUNT(*)
FROM dbo.tblForumPosts as t2
WHERE t1.id = t2.SubGroupID) x(val)
Do not mix sub-query and join logic. Use only one of them. I prefer sub-select.
SELECT tblForumSubGroups_1.id,
tblForumSubGroups_1.GroupID,
tblForumSubGroups_1.SubGroupTitle,
tblForumSubGroups_1.SubGroupDesc,
(SELECT COUNT(*)
FROM dbo.tblForumPosts
WHERE dbo.tblForumSubGroups.id = dbo.tblForumPosts.SubGroupID) AS Expr1
FROM dbo.tblForumSubGroups AS tblForumSubGroups_1
Just to supply another answer though I believe the cross apply is likely the best option:
SELECT
A.id, A.GroupID, A.SubGroupTitle, A.SubGroupDesc,
B.IDCount AS Expr1
FROM dbo.tblForumSubGroups A
INNER JOIN (
Select SubGroupID, Count(ID) as IDCount
from dbo.tblForumPosts
Group By SubGroupID
) B On A.ID = B.SubGroupID

SQL - remove duplicates from left join

I'm creating a joined view of two tables, but am getting unwanted duplicates from table2.
For example: table1 has 9000 records and I need the resulting view to contain exactly the same; table2 may have multiple records with the same FKID but I only want to return one record (random chosen is ok with my customer). I have the following code that works correctly, but performance is slower than desired (over 14 seconds).
SELECT
OBJECTID
, PKID
,(SELECT TOP (1) SUBDIVISIO
FROM dbo.table2 AS t2
WHERE (t1.PKID = t2.FKID)) AS ProjectName
,(SELECT TOP (1) ASBUILT1
FROM dbo.table2 AS t2
WHERE (t1.PKID = t2.FKID)) AS Asbuilt
FROM dbo.table1 AS t1
Is there a way to do something similar with joins to speed up performance?
I'm using SQL Server 2008 R2.
I got close with the following code (~.5 seconds), but 'Distinct' only filters out records when all columns are duplicate (rather than just the FKID).
SELECT
t1.OBJECTID
,t1.PKID
,t2.ProjectName
,t2.Asbuilt
FROM dbo.table1 AS t1
LEFT JOIN (SELECT
DISTINCT FKID
,ProjectName
,Asbuilt
FROM dbo.table2) t2
ON t1.PKID = t2.FKID
table examples
table1 table2
OID, PKID FKID, ProjectName, Asbuilt
1, id1 id1, P1, AB1
2, id2 id1, P5, AB5
3, id4 id2, P10, AB2
5, id5 id5, P4, AB4
In the above example returned records should be id5/P4/AB4, id2/P10/AB2, and (id1/P1/AB1 OR id1/P5/AB5)
My search came up with similar questions, but none that resolved my problem. link, link
Thanks in advance for your help. This is my first post so let me know if I've broken any rules.
This will give the results you requested and should have the best performance.
SELECT
OBJECTID
, PKID
, t2.SUBDIVISIO,
, t2.ASBUILT1
FROM dbo.table1 AS t1
OUTER APPLY (
SELECT TOP 1 *
FROM dbo.table2 AS t2
WHERE t1.PKID = t2.FKID
) AS t2
Your original query is producing arbitrary values for the two columns (the use of top with no order by). You can get the same effect with this:
SELECT t1.OBJECTID, t1.PKID, t2.ProjectName, t2.Asbuilt
FROM dbo.table1 t1 LEFT JOIN
(SELECT FKID, min(ProjectName) as ProjectName, MIN(asBuilt) as AsBuilt
FROM dbo.table2
group by fkid
) t2
ON t1.PKID = t2.FKID
This version replaces the distinct with a group by.
To get a truly random row in SQL Server (which your syntax suggests you are using), try this:
SELECT t1.OBJECTID, t1.PKID, t2.ProjectName, t2.Asbuilt
FROM dbo.table1 t1 LEFT JOIN
(SELECT FKID, ProjectName, AsBuilt,
ROW_NUMBER() over (PARTITION by fkid order by newid()) as seqnum
FROM dbo.table2
) t2
ON t1.PKID = t2.FKID and t2.seqnum = 1
This assumes version 2005 or greater.
If you want described result, you need to use INNER JOIN and following query will satisfy your need:
SELECT
t1.OID,
t1.PKID,
MAX(t2.ProjectName) AS ProjectName,
MAX(t2.Asbuilt) AS Asbuilt
FROM table1 t1
JOIN table2 t2 ON t1.PKID = t2.FKID
GROUP BY
t1.OID,
t1.PKID
If you want to see all rows from left table (table1) whether it has pair in right table or not, then use LEFT JOIN and same query will gave you desired result.
EDITED
This construction has good performance, and you dont need to use subqueries.