Aggregate on joined tables - sql

I m using the following query, to get the result as shown below. Actually the query is just joining 2 tables.
SELECT MT.mkt_Area_ID,MA.mkt_Reg_ID,MT.mktcate_id,MT.target_Amt,MT.year
FROM [CRM].[tblMktArea_Target] MT JOIN CRM.tblMarketingArea MA
ON MA.mkt_Area_ID= MT.mkt_Area_ID WHERE month IN (05,04) AND year=2013 AND MA.mkt_Area_ID=1
AND MA.mkt_Reg_ID =1
How can I group the results by mktcate_id to get the sum of target_amt for each category?
I tried:
SELECT MT.mkt_Area_ID,MA.mkt_Reg_ID,MT.mktcate_id,Sum(MT.target_Amt),MT.year
FROM [CRM].[tblMktArea_Target] MT JOIN CRM.tblMarketingArea MA
ON MA.mkt_Area_ID= MT.mkt_Area_ID WHERE month IN (05,04) AND year=2013 AND MA.mkt_Area_ID=1
AND MA.mkt_Reg_ID =1 group by MT.mktcate_id
and getting errror

You are getting an exception because it is necessary to add non-aggregated columns in the GROUP BY clause. Example,
SELECT MT.mkt_area_id,
MA.mkt_reg_id,
MT.mktcate_id,
SUM(MT.target_amt),
MT.year
FROM [CRM].[TBLMKTAREA_TARGET] MT
JOIN CRM.TBLMARKETINGAREA MA
ON MA.mkt_area_id = MT.mkt_area_id
WHERE month IN ( 05, 04 )
AND year = 2013
AND MA.mkt_area_id = 1
AND MA.mkt_reg_id = 1
GROUP BY MT.mktcate_id,
MT.mkt_area_id,
MA.mkt_reg_id,
MT.year

You should always GROUP BY on all the columns that are not within aggregate functions (such as SUM, MAX, AVG).
Put MT.mkt_Area_ID, MA.mkt_Reg_ID, MT.year fields into the GROUP BY clause:
SELECT MT.mkt_Area_ID,
MA.mkt_Reg_ID,
MT.mktcate_id,
Sum(MT.target_Amt),
MT.year
FROM [CRM].[tblMktArea_Target] MT JOIN CRM.tblMarketingArea MA ON
MA.mkt_Area_ID = MT.mkt_Area_ID
WHERE month IN (05,04) AND
year = 2013 AND
MA.mkt_Area_ID = 1 AND
MA.mkt_Reg_ID = 1
GROUP BY MT.mktcate_id,
MT.mkt_Area_ID,
MA.mkt_Reg_ID,
MT.year
Or remove MT.mkt_Area_ID, MA.mkt_Reg_ID, MT.year fields from the SELECT clause:
SELECT MT.mktcate_id,
Sum(MT.target_Amt)
FROM [CRM].[tblMktArea_Target] MT JOIN CRM.tblMarketingArea MA ON
MA.mkt_Area_ID = MT.mkt_Area_ID
WHERE month IN (05,04) AND
year = 2013 AND
MA.mkt_Area_ID = 1 AND
MA.mkt_Reg_ID = 1
GROUP BY MT.mktcate_id

Related

Ms SQL date range query: month to month OK but whole year incorrect results

I have a query below that returns the correct results when executed month by month. i.e. 1jan -31st jan, 2nd feb - 28th feb, 1st march -31st march.. etc etc.
but when i set historydate>= '2017-01-01' to capture the whole year, it returns completely wrong results. Any ideas? I'm on mssql
SELECT DISTINCT
cl.id AS id, cl.[KEY] AS issuekey,
MAX(historyDate) AS releaseDate,
m.issueType,
m.priority
FROM d_jira_changelog cl
JOIN d_jira_changelog_items ci ON ci.historyId = cl.historyId
JOIN d_jira_main m ON m.id = cl.id
WHERE(ci.changeitemfrom = 'Phase1'
AND ci.changeItemTo = 'Phase2')
AND changeItemField = 'status'
AND m.projectkey IN('ABC', 'CBA', 'XYZ', 'YOYO')
AND historydate >= '2017-01-01'
GROUP BY cl."id", cl."key", m.issueType, m.priority;
Issue Seem to Be IN WHERE Clause If column historydate Is Datetime Then Surely you will not get any record based on this WHERE Clause historydate >= '2017-01-01'
SELECT DISTINCT
cl.id AS id, cl.[KEY] AS issuekey,
MAX(historyDate) AS releaseDate,
m.issueType,
m.priority
FROM d_jira_changelog cl
JOIN d_jira_changelog_items ci ON ci.historyId = cl.historyId
JOIN d_jira_main m ON m.id = cl.id
WHERE(ci.changeitemfrom = 'Phase1'
AND ci.changeItemTo = 'Phase2')
AND changeItemField = 'status'
AND m.projectkey IN('ABC', 'CBA', 'XYZ', 'YOYO')
CONVERT(NVARCHAR,historydate,111) >= CONVERT(NVARCHAR,'2017-01-01',111)
GROUP BY cl."id", cl."key", m.issueType, m.priority;

