SQL - Average on DateDiff with taking out weekends - sql

I have an SQL statement that calculates how many days late our vendors pay for invoices. It only includes weekdays and it works perfectly. My customer is now asking if I can have an average of those days late per vendor. Here is my code that works:
DATEDIFF(dd, PURCHTABLE.CONFIRMEDDLV, MAX(VENDPACKINGSLIPJOUR.DELIVERYDATE))
-(DATEDIFF(wk, PURCHTABLE.CONFIRMEDDLV, MAX(VENDPACKINGSLIPJOUR.DELIVERYDATE)) * 2)
-(CASE WHEN DATENAME(dw, PURCHTABLE.CONFIRMEDDLV) = 'Sunday'
THEN 1
ELSE 0
END)
-(CASE WHEN DATENAME(dw, MAX(VENDPACKINGSLIPJOUR.DELIVERYDATE)) = 'Saturday'
THEN 1
ELSE 0
END) AS 'DAYS LATE'
If I try to put this in an AVG(), but it tells me I cannot perform an aggregate function on an aggregate function.
UPDATE:
This is my original SQL:
SELECT
PURCHTABLE.PURCHNAME AS 'VENDOR NAME',
PURCHTABLE.ORDERACCOUNT AS 'VENDOR NUMBER',
COUNT(DISTINCT PURCHTABLE.PURCHID) AS 'PURCHASE ORDER',
COUNT(PURCHLINE.LINENUMBER) AS 'NUMBER OF LINES',
SUM(PURCHLINE.LINEAMOUNT) AS 'PO PRICE TOTAL',
DATEDIFF(dd, PURCHTABLE.CONFIRMEDDLV, MAX(VENDPACKINGSLIPJOUR.DELIVERYDATE))-(DATEDIFF(wk, PURCHTABLE.CONFIRMEDDLV, MAX(VENDPACKINGSLIPJOUR.DELIVERYDATE)) * 2)-(CASE WHEN DATENAME(dw, PURCHTABLE.CONFIRMEDDLV) = 'Sunday' THEN 1 ELSE 0 END)-(CASE WHEN DATENAME(dw, MAX(VENDPACKINGSLIPJOUR.DELIVERYDATE)) = 'Saturday' THEN 1 ELSE 0 END) AS 'DAYS LATE'
FROM
PURCHTABLE
JOIN
PURCHLINE ON PURCHLINE.PURCHID = PURCHTABLE.PURCHID
JOIN
VENDPACKINGSLIPJOUR ON VENDPACKINGSLIPJOUR.PURCHID = PURCHTABLE.PURCHID
WHERE
PURCHTABLE.DELIVERYDATE >= '2017-01-01'
AND
PURCHTABLE.DELIVERYDATE <= '2017-01-20'
AND
PURCHTABLE.ORDERACCOUNT = 'VN03526'
GROUP BY
PURCHTABLE.PURCHNAME,
PURCHTABLE.ORDERACCOUNT,
PURCHTABLE.DELIVERYDATE,
PURCHTABLE.CONFIRMEDDLV
So I don't quite understand how I change that to what you are saying.....I'm tried this but it's not working.
SELECT
PURCHTABLE.PURCHNAME AS 'VENDOR NAME',
PURCHTABLE.ORDERACCOUNT AS 'VENDOR NUMBER'
FROM
(SELECT
PURCHTABLE.PURCHNAME AS 'VENDOR NAME',
PURCHTABLE.ORDERACCOUNT AS 'VENDOR NUMBER',
COUNT(DISTINCT PURCHTABLE.PURCHID) AS 'PURCHASE ORDER',
COUNT(PURCHLINE.LINENUMBER) AS 'NUMBER OF LINES',
SUM(PURCHLINE.LINEAMOUNT) AS 'PO PRICE TOTAL',
DATEDIFF(dd, PURCHTABLE.CONFIRMEDDLV, MAX(VENDPACKINGSLIPJOUR.DELIVERYDATE))-(DATEDIFF(wk, PURCHTABLE.CONFIRMEDDLV, MAX(VENDPACKINGSLIPJOUR.DELIVERYDATE)) * 2)-(CASE WHEN DATENAME(dw, PURCHTABLE.CONFIRMEDDLV) = 'Sunday' THEN 1 ELSE 0 END)-(CASE WHEN DATENAME(dw, MAX(VENDPACKINGSLIPJOUR.DELIVERYDATE)) = 'Saturday' THEN 1 ELSE 0 END) AS 'DAYS LATE'
FROM
PURCHTABLE
JOIN
PURCHLINE ON PURCHLINE.PURCHID = PURCHTABLE.PURCHID
JOIN
VENDPACKINGSLIPJOUR ON VENDPACKINGSLIPJOUR.PURCHID = PURCHTABLE.PURCHID
WHERE
PURCHTABLE.DELIVERYDATE >= '2017-01-01'
AND
PURCHTABLE.DELIVERYDATE <= '2017-01-20'
AND
PURCHTABLE.ORDERACCOUNT = 'VN03526') A
GROUP BY
PURCHTABLE.PURCHNAME,
PURCHTABLE.ORDERACCOUNT,
PURCHTABLE.DELIVERYDATE,
PURCHTABLE.CONFIRMEDDLV

