Compare Sales with last year sales per customer - sql-server

I have a 2 queries that I have used UNION on to compare the sales value per customer over 2 years. The below returns 2 columns, one for organizations and one for the sales value/customer. But the 2 year split is not working. It seems to be pulling all the values into one column rather than having a column for 2018 and a column for 2019. Maybe I should be using a join or a sub-query?
The return result would look something like:
Organization Last Year Previous year
CUS 12000 160000
etc
SELECT Top 25
FORMAT(SUM(dbo.ARInvoices.arpFullInvoiceSubtotalBase), 'C2') AS "previousyear ", dbo.Organizations.cmoOrganizationID AS "Organization"
FROM (dbo.ARInvoices
LEFT OUTER JOIN dbo.Organizations ON dbo.ARInvoices.arpCustomerOrganizationID = dbo.Organizations.cmoOrganizationID)
WHERE YEAR(arpInvoiceDate) = year(DATEADD(year, -2, getdate()))AND arpInvoiceType = 1
GROUP BY dbo.Organizations.cmoOrganizationID
UNION
SELECT Top 25
FORMAT(SUM(dbo.ARInvoices.arpFullInvoiceSubtotalBase), 'C2') AS "Lastyear", dbo.Organizations.cmoOrganizationID AS "Organization"
FROM (dbo.ARInvoices
LEFT OUTER JOIN dbo.Organizations ON dbo.ARInvoices.arpCustomerOrganizationID = dbo.Organizations.cmoOrganizationID)
WHERE YEAR(arpInvoiceDate) = year(DATEADD(year, -1, getdate()))AND arpInvoiceType = 1
GROUP BY dbo.Organizations.cmoOrganizationID'

You could do conditional aggregation
select
sum(case
when arpInvoiceDate >= datefromparts(year(getdate()) - 2, 1, 1)
and arpInvoiceDate < datefromparts(year(getdate()) - 1, 1, 1)
then i.arpFullInvoiceSubtotalBase
end) as previousYear,
sum(case
when arpInvoiceDate >= datefromparts(year(getdate()) - 1, 1, 1)
then i.arpFullInvoiceSubtotalBase
end) as lastYear
from dbo.ARInvoices i
inner join dbo.Organizations o ON i.arpCustomerOrganizationID = o.cmoOrganizationID
where arpInvoiceType = 1 and arpInvoiceDate >= datefromparts(year(getdate()) - 2, 1, 1)
group by o.cmoOrganizationID
Notes:
I used INNER JOIN instead of LEFT JOIN since one of the columns for the left table is used in the GROUP BY clause
table aliases do make the query shorter to write and easier to read
I changed the implementation of the date filtering so no date function is used on the table columns (this makes the query more efficient)

Related

SQL Query to group by time and roll up and concatenate string values

I am trying to get a particular format from a group of times and days between two tables.
Database:
MeetingTime table has a relationship from MeetingTime.DayOfWeekId (foreign key) to table DayOfWeek.Id (Primary Key). Example Query:
select t.ClassId, d.Name, t.StartTime, t.EndTime
From MeetingTime t
Inner Join DaysOfWeek d on d.Id = t.DayOfWeekId
Where t.classId = 8
Results:
My desired results for this set of data would be one row, because the start and end times are the same.
09:00-15:35 M/T/W/Th/F
NOTE, the start and end time above, can be separate columns above, the main goal is display the days of the week for each grouped time.
The monkey wrench is that the times can be completely different or the same. For example this data set:
I would want displayed in 2 rows:
07:35-14:15 M/T/W
08:00-14:15 Th/F
And finally, this dataset where all times are different:
Would display in 5 rows:
13:48-14:48 M
15:48-16:48 T
05:49-23:53 W
14:49-16:49 Th
13:49-16:49 F
I haven't had much success with grouping the times. I did figure out how to concatenate the days of the week rolling the days up into one column using the 'Stuff' Operator, but didn't get anywhere with the grouping of the start and end time coupled with this yet.
Concatenating and rolling up days:
STUFF((SELECT '/ ' +
(CASE
WHEN d.[Name] = 'Thursday' THEN SUBSTRING(d.[Name], 1, 2)
WHEN d.[Name] = 'Sunday' THEN 'U'
WHEN d.[Name] != '' THEN SUBSTRING(d.[Name], 1, 1)
ELSE NULL
END)
FROM MeetingTime m
Inner Join [DayOfWeek] d on d.Id = m.DayOfWeekId
Where m.ClassId = class.Id
FOR XML PATH('')), 1, 1, '') [ClassSchedule]
I'm also not opposed to just returning the rows and handling the data manipulation in C# code, but wanted to see if SQL could handle it.
I was able to get this working. Here is the query:
select
t.ClassId,
t.StartTime,
t.EndTime,
STUFF((SELECT '/' + (CASE
WHEN w.[Name] = 'Thursday' THEN SUBSTRING(w.[Name], 1, 2)
WHEN w.[Name] = 'Sunday' THEN 'U'
WHEN w.[Name] != '' THEN SUBSTRING(w.[Name], 1, 1)
ELSE NULL
END)
From MeetingTime s
Inner Join DayOfWeek w on w.Id = s.DayOfWeekId
Where s.classId = 7 and s.DayOfWeekId > 0
and s.StartTime = t.StartTime
and s.EndTime = t.EndTime
FOR XML PATH('')), 1, 1, '') [ClassSchedule]
From MeetingTime t
Inner Join DayOfWeek d on d.Id = t.DayOfWeekId
Where t.classId = 7 and t.DayOfWeekId > 0
Group by t.StartTime, t.EndTime, t.ClassId
Obviously hardcoded Id you would want to create a variable.
Results where the start and end time are all the same:
Some times the same and some different:
Some times the same and some different with days not in order:
Times all different:
Times with only Mon/Wed/Fri.
I feel pretty good about this, except I'd like to fix the order of the above result image where all times are different and the days are not in chronological order.

