T-SQL, zero sum for no match on join - sql-server

I have two tables, one with all my Branches, and one with all my sales. The sales table also contains a Sales Rep ID, a Branch ID, a month and a year.
I need a query that will return the sum of a specific rep's sales for a year, grouped by branch and month, and the query must return 0 if there has been no sales in a branch for that month. I have the following, which does not return 0 if there are no sales:
SELECT
s.Month,
b.BranchName,
SUM(s.InvoiceAmount) AS 'Sales'
FROM
Branch b
INNER JOIN
Sales s ON s.BranchID = b.BranchID
WHERE
s.Year = 2008
AND
s.SalesRepID= 11
GROUP BY
s.Month,
b.BranchName
ORDER BY
s.Month,
b.BranchName

You will need to add the "missing" data to be able to join it.
SELECT
b.BranchName,
SUM(ISNULL(s.InvoiceAmount, 0)) AS 'Sales',
s.Month
FROM
Branch b
LEFT OUTER JOIN (
SELECT
b.BranchID AS BranchID
, s.SalesRepID AS SalesRepID
, Months.Month AS Month
, Years.Year AS Year
, 0 AS InvoiceAmount
FROM
Sales s
CROSS JOIN (
SELECT 1 AS Month
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9
UNION ALL SELECT 10
UNION ALL SELECT 11
UNION ALL SELECT 12
) Months
CROSS JOIN (
SELECT 2007 AS Year
UNION ALL SELECT 2008
UNION ALL SELECT 2009
) Years
CROSS JOIN Branch b
UNION ALL SELECT
s.BranchID AS BranchID
, s.SalesRepID AS SalesRepID
, s.Month AS Month
, s.Year AS Year
, s.InvoiceAmount AS InvoiceAmount
FROM Sales s
)s ON s.BranchID = b.BranchID
WHERE
s.Year = 2008
AND s.SalesRepID= 11
GROUP BY
s.Month,
b.BranchName
ORDER BY
b.BranchName,
s.Month

You'll need to do a LEFT JOIN to Sales, so as to return even the reps that do not have any records in the Sales table.

If your query is returning NULL, you can use one of the coalescing methods: COALESCE(SUM(...), 0) will return the first non-NULL value in the list...

You need to use a left join and an isnull to get the sum right:
SELECT b.BranchName
, SUM(isnull(s.InvoiceAmount, 0)) AS 'Sales'
FROM Branch b
LEFT JOIN Sales s ON s.BranchID = b.BranchID
GROUP BY s.Month, b.BranchName
ORDER BY s.Month, b.BranchName
You still need to do some more work with it to get the months showing too if a salesman has no sales in a particular month.

I changed the join from inner to left outer and added the ISNULL function for branches with no sales.
SELECT
b.BranchName,
s.Month,
SUM(ISNULL(s.InvoiceAmount,0)) AS 'Sales'
FROM
Branch b
LEFT JOIN
Sales s ON s.BranchID = b.BranchID
WHERE
s.Year = 2008
AND
s.SalesRepID= 11
GROUP BY
s.Month,
b.BranchName
ORDER BY
s.Month,
b.BranchName

Related

Month by Month Sales breakdown for top 10 Product for specific year Using Adventure Works Database in SQL Server

This is what I used to find the top 10 products for 2013 by total sum of sales. What is the easiest way to get a monthly breakdown of sales for a specific product ID for the year?
SELECT TOP 10
sod.ProductID, prd.Name, SUM(LineTotal) AS SumOfSales
FROM
Sales.SalesOrderDetail AS SOD
JOIN
Sales.SalesOrderHeader AS SOH ON SOD.SalesOrderID = SOH.SalesOrderID
JOIN
Production.Product prd ON prd.ProductID = sod.ProductID
WHERE
SOH.OrderDate >= '01/01/2013'
AND SOH.OrderDate <= '12/31/2013'
GROUP BY
sod.ProductID, prd.Name
-- HAVING SUM(LineTotal) >= 2000000
ORDER BY
SUM(LineTotal) DESC
Image of SQL output
This is what I found after research but it says date_format is invalid
select date_format(sdate,'%M-%Y') as sdate,
sum(LineTotal) as 'netsales',
from Sales.SalesOrderDetail
where ProductID=782 and ModifiedDate >= '01/01/2013' and ModifiedDate <= '12/31/2013'
group by MONTH(sdate)
order by MONTH(sdate);
Full list:
select *
from Sales.SalesOrderDetail
where ProductID=782 and DATEPART(YEAR,ModifiedDate) = 2013
You can use "*" or column names
Mothly Group List:
select datepart(month,ModifiedDate) as sdate,
sum(LineTotal) as 'netsales',
from Sales.SalesOrderDetail
group by datepart(month,ModifiedDate)
but you will see month number in sdate column.

SQL select top 10 for each year