The code you have at the moment will be part of a larger query, such as:
select VendorID
,VendorName
...
...
,<Your Days Late Code> as DaysLate
,InvoiceAmount
...
from tables
group by VendorID
,VendorName
all you need to do to average over all of this is pick the other columns you want to do the average by and wrap the whole thing in another select statement:
select VendorID
,VendorName
,avg(DaysLate) as AverageDaysLate
,sum(InvoiceAmount) as TotalInvoiceAmount
from(
select VendorID
,VendorName
...
...
,<Your Days Late Code> as DaysLate
,InvoiceAmount
...
from tables
group by VendorID
,VendorName
) a
group by VendorID
,VendorName

Related

sql difference in two dates

In sql server, I have two tables:
Tran_Ex
Transactions
They both have customer_id which is the key to join the tables.
I want to find the difference in WORKING DAYS of the Date_Reported (from transactions) from the Date_Received (from the Tran_ex). I would like an extra column with these figures:
eg
Date Reported | Date Received | Difference in days
Thanks in advance
Use DATEDIFF() function()
You can get Working Day (Monday to Friday) difference from this query, for bank holidays you need seperate logic.
Select Date_Reported,
Date_Received ,
(DATEDIFF(dd, Date_Reported, Date_Received) + 1)
-(DATEDIFF(wk, Date_Reported, Date_Received) * 2)
-(CASE WHEN DATENAME(dw, Date_Reported) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, Date_Received) = 'Saturday' THEN 1 ELSE 0 END)
AS Working_days_Difference
from Tran_Ex as tx
inner join
Transactions as tr
on(tx.customer_id = tr.customer_id)
Modified the Query on suggestions based on #scsimon for not using shorthands.
SELECT Date_Reported,
Date_Received ,
datediff(day,((CASE WHEN Datename(weekday, Date_Reported) = 'Sunday' THEN 1 ELSE 0 END ) - (CASE WHEN Datename(weekday, Date_Received ) = 'Saturday' THEN 1 ELSE 0 END )),Datediff(day,(Datediff(week, Date_Reported, Date_Received ) * 2 ),
(Datediff(day, Date_Reported, Date_Received ) + 1 )))
AS Working_days_Difference
from Tran_Ex as tx
inner join
Transactions as tr
on(tx.customer_id = tr.customer_id)
Use DATEDIFF() function :
select t.Date_Reported, t1.Date_Received,
datediff(day, t.Date_Reported, t1.Date_Received) [Difference in days]
from Tran_Ex tx
inner join Transactions t on t.customer_id = tx.customer_id;

SQL query error not working