Return a zero value if there is no data found

I am trying to create a query to pull the number of new clients/week over 3 months. In the weeks where there was no new customers, it doesn't return anything - I would like it to return a zero value. I understand I need to create a table of all the possible weeks. But I am having trouble understanding how to create the table and join it.
SELECT distinct COUNT(DISTINCT dbo.Quotes.qmpQuoteID) AS "Qty of Quote Lines Won",
MIN(OmpOrderDate) As "WeekStarting"
FROM SalesOrders
Left Outer Join SALESORDERLINES On OMPSALESORDERID = OMLSALESORDERID
Left Outer Join QUOTELINES On OMLQUOTEID = QMLQUOTEID And OMLQUOTELINEID = QMLQUOTELINEID
Left Outer Join QUOTES On QMLQUOTEID = QMPQUOTEID left outer join organizations on dbo.Quotes.qmpCustomerOrganizationID = dbo.Organizations.cmoOrganizationID
WHERE ompOrderDate >= DATEADD(MOnth, -3, GETDATE())
AND cmocustomerprospectdate >= DATEADD(MOnth, -3, GETDATE())
AND OMLQUOTEID > 1
Group By DATEADD(week, DATEDIFF(week, 0, ompOrderDate),0)
Order by MIN(OmpOrderDate) ASC
Thanks in advance!
this returns the results :
Qty of Quote Lines Won Week Starting
1                           23/04/2020
1                           15/05/2020
2                           19/05/2020
1                           etc
2
Ideally this would look like:
Qty of Quote Lines Won Week Starting
1                            21/04/2020
0                           28/04/2020
0                           05/05/2020
1                           12/05/2020
etc - many thanks - I'm sorry my formatting is terrible

Similar to the last Joining two tables on columns that don't equal and summing 3 columns in the second table

I have a equipment table and a mobile work order table that I am wanting to join, I am wanting to display all the equipment and the reactive hours. If there is no reactive hours for a certain piece of equipment then I want to display a zero in the rows where value is null. This is what I have below. It only gives me the equipment that has reactive hours in the other table.
SQL Server
Select e.EquipNbr, coalesce(sum(mw.MaintTech1hours + mw.MaintTech2hours + mw.MaintTech3hours), 0) ReactiveHours
From MblEquip e
inner join MobileWorkOrder mw on
mw.EquipNbr = e.EquipNbr
and mw.DateTm between DATEADD(month, DATEDIFF(month, 0, getDate()), 0)
and DATEADD(month, DATEDIFF(month, -1, getDate()), -1)
where e.DelFlg = 0 and mw.Category = 'Reactive'
group by e.EquipNbr order by ReactiveHours Desc;
If you test a value into 'where condition', your 'left outer join' is equivalent to 'inner join'.
Try this (SQL remained)
Select e.EquipNbr, coalesce(sum(isnull(mw.MaintTech1hours, 0) + isnull(mw.MaintTech2hours, 0) + isnull(mw.MaintTech3hours, 0)), 0) ReactiveHours
From MblEquip e
left outer join MobileWorkOrder mw on mw.EquipNbr = e.EquipNbr and mw.Category = 'Reactive'
and Year(mw.DateTm) =Year(getdate()) and Month(mw.DateTm) =Month(getdate())
where e.DelFlg = 0
group by e.EquipNbr
order by ReactiveHours Desc;

Exclude certain line depending on a certain condition in t-SQL