I have a fact database from which I want to make a trendline based on top 10 items based on sum quantity for each item per year.
I've done the following, but it does for example select more than 10 entities for my year 2007:
select TOP 10 sum(Quantity) as Quantity,DIM_Time.Year, DIM_Item.Name as Name
from Fact_Purchase
join DIM_Item on DIM_Item.BKey_ItemId = Fact_Purchase.DIM_Item
join DIM_Time on DIM_Time.ID = Fact_Purchase.DIM_Time_DeliveryDate
where Fact_Purchase.DIM_Company = 2 and DIM_Time.ID = FACT_Purchase.DIM_Time_DeliveryDate
Group by dim_item.Name, DIM_Time.Year
Order by Quantity DESC
How do I select top 10 items with the highest quantity through all my years, with only 10 top entities for each year?
As you can guess, the company is individual, and Is going to be a parameter in my report
I think this is what you're going for. My apologies if I messed up on translating your tables across.
select *
from (
select DIM_Time.[Year], dim_item.Name, SUM(Quantity) Quantity, RANK() OVER (PARTITION BY DIM_Time.[Year] ORDER BY SUM(Quantity) DESC) salesrank
from Fact_Purchase
join DIM_Item on DIM_Item.BKey_ItemId = Fact_Purchase.DIM_Item
join DIM_Time on DIM_Time.ID = Fact_Purchase.DIM_Time_DeliveryDate
where Fact_Purchase.DIM_Company = 2 and DIM_Time.ID = FACT_Purchase.DIM_Time_DeliveryDate
group by dim_item.Name, DIM_Time.[Year]
) tbl
where salesrank <= 10
order by [Year], salesrank
The subquery groups by name/year, and the RANK() OVER part sets up a sort of row index that increments by SUM(Quantity) and restarts for each Year. From there you just have to filter out anything with a salesrank (index) that's over 10.
SELECT
_year,
Name,
_SUM,
RANK_iD
FROM
(
SELECT
_year,
Name,
_SUM,
DENSE_RANK()OVER(PARTITION BY _year,_Month ORDER BY _SUM DESC) AS RANK_iD
FROM(
Select
DIM_Time AS _year,
DIM_Item as Name,
sum(Quantity) AS _SUM
from
#ABC
GROUP BY
_year,
Name
)A
)B
WHERE RANK_iD<=10

How to group by month of a date using a function in a select statement

I am having problems grouping by the month of a date when using a function. It was working before but the query was less complicated as I am now using a function that uses a rolling year from the current month. Here is my code.
SELECT
CASE
WHEN DATEDIFF(mm,dbo.fn_firstofmonth(getdate()), dbo.fn_firstofmonth(D.expected_date)) < 12
THEN DATEDIFF(mm,dbo.fn_firstofmonth(getdate()), dbo.fn_firstofmonth(D.expected_date)) + 1
ELSE 13 END AS [Expected Month],
P.probability AS [Category], COUNT(O.id) AS [Customers]
FROM opportunity_probability P
INNER JOIN opportunity_detail D ON D.probability_id = P.id
INNER JOIN opportunities O ON D.opportunity_id = O.id
INNER JOIN
(
SELECT opportunity_id
FROM opportunity_detail
GROUP BY opportunity_id
) T ON T.opportunity_id = O.customer_id
GROUP BY P.probability, MONTH(D.expected_date)
ORDER BY P.probability, MONTH(D.expected_date)
It works if I have D.expected_date in the GROUP BY but I need to group on the MONTH of this date as it does not bring through the data correctly.
You could always remove the group by, then put your entire select into another select, and than group by the outer select:
select t.A, t.B from (select A, datepart(month, b) as B) t group by t.A, t.B
This way you can address your month field as if it where a normal field.
Example is far from complete, but should get you on your way.
You can try to find month by this code:
GROUP BY P.probability, DATEPART(month, D.expected_date)
try this
SELECT
to_char(D.expected_date, 'YYYY-MM'),
CASE
WHEN DATEDIFF(mm,dbo.fn_firstofmonth(getdate()), dbo.fn_firstofmonth(D.expected_date)) < 12
THEN DATEDIFF(mm,dbo.fn_firstofmonth(getdate()), dbo.fn_firstofmonth(D.expected_date)) + 1
ELSE 13 END AS [Expected Month],
P.probability AS [Category], COUNT(O.id) AS [Customers]
FROM opportunity_probability P
INNER JOIN opportunity_detail D ON D.probability_id = P.id
INNER JOIN opportunities O ON D.opportunity_id = O.id
INNER JOIN
(
SELECT opportunity_id
FROM opportunity_detail
GROUP BY opportunity_id
) T ON T.opportunity_id = O.customer_id
GROUP BY P.probability, to_char(D.expected_date, 'YYYY-MM')
ORDER BY P.probability, to_char(D.expected_date, 'YYYY-MM')

