SQL Count from 2 tables - sql

Background: There are multiple DBPArentProductKEys associated with a POG.ID.
I need to count the number of Pog.DBKEYs that occurs. Right now the results count total POG.IDs in the total database for value4, but I want the count associated with the DBparentproductkey.
select distinct
Count(pog.DBKey) as Total,
pos.DBParentProductKey
from
ix_spc_planogram as pog with (nolock), ix_spc_position as pos with (nolock),
ix_spc_product as pro with (nolock)
where
pog.dbkey = pos.dbparentplanogramkey
and pog.Value4 = 358
group by
pog.DBKey, pos.DBParentProductKey

Take pog.DBKey out of the GROUP BY.
Also, I think you are missing a join condition. You have no join condition against table pro.
Finally, DISTINCT shouldn't be needed.

Related

Not getting 0 value in SQL count aggregate by inner join

I am using the basic chinook database and I am trying to get a query that will display the worst selling genres. I am mostly getting the answer, however there is one genre 'Opera' that has 0 sales, but the query result is ignoring that and moving on to the next lowest non-zero value.
I tried using left join instead of inner join but that returns different values.
This is my query currently:
create view max
as
select distinct
t1.name as genre,
count(*) as Sales
from
tracks t2
inner join
invoice_items t3 on t2.trackid == t3.trackid
left join
genres as t1 on t1.genreid == t2.genreid
group by
t1.genreid
order by
2
limit 10;
The result however skips past the opera value which is 0 sales. How can I include that? I tried using left join but it yields different results.
Any help is appreciated.
If you want to include genres with no sales then you should start the joins from genres and then do LEFT joins to the other tables.
Also, you should not use count(*) which counts any row in the resultset.
SELECT g.name Genre,
COUNT(i.trackid) Sales
FROM genres g
LEFT JOIN tracks t ON t.genreid = g.genreid
LEFT JOIN invoice_items i ON i.trackid = t.trackid
GROUP BY g.genreid
ORDER BY Sales LIMIT 10;
There is no need for the keyword DISTINCT, since the query returns 1 row for each genre.
When asking for the top n one must always state how to deal with ties. If I am looking for the top 1, but there are three rows in the table, all with the same value, shall I select 3 rows? Zero rows? One row arbitrarily chosen? Most often we don't want arbitrary results, which excludes the last option. This excludes LIMIT, too, because LIMIT has no clause for ties in SQLite.
Here is an example with DENSE_RANK instead. You are looking for the worst selling genres, so we must probably look at the revenue per genre, which is the sum of price x quantity sold. In order to include genres without invoices (and maybe even without tracks?) we outer join this data to the genre table.
select total, genre_name
from
(
select
g.name as genre_name,
coalesce(sum(ii.unit_price * ii.quantity), 0) as total
dense_rank() over (order by coalesce(sum(ii.unit_price * ii.quantity), 0)) as rnk
from genres g
left join tracks t on t.genreid = g.genreid
left join invoice_items ii on ii.trackid = t.trackid
group by g.name
) aggregated
where rnk <= 10
order by total, genre_name;

SQL dividing a count from one table by a number from a different table