Firstly, I have created the following stock sales SELECT statement:
SELECT
PostST.TxDate AS TxDate,
PostST.Reference AS InvNum,
Client.Name AS CustomerName,
SalesRep.Code AS SalesRep,
WhseMst.Code AS Whse,
CONCAT (StkItem.Description_1, ' - ',StkItem.Code) AS Item,
_etblLotTracking.cLotDescription AS LotNumber,
CASE
WHEN PostST.TrCodeID = 34 THEN (PostST.Quantity * 1)
WHEN PostST.TrCodeID = 30 THEN (PostST.Quantity * -1)
ELSE 0
END AS QtySold,
CAST
(
CASE
WHEN PostST.TrCodeID = 34 THEN (PostST.Credit / PostST.Quantity)
WHEN PostST.TrCodeID = 30 THEN (PostST.Debit / (PostST.Quantity * -1))
ELSE 0
END
as [money]
)
AS CustomerPrice,
StkItem.ItemGroup AS ItemGroup,
StkItem.ulIIStockType AS StockType,
YEAR (PostST.TxDate) AS Year,
DATENAME (MONTH, (PostST.TxDate)) AS Month
FROM
PostST
INNER JOIN StkItem
ON StkItem.StockLink = PostST.AccountLink
INNER JOIN PostAR
ON PostAR.cAuditNumber = PostST.cAuditNumber
INNER JOIN Client
ON Client.DCLink = PostAR.AccountLink
INNER JOIN SalesRep
ON SalesRep.idSalesRep = PostAR.RepID
INNER JOIN WhseMst
ON WhseMst.WhseLink = PostST.WarehouseID
FULL JOIN _etblLotTracking
ON _etblLotTracking.idLotTracking = PostST.iLotID
WHERE
PostST.TrCodeID IN (34, 30) AND StkItem.ItemGroup <> 'TRAN'
This query is run from Sage Evolution and data is dumped into Excel. From there I manipulate to view each item and the sales history in quantity per month and year.
My problem is as follows:
Within the data that follows, is sometimes a customer who has perhaps stopped buying a particular item. What I need is for this statement to also filter out a line by the following condition:
If the customer does not have a sale for 6 months or more, then that STOCK ITEM must be filtered out for that specific customer.
Thank you!

Counting duplicate items in different order

Goal:
To know if we have purchased duplicate StockCodes or Stock Description more than once on difference purchase orders
So, if we purchase Part ABC on Purchase Order 1 and Purchase Order 2, it should return the result of
PurchaseOrders, Part#, Qty
Purchase Order1, Purchase Order2, ABC, 2
I just don't know how to pull the whole code together, more to the point, how do I know if it's occurred on more than 1 Purchase Order without scrolling through all the results , may also have to do with Multiple (Having Count) Statements as I only seem to be doing by StockCode
SELECT t1.PurchaseOrder,
t1.MStockCode,
Count(t1.MStockCode) AS SCCount,
t1.MStockDes,
Count(t1.MStockDes) AS DescCount
FROM PorMasterDetail t1
INNER JOIN PorMasterHdr t2
ON t1.PurchaseOrder = t2.PurchaseOrder
WHERE Year(t2.OrderEntryDate) = Year(Getdate())
AND Month(t2.OrderEntryDate) = Month(Getdate())
GROUP BY t1.PurchaseOrder,
t1.MStockCode,
t1.MStockDes
HAVING Count(t1.MStockCode) > 1
Using responses I came up with the following
select * from
(
SELECT COUNT(dbo.InvMaster.StockCode) AS Count, dbo.InvMaster.StockCode AS StockCodes,
dbo.PorMasterDetail.PurchaseOrder, dbo.PorMasterHdr.OrderEntryDate
FROM dbo.InvMaster INNER JOIN dbo.PorMasterDetail ON
dbo.InvMaster.StockCode = dbo.PorMasterDetail.MStockCode
INNER JOIN dbo.PorMasterHdr ON dbo.PorMasterDetail.PurchaseOrder = dbo.PorMasterHdr.PurchaseOrder
WHERE YEAR(dbo.PorMasterHdr.OrderEntryDate) = YEAR(GETDATE())
GROUP BY dbo.InvMaster.StockCode, dbo.InvMaster.StockCode,
dbo.PorMasterDetail.PurchaseOrder, dbo.PorMasterHdr.OrderEntryDate
) Count
Where Count.Count > 1
This returns the below , which is starting to be a bit more helpful
In result line 2,3,4 we can see the same stock code (*30044) ordered 3 times on different
purchase orders.
I guess the question is, is it possible to look at If something was ordered more than once within say a 30 day period.
Is this possible?
Count StockCodes PurchaseOrder OrderEntryDate
2 *12.0301.0021 322959 2014-09-08
2 *30044 320559 2014-01-21
8 *30044 321216 2014-03-26
4 *30044 321648 2014-05-08
5 *32317 321216 2014-03-26
4 *4F-130049/TEST 323353 2014-10-22
5 *650-1157/E 322112 2014-06-24
2 *650-1757 321226 2014-03-27
SELECT *
FROM
(
SELECT h.OrderEntryDate, d.*,
COUNT(*) OVER (PARTITION BY d.MStockCode) DupeCount
FROM
PorMasterHdr h
INNER JOIN PorMasterDetail d ON
d.PurchaseOrder = h.PurchaseOrder
WHERE
-- first day of current month
-- http://blog.sqlauthority.com/2007/05/13/sql-server-query-to-find-first-and-last-day-of-current-month/
h.OrderEntryDate >= CONVERT(VARCHAR(25), DATEADD(dd,-(DAY(GETDATE())-1),GETDATE()),101)
) dupes
WHERE
dupes.DupeCount > 1;
This should work if you're only deduping on stock code. I was a little unclear if you wanted to dedupe on both stock code and stock desc, or either stock code or stock desc.
Also I was unclear on your return columns because it almost looks like you're wanting to pivot the columns so that both purchase order numbers appear on the same line.

Resources