I have written a SQL query but I am getting error as
Incorrect syntax near 'company_name'.
I am using SQL Server 2005.
My query:
SELECT TOP 1
MONTH(a.dt_of_leave) MONTH,
YEAR(a.dt_of_leave) YEAR
FROM
emp_mst a
WHERE
MONTH(a.dt_of_leave) >= MONTH(getdate()) - 1
AND YEAR(a.dt_of_leave) = CASE
WHEN MONTH(getdate()) = 1
THEN YEAR(getdate()) - 1
ELSE YEAR(getdate()) company_name 'COMPANY NAME',
Deputed_Company_Name 'DEPUTED COMPANY NAME' emp_card_no 'EMP CODE',
emp_name 'EMPLOYEE NAME',
LWP,
'' Remarks,
Adj_Days Gain_Loss_LOP_Days,
VAL_DAY LOP_Days_Desc,
MONTH,
YEAR
FROM XXACL_EMP_INFO_LWP_OTDAYS_HRS_V WHERE emp_type='C'
AND MONTH = '3'
AND YEAR = '2016'
AND emp_card_no IN(312,
1250,
362)
UPDATE
I have two working queries:
1st query
select top 1
month(a.dt_of_leave) month,
year(a.dt_of_leave) year
from
emp_mst a
where
month(a.dt_of_leave) >= month(getdate())-1
and year(a.dt_of_leave) = case
when month(getdate()) = 1
then year(getdate()) - 1
else year(getdate())
end
and emp_card_no IN (312, 1250, 362)
order by
emp_name
2nd query:
select
company_name 'COMPANY NAME',
Deputed_Company_Name 'DEPUTED COMPANY NAME',
emp_card_no 'EMP CODE',
emp_name 'EMPLOYEE NAME',
LWP, '' Remarks,
Adj_Days Gain_Loss_LOP_Days,
VAL_DAY LOP_Days_Desc, month, year
from
XXACL_EMP_INFO_LWP_OTDAYS_HRS_V
where
emp_type = 'C'
and month = '3' and year = '2015'
and emp_card_no in (312, 1250, 362)
What I want is in second query, I want to add month and year which i get from first query..
I need to merge that in second query
Try something like this - it will use the three emp_card_no given in the outer WHERE clause, and get their most recent month/year entry:
; WITH MonthAndYear AS
(
SELECT
MONTH(a.dt_of_leave) month,
YEAR(a.dt_of_leave) year,
emp_card_no,
RowNum = ROW_NUMBER() OVER (PARTITION BY emp_card_no ORDER BY dt_of_leave DESC)
FROM
emp_mst a
WHERE
MONTH(a.dt_of_leave) >= MONTH(GETDATE()) - 1
AND YEAR(a.dt_of_leave) = CASE
WHEN MONTH(GETDATE()) = 1
THEN YEAR(GETDATE()) - 1
ELSE YEAR(GETDATE())
END
)
SELECT
x.company_name 'COMPANY NAME',
x.Deputed_Company_Name 'DEPUTED COMPANY NAME',
x.emp_card_no 'EMP CODE',
x.emp_name 'EMPLOYEE NAME',
x.LWP, '' Remarks,
x.Adj_Days Gain_Loss_LOP_Days,
x.VAL_DAY LOP_Days_Desc,
x.month, x.year
FROM
XXACL_EMP_INFO_LWP_OTDAYS_HRS_V x
INNER JOIN
MonthAndYear my ON x.emp_card_no = my.emp_card_no
AND x.Month = my.Month AND x.Year = my.Year
AND my.RowNum = 1
WHERE
x.emp_type = 'C'
AND x.emp_card_no IN (312, 1250, 362);
I hope that's what you're looking for ! If not - please share table structure, sample data, expected output etc.

group by week, get first day of week, pivot by weekday