I am struggling with taking a Count() from one table and dividing it by a correlating number from a different table in Microsoft SQL Server.
Here is a fictional example of what I'm trying to do
Lets say I have a table of orders. One column in there is states.
I have a second table that has a column for states, and second column for each states population.
I'd like to find the order per population for each sate, but I have struggled to get my query right.
Here is what I have so far:
SELECT Orders.State, Count(*)/
(SELECT StatePopulations.Population FROM Orders INNER JOIN StatePopulations
on Orders.State = StatePopulations.State
WHERE Orders.state = StatePopulations.State )
FROM Orders INNER JOIN StatePopulations
ON Orders.state = StatePopulations.State
GROUP BY Orders.state
So far I'm contending with an error that says my sub query is returning multiple results for each state, but I'm newer to SQL and don't know how to overcome it.
If you really want a correlated sub-query, then this should do it...
(You don't need to join both table in either the inner or outer query, the correlation in the inner query's where clause does the 'join'.)
SELECT
Orders.state,
COUNT(*) / (SELECT population FROM StatePopulation WHERE state = Orders.state)
FROM
Orders
GROUP BY
Orders.state
Personally, I'd just join them and use MAX()...
SELECT
Orders.state,
COUNT(*) / MAX(StatePopulation.population)
FROM
Orders
INNER JOIN
StatePopulation
StatePopulation.state = Orders.state
GROUP BY
Orders.state
Or aggregate your orders before you join...
SELECT
Orders.state,
Orders.order_count / StatePopulation.population
FROM
(
SELECT
Orders.state,
COUNT(*) AS order_count
FROM
Orders
GROUP BY
Orders.state
)
Orders
INNER JOIN
StatePopulation
StatePopulation.state = Orders.state
(Please forgive typos and smelling pistakes, I'm doing this on a phone.)

Sum By Group in Access 2016 Query

I have a query that returns the following data:
I am trying to adapt it to sum the total number of runs at each venue. I have come up with the query below but there are two issues:
it is not summing by venue it is summing all runs;
it takes a very long time to run.
Can anyone see what I'm doing wrong?
Thanks
SELECT ScorecardBatting.matchId, ScorecardBatting.battingTeam, ScorecardBatting.inningsNo, ScorecardBatting.batsmanId, ScorecardBatting.howDismissed, ScorecardBatting.runs, ScorecardBatting.ballsFaced, Matches.venue, (SELECT SUM(runs) FROM ScorecardBatting WHERE Matches.venue=Matches.venue) AS TOTAL
FROM Matches INNER JOIN ScorecardBatting ON Matches.matchId = ScorecardBatting.matchId
GROUP BY ScorecardBatting.matchId, ScorecardBatting.battingTeam, ScorecardBatting.inningsNo, ScorecardBatting.batsmanId, ScorecardBatting.howDismissed, ScorecardBatting.runs, ScorecardBatting.ballsFaced, Matches.venue;
If you want the total number of runs for each venue, then a simple aggregation query does what you want:
SELECT Matches.venue, SUM(runs) AS TOTAL
FROM Matches INNER JOIN
ScorecardBatting
ON Matches.matchId = ScorecardBatting.matchId
GROUP BY Matches.venue;
If you want this in your original query, you could join it in:
select . . ., t.total
from Matches inner join
ScorecardBatting
on Matches.matchId = ScorecardBatting.matchId join
(select Matches.venue, sum(runs) AS TOTAL
from Matches INNER JOIN
ScorecardBatting
on Matches.matchId = ScorecardBatting.matchId
group by Matches.venue
) t
on t.venue = matches.venue;
I don't think you need a group by fro your query.

Subquery performing a COUNT DISTINCT on the wrong grouping

I'm fairly new to SQL and have a problem with a subquery that is performing a count distinct on the wrong grouping. I'd appreciate any help at all with this.
I have attendees at sessions for a particular group that I am querying for a MS SQL Server (SSRS 2008) Report.
I am trying to join TblGroup, TblGroupSession and TblGroupSUAttendee and count the DISTINCT number of GroupSUAttendee at any GROUP. The query below is counting the distinct number of GroupSUAttendee at any SESSION, so when I add the counts together for a group I am getting duplicates if a TblGroupSUAttendee has attended more than one session.
I need to keep one row per session in the query as I need that for other purposes, but it is fine for each session row to show the complete total of TblGroupSUAttendees for that group as I can reference that value once per group in my SSRS report.
Thoughts/advice/pointers much appreciated.
Thanks
Eils
SELECT
TblGroup.GroupId
,TblGroupSession.GroupSessionId
,TblGroupSession.GroupSessionDate
,TblGroupSUAttendee.GroupSUAttendeeCount
FROM
TblGroup
LEFT OUTER JOIN TblGroupSession
ON TblGroup.GroupId = TblGroupSession.GroupSessionGroupId
LEFT OUTER JOIN (select COUNT(DISTINCT GroupSUAttendeeId) AS GroupSUAttendeeCount,
GroupSUAttendeeGroupSessionId
FROM TblGroupSUAttendee
GROUP BY GroupSUAttendeeGroupSessionId) as TblGroupSUAttendee ON GroupSUAttendeeGroupSessionId = TblGroupSession.GroupSessionId
WHERE
GroupSessionDate >= #StartDate AND GroupSessionDate <= #EndDate
If you want to count attendees within groups, then use group by, but don't include per-session information. In other words, just combine the groups with the sessions, and the sessions with the attendees in one query. Then aggregate by GroupId and count the attendees:
SELECT g.GroupId,
COUNT(DISTINCT GroupSUAttendeeId) AS GroupSUAttendeeCount
FROM TblGroup g LEFT OUTER JOIN
tblGroupSession gs
ON g.GroupId = gs.GroupSessionGroupId LEFT OUTER JOIN
TblGroupSUAttendee ga
ON ga.GroupSUAttendeeGroupSessionId = gs.GroupSessionId
GROUP BY g.GroupId;

Sum Distinct Rows Only In Sql Server

I have four tables,in which First has one to many relation with rest of three tables named as (Second,Third,Fourth) respectively.I want to sum only Distinct Rows returned by select query.Here is my query, which i try so far.
select count(distinct First.Order_id) as [No.Of Orders],sum( First.Amount) as [Amount] from First
inner join Second on First.Order_id=Second.Order_id
inner join Third on Third.Order_id=Second.Order_id
inner join Fourth on Fourth.Order_id=Third.Order_id
The outcome of this query is :
No.Of Orders Amount
7 69
But this Amount should be 49,because the sum of First column Amount is 49,but due to inner join and one to many relationship,it calculate sum of also duplicate rows.How to avoid this.Kindly guide me
I think the problem is cartesian products in the joins (for a given id). You can solve this using row_number():
select count(t1234.Order_id) as [No.Of Orders], sum(t1234.Amount) as [Amount]
from (select First.*,
row_number() over (partition by First.Order_id order by First.Order_id) as seqnum
from First inner join
Second
on First.Order_id=Second.Order_id inner join
Third
on Third.Order_id=Second.Order_id inner join
Fourth
on Fourth.Order_id=Third.Order_id
) t1234
where seqnum = 1;
By the way, you could also express this using conditions in the where clause, because you appear to be using the joins only for filtering:
select count(First.Order_id) as [No.Of Orders], sum(First.Amount) as [Amount]
from First
where exists (select 1 from second where First.Order_id=Second.Order_id) and
exists (select 1 from third where First.Order_id=third.Order_id) and
exists (select 1 from fourth where First.Order_id=fourth.Order_id);