using count on when creating a view - sql

im have a view that need to include the count of members volunteering for an event. I'm getting an error 'not a single-group group functions'. Any idea how to resolve this?
CREATE VIEW atbyrd.events__view AS
SELECT e.name, e."DATE", b."LIMIT",b.allocated_amount, COUNT(em.member_id), e.comments
FROM events e INNER JOIN budgets b ON b.event_id = e.id
INNER JOIN event_members em ON em.event_id = e.id;

SELECT e.name,
e."DATE",
b."LIMIT",
b.allocated_amount,
(select COUNT(member_id) from event_members) as mem_count,
e.comments
FROM events e
INNER JOIN budgets b ON b.event_id = e.id
INNER JOIN event_members em ON em.event_id = e.id;

You could use the analytic function count()
SELECT e.name
, e."DATE"
, b."LIMIT"
, b.allocated_amount
, COUNT(em.member_id) over ( partition by em.event_id )
, e.comments
FROM events e
INNER JOIN budgets b
ON b.event_id = e.id
INNER JOIN event_members em
ON em.event_id = e.id;
Simply put this counts the number of members per event_id but as it's not an aggregate function no GROUP BY is required. You receive the same value per event_id.

Related

SQL Finding Group where attendance less than average

How can i get the number of attendees below average? This is my Oracle query
SELECT e.event_id EventID,c.concert_name ConcertName, c.concert_date,
AVG(e.attendance) Attendance
FROM event e INNER JOIN concert c ON c.concert_id = e.concert_id
WHERE Attendance - AVG(e.Attendance)
GROUP BY c.concert_id ASC;
Using the AVG(..) OVER () analytic function (and without a correlated sub-query):
SELECT eventId,
ConcertName,
Concert_Date
FROM (
SELECT e.event_id EventID,
c.concert_name ConcertName,
c.concert_date,
e.attendance,
AVG(e.attendance) OVER () AS avg_Attendance
FROM event e
INNER JOIN concert c
ON c.concert_id = e.concert_id
)
WHERE attendance < avg_attendance;
You can try with this way:
SELECT e.event_id EventID,c.concert_name ConcertName, c.concert_date,
AVG(e.attendance) Attendance
FROM event e INNER JOIN concert c ON c.concert_id = e.concert_id
WHERE e.attendance < (select AVG(ev.attendance) from event ev)
GROUP BY c.concert_id ASC;

SQL Server Circular Query

I have 4 tables, in that I want to fetch records from all 4 and aggregate the values
I have these tables
I am expecting this output
but getting this output as a Cartesian product
It is multiplying the expenses and allocation
Here is my query
select
a.NAME, b.P_NAME,
sum(a.DURATION) DURATION,
sum(b.[EXP]) EXPEN
from
(select
e.ID, a.P_ID, e.NAME, a.DURATION DURATION
from
EMPLOYEE e
inner join
ALLOCATION a ON e.ID = a.E_ID) a
inner join
(select
p.P_ID, e.E_ID, p.P_NAME, e.amt [EXP]
from
PROJECT p
inner join
EXPENSES e ON p.P_ID = e.P_ID) b ON a.ID = b.E_ID
and a.P_ID = b.P_ID
group by
a.NAME, b.P_NAME
Can anyone suggest something about this.
The following should work:
SELECT e.Name,p.Name,COALESCE(d.Duration,0),COALESCE(exp.Expen,0)
FROM
Employee e
CROSS JOIN
Project p
LEFT JOIN
(SELECT E_ID,P_ID,SUM(Duration) as Duration FROM Allocation
GROUP BY E_ID,P_ID) d
ON
e.E_ID = d.E_ID and
p.P_ID = d.P_ID
LEFT JOIN
(SELECT E_ID,P_ID,SUM(AMT) as Expen FROM Expenses
GROUP BY E_ID,P_ID) exp
ON
e.E_ID = exp.E_ID and
p.P_ID = exp.P_ID
WHERE
d.E_ID is not null or
exp.E_ID is not null
I've tried to write a query that will produce results where e.g. there are rows in Expenses but no rows in Allocations (or vice versa) for some particular E_ID,P_ID combination.
Use left join in select query by passing common id for all table
Hi I got the answer what I want from some modification in the query
The above query is also working like a charm and have done some modification to the original query and got the answer
Just have to group by the inner queries and then join the queries it will then not showing Cartesian product
Here is the updated one
select a.NAME,b.P_NAME,sum(a.DURATION) DURATION,sum(b.[EXP]) EXPEN from
(select e.ID,a.P_ID, e.NAME,sum(a.DURATION) DURATION from EMPLOYEE e inner join ALLOCATION a
ON e.ID=a.E_ID group by e.ID,e.NAME,a.P_ID) a
inner join
(select p.P_ID,e.E_ID, p.P_NAME,sum(e.amt) [EXP] from PROJECT p inner join EXPENSES e
ON p.P_ID=e.P_ID group by p.P_ID,p.P_NAME,e.E_ID) b
ON a.ID=b.e_ID and a.P_ID=b.P_ID group by a.NAME,b.P_NAME
Showing the correct output

