I have three tables TeamTerritoryMapping, UpdQuotaTbl and tblInvoiceFile
When I join the first two tables I am getting the correct result
select
TTM.Team, Sum(Upd.Quota) as Quota
from
TeamTerritoryMapping TTM
inner join
UpdQuotaTbl upd on upd.ITM = TTm.Territory
where
upd.Month = 'july'
group by
TTM.Team
but when I join the third table for another column revenue from tblinvoicefile, some of the rows are getting duplicated and the end result is becoming higher. Below is the query which I am using to join 3 tables
select
TTM.Team,
Sum(upd.Quota) as quota,
sum(inv.[End MS Sales Revenue]) as Revenue
from
UpdQuotaTbl Upd
inner join
TeamTerritoryMapping TTM on TTM.Territory = upd.ITM
inner join
tblInvoiceFile inv on inv.[Inv Territory] = TTM.Territory
where
upd.Month = 'july'
and inv.[End Fiscal Month] = 'July, 2013'
So how can I eradicate the duplicate values in third table, I am getting the correct value when I join two tables ie TeamTerritoryMapping,UpdQuotaTbl and also tables TeamTerritoryMapping.
It looks like tblInvoiceFile has multiple entires for [Invenio Territory] which is causing this issue. If your intention is to bring in and sum all the [End MS Sales Revenue] for that table you can try something like this
SELECT TTM.Team,Sum(upd.Quota) as quota,sum(inv.[End MS Sales Revenue]) as Revenue
FROM UpdQuotaTbl Upd
INNER JOIN TeamTerritoryMapping TTM ON TTM.Territory = upd.ITM
INNER JOIN
(SELECT [Invenio Territory], SUM([End MS Sales Revenue]) AS [End MS Sales Revenue]
FROM tblInvoiceFile
WHERE [End Fiscal Month] = 'July, 2013'
GROUP BY [Invenio Territory]) AS inv
ON inv.[Invenio Territory] = TTM.Territory
WHERE upd.Month = 'july'
My initial response would be : The reason you're getting some results multiple times is because the ON used to join tblInvoiceFile is not 'unique' enough. If you look at the primary key (or a unique?) of said table you'll probably notice that it involves more than just the Inv Territory field.
To solve it you can do two different things.
Expand the ON clause to include more fields that make the connection unique
Keep the query as it is now but aggregate the results so the invoice information gets SUMmed
The problem is, it seems like you're already SUM()-ing the information (although as noted by Win, you're missing the GROUP BY), so I'm not quite sure why this would not work.
UPDATE: Only now realise that your problem is not doubled records, but doubled values in the first SUM(). Best way to solve this is by PRE-aggregating the values as shown by Abhi.
Related
UPDATE: After spending some time on this, I have realised that the best way to describe this problem concisely is to say that I am looking for the equivalent of a VLOOKUP in SQL (albeit using grouped values).
I have a query which joins two tables on surrogate key fields (specialty and specialty_sk).
I want to count the total number of unique values under specialty which I do like so:
SELECT specialty_sk, COUNT(*)
FROM [Appointment_vw]
WHERE [appointment date] BETWEEN '2021-02-01' AND '2021-02-07'
GROUP BY specialty_sk
This works as expected:
However, when I join to the surrogate key field in another table in order to pull the name for each specialty in, I receive this:
Column 'Specialty_vw.specialty' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Query:
SELECT A.specialty_sk, S.specialty
FROM [Appointment_vw] A INNER JOIN [Specialty_vw] S
ON A.specialty_sk = S.specialty
WHERE [appointment date] BETWEEN '2021-02-01' AND '2021-02-07'
GROUP BY A.specialty_sk
Or
SELECT A.specialty_sk, COUNT(*), S.specialty
FROM [Appointment_vw] A INNER JOIN [Specialty_vw] S
ON A.specialty_sk = S.specialty
WHERE [appointment date] BETWEEN '2021-02-01' AND '2021-02-07'
GROUP BY A.specialty_sk
Or
SELECT A.specialty_sk, COUNT(specialty_sk), S.specialty
FROM [Appointment_vw] A INNER JOIN [Specialty_vw] S
ON A.specialty_sk = S.specialty
WHERE [appointment date] BETWEEN '2021-02-01' AND '2021-02-07'
GROUP BY A.specialty_sk
In other versions of the above queries, I have received messages regarding some variables not being able to be cast from varchar to int.
Where am I going wrong here? I assume that it has something to do with COUNT(*).
If so, then how can I find out what each specialty code is without pulling in the specialty_sk field from the other table? (The [Appointment_vw] table is almost 32,000,000 rows deep so this wouldn't be ideal.)
What I want to achieve is a count of all of the unique specialty values from A and then to pull in the names of those specialties from S and display them alongside the results shown above in a new column.
I can only assume it's to do with the fact that I am grouping my results, whereas on the JOIN I am looking to pull in a single value that identifies the specialty code.
When you are using a GROUP BY, any column that you have in the SELECT which is not being aggregated/counted etc needs to also be in the GROUP BY. So the following should produce the results you are expecting if there is a 1-1 mapping between on A.specialty_sk = S.specialty
SELECT
A.specialty_sk,
COUNT(*),
S.specialty
FROM [Appointment_vw] A INNER JOIN [Specialty_vw] S
ON A.specialty_sk = S.specialty
WHERE [appointment date] BETWEEN '2021-02-01' AND '2021-02-07'
GROUP BY A.specialty_sk, S.specialty
After some time spent trying to work this out, I discovered where I had gone wrong - I had overlooked selecting the field that I was trying to pull in (S.specialty).
The correct query is:
SELECT A.specialty_sk, S.specialty, COUNT(A.specialty_sk)
FROM Appointment_vw A INNER JOIN Specialty_vw S
ON A.specialty_sk = S.Specialty_sk
WHERE CAST([appointment date] AS DATE) BETWEEN '2021-02-01' AND '2021-02-07'
GROUP BY A.specialty_sk, S.Specialty
As such, instead of getting this:
specialty_sk n
spec1 34
spec2 3
spec3 87
I now get this:
specialty_sk specialty n
spec1 specialty number one 34
spec2 specialty number two 3
spec3 specialty number three 87
Thank you everyone for your assistance.
I have a code that pulls all of a Reps new customers and their year to date sales. The only problem is it only pulls customers that have sales in the invdate range, but I need it to show all of the accounts with a 0 if they do not have any sales. Is there any way to achieve this? I tried using COALESCE and it didn't seem to work. I also tried using left, right, full outer joins. Any help would be appreciated!
select
a.Acctnum,
sum(a.invtotal) as total
from invoices a right join accounts b on a.acctnum = b.acctnum where
a.invdate between '1/1/2017' and '12/31/2017'
and a.sls = '78'
and b.sls = '78'
and b.activetype = 'y' and b.startdate > (getdate()-365)
group by a.acctnum
order by total desc
You are restricting your results in your WHERE clause AFTER you join your table causing records to drop. Instead, switch to a LEFT OUTER JOIN with your accounts table driving the query. Then restrict your invoices table in your ON clause so that invoices are dropped BEFORE you join.
SELECT a.Acctnum,
sum(a.invtotal) AS total
FROM accounts b
LEFT OUTER JOIN invoices a ON
a.accntnum = b.acctnum AND
--Put the restrictions on your left most table here
--so they are removed BEFORE joining.
a.invdate BETWEEN '1/1/2017' AND '12/31/2017'
AND a.sls = '78'
WHERE
b.sls = '78'
AND b.activetype = 'y'
AND b.startdate > (getdate() - 365)
GROUP BY a.acctnum
ORDER BY total DESC
It's a bit like doing a subquery in invoices before joining in as the left table. It's just easier to drop the conditions into the ON clause.
Your problem is you where clauses are changing the right join to an inner join. Put all the ones that are aliased by a. into the ON clause.
I'm trying to join 2 tables to get an output report. The tables involved are the stock and dailysales table.
Stock and Dailysales tables:
Desired output format:
I am trying to join 2 tables by using the below query
Select item,article,sold,stockonhand
from stock S
left join dailysales as D on S.item=D.item
group by item
I want the output to include all rows from the stock table. Like there is stock, but not sold, also to be included in the report. Currently my report is does not show, (stocked but not sold).
Hope you can understand my context or point me to a tutorial which I could read up. I tried to search for few days and couldn't find an exact question to mine.
Not tested -
select item,article,sum(sold),sum(stockonhand)-sum(sold) from (
select a.item,a.article,a.stockonhand,case when b.sold is null then 0 else b.sold end as sold
from stock a left join dailysales b on (a.item = b.item))
group by item,article;
It's basically does the left join and put 0 on the null column(for sum after)
and then summing up the results grouping by all the columns in the select(that what was wrong with your query)
Simply LEFT JOIN the two tables (to get the flute too), do a GROUP BY, and SUM the sold:
select s.item, s.article, coalesce(SUM(d.sold),0) as "qty sold", s.stockonhand
from stock S
left join dailysales as D on S.item=D.item
group by s.item, s.article, s.stockonhand
The coalesce is there to replace NULL with 0, for items not sold. (Thanks sagi!)
General GROUP BY tip: If a GROUP BY clause is specified, each column reference in the SELECT list must either identify a grouping column or be the argument of a set function.
Also, you can remove the article column from the dailysales table. That data is already stored in the stock table. Never store same data twice! (Normalization!) Risk for data inconsistency if you keep that column.
You can sum the item in a separated table, it would be clearer than GROUP BY 2 tables
SELECT
s.item,
s.article,
ISNULL(ds.sold, 0) AS qtysold,
s.stockonhand
FROM
stock s OUTER APPLY
(SELECT SUM(sold) AS sold FROM dailysales WHERE item = s.item GROUP BY item) ds
This small example is based on a question that I have run into countless times, however I failed finding the best answer.
I would like to create a report on Incidents logged per type, per month. Written the following query.
SELECT
d.MonthPeriod
,i.[Type]
,COUNT(*) AS [Count of Calls]
FROM
[dbo].[FactIncident] as i
LEFT JOIN
[dbo].[DimDate] as d on i.DateLoggedKey = d.DateKey
GROUP BY
d.[MonthPeriod],
i.[Type]
This results in the following:
Although correct, I would like to visualize earlier months with 0 logged calls. DimDate contains the following.
What is the best and/or most efficient way of showing the count of calls per month, per type, for all months. Even if the count is 0?
Thought of using Cross Apply, however the resultant query gets huge quickly. Only think of a dataset requiring the count of calls per customer, per category, per month over the last 3 years..
Any ideas?
Do the left join starting with the calendar table, so you keep all the months:
SELECT d.MonthPeriod, i.[Type], COUNT(i.type) AS [Count of Calls]
FROM [dbo].[DimDate] d LEFT JOIN
[dbo].[FactIncident] i
ON i.DateLoggedKey = d.DateKey
GROUP BY d.[MonthPeriod], i.[Type];
This will, of course, return the type as NULL for the months with no data.
If you want all types present, then use CROSS JOIN on the types. This example gets the data from the fact table, but you might have another reference table containing each type:
SELECT d.MonthPeriod, t.[Type], COUNT(i.type) AS [Count of Calls]
FROM [dbo].[DimDate] d CROSS JOIN
(select distinct type from factincident) t LEFT JOIN
[dbo].[FactIncident] i
ON i.DateLoggedKey = d.DateKey and i.type = t.type
GROUP BY d.[MonthPeriod], t.[Type];
So I want to create a variance report. Simply sales - planned sales = variance etc.
I have two table, one called Actual one called Plan. Both have the same fields,
-account code
-month
-year
-sales
The idea being I populate the Plan table with the years plan data then update Actuals with actuals as they come in.
The problem I have, is how do I build a query that shows both (1) unplanned sales and (2) planned sales without an actual? I can't find a join type that does it.
Or am I completely missing the point and a more obvious way of doing this?!
I am not sure if I understand the problem. If sometimes records are missing in Actual and sometimes in Plan then combine a LEFT JOIN query with a RIGHT JOIN query in a UNION query.
SELECT
P.*,
A.sales - P.sales AS variance
FROM
Plan P
LEFT JOIN Actual A
ON P.[account code] = A.[account code] AND
P.month = A.month AND
P.year = A.year
UNION ALL
SELECT
A.*,
NULL AS variance
FROM
Plan P
RIGHT JOIN Actual A
ON P.[account code] = A.[account code] AND
P.month = A.month AND
P.year = A.year
WHERE
P.[account code] IS NULL
The WHERE clause avoids duplicates and selects only records that were missing in the first SELECT query.