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

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;

Related

Convert Access Crosstab Query to SQL Server

I have a crosstab query in MS Access which runs very slow after migrating my backend to an SQL Server 2017. So I want to create a view in SQL that does the same aggregation.
MS Access Query:
TRANSFORM Sum([Auftrag Positionen].Gesamtpreis) AS SummevonGesamtpreis
SELECT Format$([Stammdaten Datum].[Datum],'yyyy\/mm mmmm') AS Monat, Sum([Auftrag Positionen].Gesamtpreis) AS Gesamt
FROM [Stammdaten Datum] LEFT JOIN (Auftrag LEFT JOIN ([Stammdaten Statistik] RIGHT JOIN [Auftrag Positionen] ON [Stammdaten Statistik].Kennzeichen = [Auftrag Positionen].Statistik) ON Auftrag.[Auftrags-Nummer] = [Auftrag Positionen].[Auftrags-Nummer]) ON [Stammdaten Datum].Datum = Auftrag.Auftragseingang
WHERE (((Auftrag.[Auftrag-Angebot])="Auftrag"))
GROUP BY Format$([Stammdaten Datum].[Datum],'yyyy\/mm mmmm')
ORDER BY Format$([Stammdaten Datum].[Datum],'yyyy\/mm mmmm') DESC
PIVOT [Stammdaten Statistik].Beschreibung;
I get that I can cancel out the access date formatting:
SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, [Stammdaten Datum].[Datum]), 0) AS Monat, Sum([Auftrag Positionen].Gesamtpreis) AS Gesamt
FROM [ROBI_1].[dbo].[Stammdaten Datum] LEFT JOIN ([ROBI_1].[dbo].Auftrag LEFT JOIN (ROBI_1.dbo.[Stammdaten Statistik] RIGHT JOIN ROBI_1.dbo.[Auftrag Positionen] ON [Stammdaten Statistik].Kennzeichen = [Auftrag Positionen].Statistik) ON Auftrag.[Auftrags-Nummer] = [Auftrag Positionen].[Auftrags-Nummer]) ON [ROBI_1].[dbo].[Stammdaten Datum].Datum = Auftrag.Auftragseingang
WHERE ((([Auftrag].[Auftrag-Angebot])='Auftrag'))
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, [Stammdaten Datum].[Datum]), 0)
ORDER BY DATEADD(MONTH, DATEDIFF(MONTH, 0, [Stammdaten Datum].[Datum]), 0) DESC
But I don't know how to do the pivot aggregation, everything I've tried gave me syntax errors. (I am a noob in SQL/T-SQL indeed).
I appreciate any help!
I guess it would be something like this:
;WITH MonatGesamt AS
(
SELECT
Monat = DATEPART(MONTH, SD.Datum)
, Gesamtpreis = ISNULL(AP.Gesamtpreis, 0)
FROM ROBI_1.dbo.[Stammdaten Datum] SD
LEFT JOIN ROBI_1.dbo.Auftrag AT ON AT.Auftragseingang = SD.Datum
LEFT JOIN ROBI_1.dbo.[Auftrag Positionen] AP ON AP.[Auftrags-Nummer] = AT.[Auftrags-Nummer]
WHERE AT.[Auftrag-Angebot] = 'Auftrag'
)
SELECT
Monat
, Gesamt = SUM(Gesamtpreis)
FROM MonatGesamt
GROUP BY Monat
ORDER BY Monat DESC

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

Compare Sales with last year sales per customer

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)

Update Column using calculation in last year from another table

I am trying to update (using Inner joins for three tables) item stats STAT for table IM_ITEM by highlighting items that sold less than 12 as "D" (Discontinue).
The 2nd table PS_TKT_HIST_LIN has the Quantity sold column QTY_SOLD for each item on each day and the date column BUS_DAT.
I also need a third table IM_INV to filter the data, I need to say the last received date LST_RECV_DAT for these items is earlier than "2019-01-01" and last sales date LST_SAL_DAT is after "2019-01-01". I used the following code
UPDATE M
SET M.STAT = 'D'
FROM
dbo.IM_ITEM AS M
INNER JOIN
IM_INV AS N
ON
M.ITEM_NO = N.ITEM_NO
INNER JOIN
dbo.PS_TKT_HIST_LIN S`
ON
M.ITEM_NO = S.ITEM_NO
WHERE
CONVERT(DATETIME, FLOOR(CONVERT(FLOAT, N.LST_RECV_DAT))) <= '2019-01-01'
AND CONVERT(DATETIME, FLOOR(CONVERT(FLOAT, N.LST_SAL_DAT))) >= '2019-01-01'
AND M.STAT = 'A'
AND SUM(case when DATEPART(YYYY, (BUS_DAT)) = DATEPART(YYYY, DATEADD(YYYY, -1, getdate()))
AND DATEPART(yyyy, (BUS_DAT)) = DATEPART(yyyy, DATEADD(YYYY, -1, getdate()))
then qty_sold else 0)<12
It comes with an error
Any advise please
You should use HAVING clause instead of Sum in where.
You can use CTE to achieve the value, then update accordingly.
;with cte as(
select ITEM_NO, ..
from ..
group by ITEM_NO
having .. < 12
)
update M
set SET M.STAT = 'D'
from dbo.IM_ITEM AS M
inner join cte on M.ITEM_NO = cte.ITEM_NO
You can't use an aggregate function in where clause unless defined under subquery.

Resources