SQL JOIN 3 TABLES WITH COUNT AND GROUP BY CLAUSE

I Have 3 tables like that:
EXPEDITION (ID, CreateDate, Status);
PACKAGE (ID, EXPEDITION_ID)
ITEM (ID, EXPEDIITONPACKAGE_ID);
I need to know, for each expedition, the quantity of packages and the quantity of items.
UPDATE
This is the query that seems to have it.
SELECT
E.ID,
P.Packages,
I.Items
FROM EXPEDITION E
LEFT JOIN (
SELECT DISTINCT E.ID, COUNT(P.ID) AS "Packages" FROM EXPEDITION E
LEFT JOIN PACKAGE P
ON E.ID = P.EXPEDITION_ID
GROUP BY E.ID
) P
ON E.ID = P.ID
LEFT JOIN (
SELECT DISTINCT P.ID as "PackageID", COUNT(I.ID) AS "Items" FROM PACKAGE P
JOIN ITEM I
ON P.ID = I.EXPEDIITONPACKAGE_ID
GROUP BY P.ID
) I
ON P.ID = I.PackageId
GROUP BY
E.ID,
P.Packages,
I.Items
ORDER BY
E.ID
It has two inner queries, that count the IDs separately, and they are joined in the main query to show the results.
Try this. Not tested yet...but it should work..
;With c1 as
(
Select e.expid, count(e.expid) as qtyPck
From packages p inner join
Expeditions e on p.expid = e.expid
Group by e.expid
),
C2 as
(
Select i.pakId, count(i.pakId) as qtyItems
From items i inner join packages p
On i.pakId = p.pakId
Group by i.pakid
)
Select e.expId, p.qtyPck, I.qtyItems
From expeditions e
Join packages p on p.expId = e.expId
Join items i on i.pakId = p.pakId;

Why are my SQL statement count different fields from differrent tables in one SQL statement?

I have a SQL query:
SELECT
e.name as estate_name
, g.name as governing_body
, count(s.id) as total_stands
, count(sp.id) as service_providers
FROM estates e
LEFT JOIN governing_bodies
ON e.governing_body_id = g.id
LEFT JOIN stands s
ON s.estate_id = e.id
LEFT JOIN services sp
ON sp.estate_id = e.id
GROUP BY e.id
It seems like my counts multiply each other. If my first count is 3 and second count is 10 the results in service_providers field and total_stands field will be 30.
What am I doing wrong?
What about changing the COUNT(blah) constructs to COUNT(DISTINCT blah) ?
A count() displays the number of rows found for your group. Since you're grouping on estate, it will count the number of rows you join to estate. Joins will multiply the number of rows, so 3 x 10 = 30 sounds like the correct count. Run the query without GROUP BY to see what's happening.
One way to fix it would look like this:
SELECT
e.name as estate_name,
g.name as governing_body,
(select count(*) from stands s where s.estate_id = e.id) as stands,
(select count(*) from services sp where sp.estate_id = e.id) as services
FROM estates e
LEFT JOIN governing_bodies g on e.governing_body_id = g.id
Writing out Alex Martelli's informative answer:
SELECT
e.name as estate_name
, g.name as governing_body
, count(distinct s.id) as total_stands
, count(distinct sp.id) as service_providers
FROM estates e
LEFT JOIN governing_bodies
ON e.governing_body_id = g.id
LEFT JOIN stands s
ON s.estate_id = e.id
LEFT JOIN services sp
ON sp.estate_id = e.id
GROUP BY e.id, g.name
Or, as a more complex alternative with JOIN syntax:
SELECT
e.name as estate_name,
g.name as governing_body,
IsNull(stand_count.total,0) as stand_count,
IsNull(service_count.total,0) as service_count
FROM estates e
LEFT JOIN governing_bodies g on e.governing_body_id = g.id
LEFT JOIN (
select estate_id, total = count(*) from stands group by estate_id
) stand_count on stand_count.estate_id = e.id
LEFT JOIN (
select estate_id, total = count(*) from services group by estate_id
) service_count on service_count.estate_id = e.id
GROUP BY
e.name,
g.name,
IsNull(stand_count.total,0),
IsNull(service_count.total,0)