Filter between dates grouping 3 tables in SQL Server

I have this SQL in SQL Server:
SELECT
Itens.Mercadoria, Mercadoria.Nome, Cabecalho.Data,
SUM(ValorUnitario) AS Total,
SUM(Quantidade) AS Quantidade
FROM
Itens
INNER JOIN
Mercadoria ON Itens.Mercadoria = Mercadoria.Codigo
INNER JOIN
Cabecalho ON Cabecalho.Codigo = Itens.Cabecalho
WHERE
Cabecalho.Data >= '2016-01-01'
AND Cabecalho.Data <= '2018-12-31'
GROUP BY
Itens.Mercadoria, Mercadoria.Nome, Cabecalho.Data
ORDER BY
4 DESC
It is returning the following result.
The highlighted values are repeating, I do not want to be repeated, I want to show only once each item and that the Quantidade and Total fields are SUM.
For example:
`Camisa Polo` -> **Quantidade = 23**
`Calça Jeans` -> **Quantidade = 15**
`Camiseta Estampada` -> **Quantidade = 21**
Assuming thate the relation between Sales and SaleItems is based on SalesId
you can use between assign to your_start_date and your_end_date a proper value
select Products.ProductName
, sum(SaleItems.Price)
, sum(SaleItems.Quantity)
from Products
inner join SaleItems on SaleItems.IdProduct = Products.IdProduct
inner join Sales on Sales.IdSale = SaleItems.IdSale
where SaleDate between your_start_date and your_end_date
group by Products.ProductName
In you case remove or aggregated the Cabecalho.Data column eg:
SELECT Itens.Mercadoria
, Mercadoria.Nome
, SUM(ValorUnitario) AS Total
, SUM(Quantidade) AS Quantidade
FROM Itens INNER JOIN Mercadoria ON Itens.Mercadoria = Mercadoria.Codigo
INNER JOIN Cabecalho ON Cabecalho.Codigo = Itens.Cabecalho
WHERE Cabecalho.Data between '2016-01-01' AND '2018-12-31'
GROUP BY Itens.Mercadoria, Mercadoria.Nome
ORDER BY 4 DESC
or
SELECT Itens.Mercadoria
, Mercadoria.Nome
, max(Cabecalho.Data)
, SUM(ValorUnitario) AS Total
, SUM(Quantidade) AS Quantidade
FROM Itens INNER JOIN Mercadoria ON Itens.Mercadoria = Mercadoria.Codigo
INNER JOIN Cabecalho ON Cabecalho.Codigo = Itens.Cabecalho
WHERE Cabecalho.Data between '2016-01-01' AND '2018-12-31'
GROUP BY Itens.Mercadoria, Mercadoria.Nome
ORDER BY 4 DESC

Show row in a series even if the data is missing from the table

I need a SQL query to return a row for every month in years 2015 and 2016 for every company that pays dues. The resulting dataset will show which months the company didn't pay dues by a null value. The problem is that if they didn't pay dues they won't have an entry in the database so no row will appear for than month. Here is the query:
SELECT
case when n.co_id <>'' then n.co_id else n.ID end ID
,su.CONTINUOUS_SINCE
,n.COMPANY
,a.EFFECTIVE_DATE
, a.AMOUNT
FROM dbo.Name n
LEFT OUTER JOIN dbo.Activity a ON n.ID = a.ID
inner JOIN dbo.Loc_Info l ON n.ID = l.ID
inner JOIN dbo.Segment_Categories s ON l.CURRENT_SEGMENT = s.CODE
inner JOIN dbo.Subscriptions su on su.id=n.id
WHERE   a.PRODUCT_CODE='rental' and n.MEMBER_TYPE in ('rb','rl') and a.EFFECTIVE_DATE Between '2015-07-01' And GetDate() AND a.ACTIVITY_TYPE='dues'
order by case when n.co_id <>'' then n.co_id else n.ID end, EFFECTIVE_DATE asc
If the company has paid every month it works out fine but the point is to find the companies that haven't paid so suppose Company XYZ paid every month in 2015 except June I need a row for June for Company XYZ that has a NULL value or a zero or some other indicator that they missed a payment. As it stands now the row is simply omitted because the data isn't there and it is hard to find a missing row out of thousands or rows.
I realize it is probably a different type of join or something but I am just not getting it to work out.
You can create a dummy table for the months, left join the dbo.Activity to it, that way you'll get all the months, and then join that to dbo.Name
1) Generate all the months from 1 to 12 with a recursive cte.
2) Get all months years and companies combinations with a cross join.
3) left join on this result-set to show missing months.
with months as (select 1 mth
union all
select mth+1 from months where mth<12)
,yearmonthscompanies as (select *
from months m
cross join (select 2015 yr union all select 2016 yr) y
cross join (select distinct id,co_id,company from name) c
)
SELECT
case when ymc.co_id <>'' then ymc.co_id else ymc.ID end ID
,su.CONTINUOUS_SINCE
,ymc.COMPANY
,coalesce(a.effective_date,datefromparts(ymc.yr,ymc.mth,1)) as effective_date
,coalesce(a.AMOUNT,0) amount
FROM yearmonthscompanies ymc
LEFT JOIN dbo.Name n ON n.co_id=ymc.co_id and n.id=ymc.id and n.company=ymc.company
LEFT JOIN dbo.Activity a ON n.ID = a.ID and a.PRODUCT_CODE='rental'
and n.MEMBER_TYPE in ('rb','rl') and a.EFFECTIVE_DATE Between '2015-07-01' and GetDate()
and a.ACTIVITY_TYPE='dues'
and year(a.effective_date) = ymc.yr and month(a.effective_date) = ymc.mth
inner JOIN dbo.Loc_Info l ON n.ID = l.ID
inner JOIN dbo.Segment_Categories s ON l.CURRENT_SEGMENT = s.CODE
inner JOIN dbo.Subscriptions su on su.id=n.id
order by case when ymc.co_id <>'' then ymc.co_id else ymc.ID end
,effective_date