I need to make a query that will show how much of each item/unit combination each customer ordered each week (group by week) while showing the first day the week, and also showing the quantity ordered each day of that week (pivot by weekday). So far i have this, but I'm not sure how to group this by week.
SELECT customer_name, item_code, item_desc, unit, delivery_date, [Monday], [Tuesday], [Wednesday], [Thursday], [Friday], [Saturday], [Sunday]
FROM (
SELECT customer_name, item_code , item_desc , unit, delivery_date, DATENAME(dw, delivery_date) AS DayWeek, qty
FROM order_items oi inner join orders on localID = local_order_id
) AS ordersItems
pivot (
SUM(qty) FOR DayWeek IN ([Monday], [Tuesday], [Wednesday], [Thursday], [Friday], [Saturday], [Sunday])
) AS pvt
The following query groups by customer/item/unit/week# combination. It returns the total number of orders as well as the # of orders broken down by the day of the week. The CASE statement is used along with the SUM function to get the total number of orders for each day of the week
EDIT: Revised query to group by Week Starting Date (instead of week # previously)
SELECT customer_name, item_code, item_desc, unit,
CASE SIGN(7-(DATEPART(dw, action)+2))
WHEN -1 THEN CAST(DATEADD(dd, 7-(DATEPART(dw, action)+2), action) AS DATE)
WHEN 0 THEN CAST(action AS DATE)
WHEN 1 THEN CAST(DATEADD(dd, -(DATEPART(dw, action)+2), action) AS DATE)
END Week_Starting_Friday
SUM(qty) Total_Orders,
SUM(
CASE DATENAME(dw, delivery_date) WHEN 'Monday' THEN qty ELSE 0 END
) [Monday],
SUM(
CASE DATENAME(dw, delivery_date) WHEN 'Tuesday' THEN qty ELSE 0 END
) [Tuesday],
SUM(
CASE DATENAME(dw, delivery_date) WHEN 'Wednesday' THEN qty ELSE 0 END
) [Wednesday],
SUM(
CASE DATENAME(dw, delivery_date) WHEN 'Thursday' THEN qty ELSE 0 END
) [Thursday],
SUM(
CASE DATENAME(dw, delivery_date) WHEN 'Friday' THEN qty ELSE 0 END
) [Friday],
SUM(
CASE DATENAME(dw, delivery_date) WHEN 'Saturday' THEN qty ELSE 0 END
) [Saturday],
SUM(
CASE DATENAME(dw, delivery_date) WHEN 'Sunday' THEN qty ELSE 0 END
) [Sunday]
FROM order_items oi inner join orders on localID = local_order_id
GROUP BY customer_name, item_code, item_desc, unit,
CASE SIGN(7-(DATEPART(dw, action)+2))
WHEN -1 THEN CAST(DATEADD(dd, 7-(DATEPART(dw, action)+2), action) AS DATE)
WHEN 0 THEN CAST(action AS DATE)
WHEN 1 THEN CAST(DATEADD(dd, -(DATEPART(dw, action)+2), action) AS DATE)
END
ORDER BY 5, customer_name, item_code, item_desc, unit;
References:
CASE statement on MSDN
DATENAME on MSDN

SQL Query Sum up Values Actual Year to Date and What the Average YTD

I need a query that, totals up expenses Actual YTD, Average YTD( out of all the years , what is my average year), Last Year YTD
I need 3 pieces of Data: Actual YTD | Average YTD | Last Years|
This is what I have so far:
select SUM(Expenses)
,DATEADD(year, datediff(year,0,[Date]), 0)
from table1
group by
DATEADD(year, datediff(year,0,[Date]), 0)
)
Try this:
DECLARE #currentYear int
SELECT #currentYear = DATEPART(year, GETDATE())
SELECT SUM(CASE WHEN DATEPART(year,[date]) = #currentYear
THEN Expenses ELSE 0 END) AS 'Actual YTD',
SUM(Expenses) / COUNT( DISTINCT DATEPART(year,[date])) AS 'Average YTD',
SUM(CASE WHEN DATEPART(year,[date]) = #currentYear -1
THEN Expenses ELSE 0 END) AS 'Last Year YTD'
FROM Table1
SQL Fiddle
Try this
select
AVG(case when
[date]>=DATEADD(year, datediff(year,0,getDate())-1, 0) and
[date]<DATEADD(year, datediff(year,0,getDate()), 0)
then Expenses end)
as average_ytd,
sum(case when
[date]>=DATEADD(year, datediff(year,0,getDate())-1, 0) and
[date]<DATEADD(year, datediff(year,0,getDate()), 0)
then Expenses else 0 end)
as actual_ytd,
sum(case when
[date]>=DATEADD(year, datediff(year,0,getDate())-2, 0) and
[date]<DATEADD(year, datediff(year,0,getDate())-1, 0)
then Expenses else 0 end)
as lat_year_ytd
from
table1

Count by day, count by week, in a grouped select statement

I am trying to count instances of a status by current day and current week, grouped by town.
(The table has just 3 columns: Town, status, status_date)
SELECT
MAX(dbo.Clients.Town) AS Town,
CASE
WHEN MAX(datepart(wk, status_date)) = DATEPART(wk, getdate()) THEN COUNT(Town)
ELSE 0
END AS wkTotal,
CASE
WHEN MAX(CONVERT(date, status_date, 106)) = CONVERT(date, getdate(), 106) THEN COUNT(Town)
ELSE 0
END AS dayTotal
FROM
dbo.Clients
WHERE
dbo.Clients.Status LIKE 'Status 1%'
AND MONTH(GETDATE()) = MONTH(dbo.Clients.Status_date)
AND YEAR(GETDATE())= YEAR(dbo.Clients.Status_date)
GROUP BY
dbo.Clients.Town
ORDER BY
dbo.Clients.Town
This code just returns a month count for both day total and week total columns
Hope you can help.
I surgest you do this:
SELECT dbo.Clients.Town AS Town,
count(*) AS wkTotal,
sum(CASE WHEN datepart(dayofyear, status_date) = DATEPART(dayofyear, getdate()) THEN 1 ELSE 0 END) AS dayTotal
FROM dbo.Clients
WHERE dbo.Clients.Status LIKE 'Status 1%' AND
datepart(week, GETDATE()) = datepart(week, dbo.Clients.Status_date)
AND YEAR(GETDATE())= YEAR(dbo.Clients.Status_date)
GROUP BY dbo.Clients.Town
ORDER BY dbo.Clients.Town