Sql query with joins between four tables with millions of rows

We have a transact sql statement that queries 4 tables with millions of rows in each.
It takes several minutes, even though it has been optimized with indexes and statistics according to TuningAdvisor.
The structure of the query is like:
SELECT E.EmployeeName
, SUM(M.Amount) AS TotalAmount
, SUM(B.Amount) AS BudgetAmount
, SUM(T.Hours) AS TotalHours
, SUM(TB.Hours) AS BudgetHours
, SUM(CASE WHEN T.Type = 'Waste' THEN T.Hours ELSE 0 END) AS WastedHours
FROM Employees E
LEFT JOIN MoneyTransactions M
ON E.EmployeeID = M.EmployeeID
LEFT JOIN BudgetTransactions B
ON E.EmployeeID = B.EmployeeID
LEFT JOIN TimeTransactions T
ON E.EmployeeID = T.EmployeeID
LEFT JOIN TimeBudgetTransactions TB
ON E.EmployeeID = TB.EmployeeID
GROUP BY E.EmployeeName
Since each transaction table contains millions of rows, I consider splitting it up into one query per transaction table, using table variables like #real, #budget, and #hours, and then joining these in a final SELECT. But in tests it seems to not speed up.
How would you deal with that in order to speed it up?
I'm not sure the query you posted will yield the results you're expecting.
It will cross join all the dimension tables (MoneyTransactions etc.) and multiply all the results.
Try this:
SELECT E.EmployeeName,
(
SELECT SUM(amount)
FROM MoneyTransactions m
WHERE M.EmployeeID = E.EmployeeID
) AS TotalAmount,
(
SELECT SUM(amount)
FROM BudgetTransactions m
WHERE M.EmployeeID = E.EmployeeID
) AS BudgetAmount,
(
SELECT SUM(hours)
FROM TimeTransactions m
WHERE M.EmployeeID = E.EmployeeID
) AS TotalHours,
(
SELECT SUM(hours)
FROM TimeBudgetTransactions m
WHERE M.EmployeeID = E.EmployeeID
) AS BudgetHours
FROM Employees E
I don't know if you have all the indexes on your tables that will speed up things, but having big tables could have this impact on a query time.
I would recommend partitioning the tables if possible. It is more work, but everything you do to speed up the query now it won't be enough after few millions new records.
Try this one:
SELECT E.EmployeeName, TA.TotalAmount, BA.BudgetAmount, TWH.TotalHours, BH.BudgetHours, TWH.WastedHours
FROM Employees E
LEFT JOIN
(SELECT E.EmployeeID, SUM(M.Amount) AS TotalAmount
FROM Employees E INNER JOIN MoneyTransactions M ON E.EmployeeID = M.EmployeeID GROUP BY E.EmployeeID)TA
ON E.EmployeeID = TA.EmployeeID
LEFT JOIN
(SELECT E.EmployeeID , SUM(B.Amount) AS BudgetAmount
FROM Employees E INNER JOIN BudgetTransactions B ON E.EmployeeID = B.EmployeeID GROUP BY E.EmployeeID)BA
ON E.EmployeeID = BA.EmployeeID
LEFT JOIN
(SELECT E.EmployeeID , SUM(T.Hours) AS TotalHours , SUM(CASE WHEN T.Type = 'Waste' THEN T.Hours ELSE 0 END) AS WastedHours
FROM Employees E INNER JOIN TimeTransactions T ON E.EmployeeID = T.EmployeeID GROUP BY E.EmployeeID)TWH
ON E.EmployeeID = TWH.EmployeeID
LEFT JOIN
(SELECT E.EmployeeID , SUM(TB.Hours) AS BudgetHours
FROM Employees E INNER JOIN TimeBudgetTransactions TB ON E.EmployeeID = TB.EmployeeID GROUP BY E.EmployeeID)BH
ON E.EmployeeID = BH.EmployeeID