Calculate the SUM of a SUM

I'm struggling with calculating the SUM on a Query that has a SUM. Here's my query:
SELECT rs.resellerid
,r.company
,r.insidesales
,SUM(total_reseller_sales) as TotalResellerSalesYear
FROM sales_report_resellers rs
INNER JOIN resellers r
ON rs.resellerid = r.resellerid
WHERE (sid > '282' AND sid < '292')
AND r.insidesales = 1
GROUP BY rs.resellerid, r.company, r.insidesales
The query returns 5 records with each a dollar amount. I need to the SUM of all 5 records.
Remove Group By and non aggregate columns from Select list
SELECT SUM(total_reseller_sales) as Total
FROM sales_report_resellers rs
INNER JOIN resellers r
ON rs.resellerid = r.resellerid
WHERE (sid > '282' AND sid < '292')
AND r.insidesales = 1
Without seeing a sample dataset, I would guess you need to remove resellerid from the SELECT and GROUP BY.
SELECT
[r].[company]
,[r].[insidesales]
,SUM([total_reseller_sales]) AS [TotalResellerSalesYear]
FROM
[sales_report_resellers] [rs]
INNER JOIN [resellers] [r] ON [rs].[resellerid] = [r].[resellerid]
WHERE
(
[sid] > '282'
AND [sid] < '292'
)
AND [r].[insidesales] = 1
GROUP BY
[r].[company]
,[r].[insidesales];

Query with LEFT OUTER JOIN on subqueries with SUMs

Im trying to perform an OUTER JOIN on related tables, but I want to JOIN the SUMs not the actual data. This query is flawed so I am looking for help on this structure, but also Im curious if there is a more elegant way of performing this type of query.
SELECT firstname,lastname, thesum1, thesum2 FROM whovians
LEFT OUTER JOIN (
SELECT SUM(thevalue) AS thesum1 FROM friends WHERE doctornumref = 10 AND year = 1968
) AS derivedTable1
ON (whovians.doctornum = friends.doctornumref)
LEFT OUTER JOIN (
SELECT SUM(amount) AS thesum2 FROM enemies WHERE doctornumref = 10 AND year = 1968
) AS derivedTable2
ON (whovians.doctornum = enemies.doctornumref) WHERE year = 1968 AND doctornum = 10;
Should work like this:
SELECT w.firstname, w.lastname, derived1.thesum1, derived2.thesum2
FROM whovians w
LEFT JOIN (
SELECT doctornumref, SUM(thevalue) AS thesum1
FROM friends
WHERE doctornumref = 10
AND year = 1968
GROUP BY 1
) AS derived1 ON derived1.doctornumref = w.doctornum
LEFT JOIN (
SELECT doctornumref, SUM(amount) AS thesum2
FROM enemies
WHERE doctornumref = 10
AND year = 1968
GROUP BY 1
) AS derived2 ON derived2.doctornumref = w.doctornum
WHERE w.doctornum = 10
AND w.year = 1968;
In this particular case, since you restrict to the same year and doctornumref / doctornum in outer query as well as subqueries, and the subquery can only return 0 or 1 rows, you can simplify with lowly correlated subqueries:
SELECT firstname,lastname
, (SELECT SUM(thevalue)
FROM friends
WHERE doctornumref = w.doctornum
AND year = w.year) AS thesum1
, (SELECT SUM(amount)
FROM enemies
WHERE doctornumref = w.doctornum
AND year = w.year) AS thesum2
FROM whovians w
WHERE year = 1968
AND doctornum = 10;
If (year, doctornum) is not unique in table whovians, the first form will prevent repeated evaluation of the subqueries and perform better, though.
You can still simplify:
SELECT w.firstname, w.lastname, f.thesum1, e.thesum2
FROM whovians w
LEFT JOIN (
SELECT SUM(thevalue) AS thesum1
FROM friends
WHERE doctornumref = 10
AND year = 1968
) f ON true -- 0 or 1 row in subquery, guaranteed to match
LEFT JOIN (
SELECT SUM(amount) AS thesum2
FROM enemies
WHERE doctornumref = 10
AND year = 1968
) e ON true
WHERE w.doctornum = 10
AND w.year = 1968;