create sql query to fetch repeat column values within time frame

Can someone help me with this query? I want to get the result of all the customer_id which repeats more than once in 24hrs
SELECT
O.Order_No, O.Customer_ID, O.DateOrdered, O.IPAddress,
C.FirstName, C.LastName, CD.nameoncard
FROM
Order_No O
INNER JOIN
CardData CD ON O.card_id = CD.id
INNER JOIN
Customers C ON O.customer_id = C.customer_id
ORDER BY
O.order_no desc
adding more details..
so suppose order with customer id xx was placed on 04/23 2:30 pm and again 2nd order was placed with same customer Id xx on same day 04/23 5:30 pm.
i want the query to return me customer Id xx
Thanks
select Customer_ID, CAST(DateOrdered as Date) DateOrdered, count(*) QTDE
from Order_No
group by Customer_ID, CAST(DateOrdered as Date)
having count(*) > 1
To get the customers who have orders issued after the first one, then you could use the following query:
select distinct A.Customer_ID
from Order_No A
inner join (select Customer_ID, min(DateOrdered) DateOrdered from Order_No group by Customer_ID ) B
on A.Customer_ID = B.Customer_ID
and A.DateOrdered - B.DateOrdered <= 1
and A.DateOrdered > B.DateOrdered
SQL Fiddle
To get all customers that have ANY TIME more than one order issued in period less or equal than 24h
select distinct A.Customer_ID
from Order_No A
inner join Order_No B
on A.Customer_ID = B.Customer_ID
and A.DateOrdered > B.DateOrdered
and A.DateOrdered - B.DateOrdered <= 1
SQL Fiddle
Self-join:
SELECT distinct O.Customer_ID
FROM
Order_No O
inner join Order_No o2
on o.customerID = o2.customerID
and datediff(hour, o.DateOrdered, o2.DateOrdered) between 0 and 24
and o.Order_No <> o2.Order_No
This will return all customer_IDs that have ever placed more than one order in any 24 hour period.
Edited to add the join criteria that the matching records should not be the same record. Should return customers who placed two different orders at the same time, but not customers who placed only one order.

Joining two select statement in sql

I have two select statements. 1st selectreturns data from previous year 2012, while 2nd select displays the current year. How will i join those two to get my desired output.
select a.id, b.item, a.sum(qty) as 'yr1qty', a.yr1amt from table A
left join table B on a.code = b.code
where date between '04/01/2012' and '04/07/2012'
group by a.id, b. item
select a.id, b.item, a.sum(qty) as 'yr2qty', a.yr2amt from table A
left join table B on a.code = b.code
where date between '04/01/2013' and '04/07/2013'
group by a.id, b. item
desired output:
id item yr1qty y1amt yr2qty yr2amt
01 item01 20 2000.00 5 500.00
02 item02 8 400.00
03 item03 10 1250.00
04 item04 3 60.00 2 40.00
05 item05 8 400.00
You should be able to join the two as subqueries using a full outer join
select
coalesce(a.id,b.id),
coalesce(a.item,b.item),
yr1qty,
yr1amt,
yr2qty,
yr2amt
from
(
select a.id, b.item, a.sum(qty) as 'yr1qty', a.yr1amt from table A
left join table B on a.code = b.code
where date between '04/01/2012' and '04/07/2012'
group by a.id, b. item) as a
full outer join
(
select a.id, b.item, a.sum(qty) as 'yr2qty', a.yr2amt from table A
left join table B on a.code = b.code
where date between '04/01/2013' and '04/07/2013'
group by a.id, b. item
) as b on a.id = b.id
Do you need two? Here's the result in one query ...
select a.id, b.item,
a.sum(
CASE WHEN date between '04/01/2012' and '04/07/2012'
THEN qty
ELSE 0
END) AS 'yr1qty', a.yr1amt,
a.sum(
CASE WHEN date between '04/01/2013' and '04/07/2013'
THEN qty
ELSE 0
END) AS 'yr2qty', a.yr2amt
from table A
left join table B on a.code = b.code
group by a.id, b.item
Did you need to use pivot?
select id,item, yr1qty,yr1amt, yr2qty, yr2amt from
(
select a.id, b.item, a.qty, a.amt,
case
when [date] between '2012-01-04' and '2012-07-01' then 'yr1qty'
when [date] between '2013-01-04' and '2013-07-01' then 'yr2qty'
else 'oor'
end as yrqty,
case
when [date] between '2012-01-04' and '2012-07-01' then 'yr1amt'
when [date] between '2013-01-04' and '2013-07-01' then 'yr2amt'
else 'oor'
end as yramt
from A
left join B on a.code = b.code
) x
pivot (
sum(qty) for yrqty in ([yr1qty],[yr2qty])
) qtyTotal
pivot (
sum(amt) for yramt in ([yr1amt],[yr2amt])
) amtTotal

Resources