SQL - AVG Output is incorrect - sql

In below query, I am calculating the lead time between two different dates and eventually trying to get the average of that lead time but the output is incorrect.
SELECT
Round(AVG(CAST(
Case when CONVERT(datetime, ORDERDATE, 105) = CONVERT(datetime, INVOUTDATE, 105) THEN 0 else
Case when CONVERT(datetime, ORDERDATE, 105) + 1 = CONVERT(datetime, INVOUTDATE, 105) THEN 1 else
(DATEDIFF(dd, CONVERT(datetime, ORDERDATE, 105), CONVERT(datetime, INVOUTDATE, 105)))
-(DATEDIFF(wk, CONVERT(datetime, ORDERDATE, 105), CONVERT(datetime, INVOUTDATE, 105))*1)
-(CASE WHEN DATENAME(dw, CONVERT(datetime, ORDERDATE, 105)) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, CONVERT(datetime, INVOUTDATE, 105)) = 'Sunday' THEN 0 ELSE 0 END) end end AS FLOAT)),4) AS LEADTIME FROM DSORDERSTATUS
WHERE ORDERTYPE <> 'Exchange Order'
AND CONVERT(datetime, ORDERDATE, 105) between '20170801' and '20170831'
AND CONVERT(datetime, INVOUTDATE, 105) IS NOT NULL
To troubleshoot the above query I extract the data by using the same query below and when I manually calculate the lead time and average it was correct.
Don't know where is the issue? can someone please tell me whether anything wrong with my query.
Please click on the link to refer sample data Link
SELECT DISTINCT DOCKETNO,
Case when CONVERT(datetime, ORDERDATE, 105) = CONVERT(datetime, INVOUTDATE, 105) THEN 0 else
Case when CONVERT(datetime, ORDERDATE, 105) + 1 = CONVERT(datetime, INVOUTDATE, 105) THEN 1 else
(DATEDIFF(dd, CONVERT(datetime, ORDERDATE, 105), CONVERT(datetime, INVOUTDATE, 105)))
-(DATEDIFF(wk, CONVERT(datetime, ORDERDATE, 105), CONVERT(datetime, INVOUTDATE, 105))*1)
-(CASE WHEN DATENAME(dw, CONVERT(datetime, ORDERDATE, 105)) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, CONVERT(datetime, INVOUTDATE, 105)) = 'Sunday' THEN 0 ELSE 0 END) end end AS LEADTIME FROM DSORDERSTATUS
WHERE ORDERTYPE <> 'Exchange Order'
AND CONVERT(datetime, ORDERDATE, 105) between '20170801' and '20170831'
AND CONVERT(datetime, INVOUTDATE, 105) IS NOT NULL

ok, now I understand..
I think you have to group by orders before to calculate avg
;with
S AS (
select DOCKETNO, ORDERDATE, INVOUTDATE, COUNT(*) n
from DSORDERSTATUS where ORDERTYPE <> 'Exchange Order'
group by DOCKETNO, ORDERDATE, INVOUTDATE
),
D as (
select [DOCKETNO], [ORDERDATE], [INVOUTDATE],
DATEDIFF(dd, CONVERT(date, [ORDERDATE], 105), CONVERT(date, [INVOUTDATE], 105)) dd,
DATEDIFF(wk, CONVERT(date, [ORDERDATE], 105), CONVERT(date, [INVOUTDATE], 105)) wk,
CASE WHEN DATEPART(dw, CONVERT(datetime, ORDERDATE, 105)) = 7 THEN 1 ELSE 0 END IsSundayOrd,
CASE WHEN DATEPART(dw, CONVERT(datetime, INVOUTDATE, 105)) = 7 THEN 1 ELSE 0 END IsSundayInv
from S
)
select avg(cast(dd - case when dd>1 then (wk + IsSundayOrd + IsSundayInv) else 0 end as float)) leadtime
from D
where CONVERT(date, ORDERDATE, 105) between '20170801' and '20170831'
AND CONVERT(date, INVOUTDATE, 105) IS NOT NULL

I will try to convert your dates to DATE instesad of DATETIME I think you are filtering too much rows because '20170831' is '2017-08-31 00:00:00' and you are loosing all ORDERDATE between '00:00:00' and '23:59:59' (for '2017-08-31')
WHERE ORDERTYPE <> 'Exchange Order'
AND CONVERT(date, ORDERDATE, 105) between '20170801' and '20170831'
AND CONVERT(date, INVOUTDATE, 105) IS NOT NULL

With the help of MtwStark i was able to resolve this.
I have modified his query,
Thanks buddy
;with
S AS (
SELECT DISTINCT DOCKETNO,
Case when CONVERT(datetime, ORDERDATE, 105) = CONVERT(datetime, INVOUTDATE, 105) THEN 0 else
Case when CONVERT(datetime, ORDERDATE, 105) + 1 = CONVERT(datetime, INVOUTDATE, 105) THEN 1 else
(DATEDIFF(dd, CONVERT(datetime, ORDERDATE, 105), CONVERT(datetime, INVOUTDATE, 105)))
-(DATEDIFF(wk, CONVERT(datetime, ORDERDATE, 105), CONVERT(datetime, INVOUTDATE, 105))*1)
-(CASE WHEN DATENAME(dw, CONVERT(datetime, ORDERDATE, 105)) = 'Sunday' THEN 1 ELSE 0 END)end end AS LEADTIME FROM DSORDERSTATUS
WHERE ORDERTYPE <> 'Exchange Order'
AND CONVERT(datetime, ORDERDATE, 105) between '20170801' and '20170808'
AND CONVERT(datetime, INVOUTDATE, 105) IS NOT NULL
),
D AS (
SELECT DOCKETNO, LEADTIME FROM S
)
SELECT AVG(CAST(LEADTIME AS FLOAT)) FROM D

Related

T-SQL - Merge two tables without create temp table

The prefer result i want I have those 2 T-SQL queries:
SELECT
CONVERT(NVARCHAR, AL.FECHA, 103) AS [DATE],
CONVERT(NVARCHAR, AL.HORA, 108) AS [HOUR],
SUM(CAST(AL.TOTALNETO AS money)) AS [AMOUNT]
FROM
ALBVENTACAB AL
WHERE
CONVERT(NVARCHAR, AL.FECHA, 103) = '10/09/2020'
-- AND CONVERT(nvarchar, GETDATE(), 103) AND
AND CONVERT(nvarchar, AL.HORA, 108) BETWEEN (SELECT CONVERT(nvarchar, AL.HORA, 108)) AND CONVERT(nvarchar, GETDATE(), 108)
GROUP BY
AL.FECHA, AL.HORA
ORDER BY
AL.FECHA
SELECT
CONVERT(NVARCHAR, AL.FECHA, 103) AS [DATE],
CONVERT(NVARCHAR, AL.HORA, 108) AS [HOUR],
SUM(CAST(AL.TOTALNETO AS money)) AS [AMOUNT]
FROM
ALBVENTACAB AL
WHERE
FECHA = CAST(DATEADD(DD, -7, GETDATE()) AS date)
AND CONVERT(nvarchar, AL.HORA, 108) BETWEEN (SELECT CONVERT(nvarchar, AL.HORA, 108)) AND CONVERT(nvarchar, GETDATE(), 108)
GROUP BY
AL.FECHA, AL.HORA
ORDER BY
AL.FECHA
Individually, their results are correct. I want to create a result as shown in the screenshot.
I tried to create a CTE, but that didn't work. What is the proper way?
Thank you!
First, the query I think you're looking for is something like this. The Friday date (#fecha) was removed to a variable of type DATE. Instead of 2 query, 1 for the week, and 1 for the particular Friday, it's now 1 query. The friday sales are broken out using conditional aggregation into a new column called [FECHA_AMOUNT]. Note: this only works if the variable #fecha falls within the last 7 days.
declare #fecha date='20201009';
SELECT
CONVERT(NVARCHAR, AL.FECHA, 103) AS [DATE],
CONVERT(NVARCHAR, AL.HORA, 108) AS [HOUR],
SUM(CAST(AL.TOTALNETO AS money)) AS [AMOUNT],
SUM(case when cast(AL.FECHA as date)=#fecha then CAST(AL.TOTALNETO AS money)
else cast(0 as money) end) AS [FECHA_AMOUNT]
FROM
ALBVENTACAB AL
WHERE
FECHA = CAST(DATEADD(DD, -7, GETDATE()) AS date)
AND CONVERT(nvarchar, AL.HORA, 108) BETWEEN (SELECT CONVERT(nvarchar, AL.HORA, 108))
AND CONVERT(nvarchar, GETDATE(), 108)
GROUP BY
AL.FECHA, AL.HORA
ORDER BY
AL.FECHA;
Finally, as note in the comments. When converting it's always good to use lengths. Also, the money data type is not considered ideal. Fwiw

Why Week conversion failed in SQL Server in my case?

I am trying to convert week of the date based on my criteria.
My date condition: if my #date is less than 4 AM, then #date - 1, else #date
declare #dates datetime
set #dates = '2019-01-01 03:59:59'
select
case
when convert(varchar(26), #dates, 108) <= '04:00:00'
then convert(varchar, dateadd(day, -1, #dates), 103)
else convert(varchar, #dates, 103)
end BusinessDate
Output:
31/12/2018 // as expected
Now I want to find the week number of the output. So I tried
declare #dates datetime
set #dates = '2019-01-01 03:59:59'
select
case
when convert(varchar(26), #dates, 108) <= '04:00:00'
then convert(varchar, dateadd(day, -1, #dates), 103)
else convert(varchar, #dates, 103)
end BusinessDate,
case
when convert(varchar(26), #dates, 108) <= '04:00:00'
then datepart(week, convert(datetime, convert(varchar, dateadd(day, -1, #dates), 103)))
else datepart(week, convert(datetime, convert(varchar, #dates, 103)))
end weeks
But I get this error:
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
Just subtract four hours:
select datepart(week,
dateadd(hour, -4, #dates)
)

Dropping rows from the report based on commission date

I need to drop rows (not show) from the report based on commission date completion.
SELECT
proj.ProjectNumber AS [Project],
proj.UserText4 AS [Sales Rep],
bc.Name AS [Customer Name],
proj.Address3 AS [Shiped to],
proj.City,
proj.State,
v_InvDet.InvoiceNumber AS [Invoice],
CASE WHEN CAST(v_InvDet.InvoiceDate as Date) = '01/01/1900'
then NULL else convert(varchar(10), v_InvDet.InvoiceDate, 101)
END AS [Invoice Date],
CASE WHEN CAST(proj.UserDate4 as Date) ='01/01/1900'
then NULL else convert(varchar(10), proj.UserDate4, 101)
END AS [Install Date],
--CASE WHEN CONVERT(DATE, proj.UserDate4) = '1900-01-01'
--THEN NULL
--ELSE CONVERT(CHAR(10), proj.UserDate4, 120)
--+ ' ' + CONVERT(CHAR(8), proj.UserDate4, 108)
--END AS [Install Date],
--case WHEN CONVERT(CHAR(10), proj.UserDate4, 120) > DATEADD( d, -30, GETDATE() )
--THEN proj.UserDate4
--END AS [Install Date],
case WHEN CONVERT(DATE, proj.UserDate4) = '1900-01-01'
THEN NULL
ELSE DATEDIFF(d, CURRENT_TIMESTAMP, proj.UserDate4)*-1
END AS [Open Days],
IIF(proj.UserText9 = 'TRUE', 'YES', 'NO') AS [HVLS Fans],
IIF(proj.UserText18 = 'TRUE', 'YES', 'NO') AS [Restrains],
IIF(proj.UserText23 = 'TRUE', 'YES', 'NO') AS [Docks],
IIF(proj.SitePM = 'TRUE', 'YES', 'NO') AS [Doors],
IIF(proj.ProjectURL = 'TRUE', 'YES', 'NO') AS [Lifts],
proj.UserText2 AS [Commission Equip],
CASE WHEN CAST(proj.Userdate5 as Date) > DATEADD( d, -14, GETDATE() )
then NULL
else convert(varchar(10), proj.Userdate5, 101)
END AS [Commission Date2],
/* Converting 01/01/1900 to NULL so it will show no date on report*/
CASE WHEN CAST(proj.Userdate5 as Date) = '01/01/1900' then NULL else convert(varchar(10), proj.Userdate5, 101)
END AS [Commission Date],
--case WHEN CAST(proj.Userdate5 as Date) = '01/01/1900' > DATEADD( d, -14, GETDATE() )
--THEN proj.UserDate5
--END AS [Commission Date1],
--proj.Userdate5 = DATEADD(d, 14, CURRENT_TIMESTAMP ),
--proj.Userdate5 as [Commission Date],
proj.UserText3 AS [Commission By]
FROM Project proj
LEFT JOIN v_InvoiceDetail As v_InvDet (nolock) ON proj.ProjectNumber = v_InvDet.ProjectNumber
LEFT JOIN Company AS bc (nolock) ON bc.CompanyID = proj.BillingCompanyID
WHERE
proj.Userdate5 >= DATEADD(d, -14, CURRENT_TIMESTAMP)
--proj.Userdate5 >= DATEADD(d, -14, CONVERT(datetime,(convert(varchar(12),proj.Userdate5, 101)))) --getdate())-14
--proj.Userdate4 between '2018-01-01' and CURRENT_TIMESTAMP
--v_InvDet.InvoiceDate between '2018-01-01' and CURRENT_TIMESTAMP
--v_InvDet.InvoiceDate >= DATEDIFF(d, proj.UserDate4, getdate())
--v_InvDet.InvoiceDate >= DATEADD( d, -140, GETDATE() )
ORDER BY proj.UserText4
I am using a "where" close to filter. Is that a way to do it? Thank you
Just wrap your query with another query so that your actual query will be inner query then put your condition.
See This:
select * from (
SELECT
proj.ProjectNumber AS [Project],
proj.UserText4 AS [Sales Rep],
bc.Name AS [Customer Name],
proj.Address3 AS [Shiped to],
proj.City,
proj.State,
v_InvDet.InvoiceNumber AS [Invoice],
CASE WHEN CAST(v_InvDet.InvoiceDate as Date) = '01/01/1900'
then NULL else convert(varchar(10), v_InvDet.InvoiceDate, 101)
END AS [Invoice Date],
CASE WHEN CAST(proj.UserDate4 as Date) ='01/01/1900'
then NULL else convert(varchar(10), proj.UserDate4, 101)
END AS [Install Date],
--CASE WHEN CONVERT(DATE, proj.UserDate4) = '1900-01-01'
--THEN NULL
--ELSE CONVERT(CHAR(10), proj.UserDate4, 120)
--+ ' ' + CONVERT(CHAR(8), proj.UserDate4, 108)
--END AS [Install Date],
--case WHEN CONVERT(CHAR(10), proj.UserDate4, 120) > DATEADD( d, -30, GETDATE() )
--THEN proj.UserDate4
--END AS [Install Date],
case WHEN CONVERT(DATE, proj.UserDate4) = '1900-01-01'
THEN NULL
ELSE DATEDIFF(d, CURRENT_TIMESTAMP, proj.UserDate4)*-1
END AS [Open Days],
IIF(proj.UserText9 = 'TRUE', 'YES', 'NO') AS [HVLS Fans],
IIF(proj.UserText18 = 'TRUE', 'YES', 'NO') AS [Restrains],
IIF(proj.UserText23 = 'TRUE', 'YES', 'NO') AS [Docks],
IIF(proj.SitePM = 'TRUE', 'YES', 'NO') AS [Doors],
IIF(proj.ProjectURL = 'TRUE', 'YES', 'NO') AS [Lifts],
proj.UserText2 AS [Commission Equip],
CASE WHEN CAST(proj.Userdate5 as Date) > DATEADD( d, -14, GETDATE() )
then NULL
else convert(varchar(10), proj.Userdate5, 101)
END AS [Commission Date2],
/* Converting 01/01/1900 to NULL so it will show no date on report*/
CASE WHEN CAST(proj.Userdate5 as Date) = '01/01/1900' then NULL else convert(varchar(10), proj.Userdate5, 101)
END AS [Commission Date],
--case WHEN CAST(proj.Userdate5 as Date) = '01/01/1900' > DATEADD( d, -14, GETDATE() )
--THEN proj.UserDate5
--END AS [Commission Date1],
--proj.Userdate5 = DATEADD(d, 14, CURRENT_TIMESTAMP ),
--proj.Userdate5 as [Commission Date],
proj.UserText3 AS [Commission By]
FROM Project proj
LEFT JOIN v_InvoiceDetail As v_InvDet (nolock) ON proj.ProjectNumber = v_InvDet.ProjectNumber
LEFT JOIN Company AS bc (nolock) ON bc.CompanyID = proj.BillingCompanyID
WHERE
proj.Userdate5 >= DATEADD(d, -14, CURRENT_TIMESTAMP)
--proj.Userdate5 >= DATEADD(d, -14, CONVERT(datetime,(convert(varchar(12),proj.Userdate5, 101)))) --getdate())-14
--proj.Userdate4 between '2018-01-01' and CURRENT_TIMESTAMP
--v_InvDet.InvoiceDate between '2018-01-01' and CURRENT_TIMESTAMP
--v_InvDet.InvoiceDate >= DATEDIFF(d, proj.UserDate4, getdate())
--v_InvDet.InvoiceDate >= DATEADD( d, -140, GETDATE() )
)
where [Commission Date] not in ( ....)
ORDER BY proj.UserText4

How to derive weekdays from query?

How to I get the weekday name after OrderH_dtmInitiated column
SELECT
Convert(char(8), OrderH_dtmInitiated, 112) AS BookingDate,
--(To derived weekdays name from OrderH_dtmInitiated namely weekdays here)
[OrderH_strEmailConfirmationSent], [OrderH_strEmail]
FROM
[VISTAIT].[dbo].[tblOrderHistory]
WHERE
OrderH_strEmailConfirmationSent IS NULL
AND OrderH_dtmInitiated >= (SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()-1)))
ORDER BY
Convert(char(8), OrderH_dtmInitiated, 112)
You could use datename:
SELECT
Convert(char(8), OrderH_dtmInitiated, 112) As BookingDate,
Datename (weekday, OrderH_dtmInitiated) As NameOfDay,
[OrderH_strEmailConfirmationSent]
,[OrderH_strEmail]
FROM [VISTAIT].[dbo].[tblOrderHistory]
WHERE OrderH_strEmailConfirmationSent is NULL And OrderH_dtmInitiated >= (SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()-1)))
ORDER by Convert(char(8), OrderH_dtmInitiated, 112)
SELECT
Convert(char(8), OrderH_dtmInitiated, 112)as datebooking,
Datename (weekday, OrderH_dtmInitiated) As NameOfDay,
count(distinct OrderH_strCinemaId)as cinemassite,
count(distinct OrderH_intID)as TotalBookingMade,
SUM(case when OrderH_strEmailConfirmationSent like 'Y' then 1 else 0 end) as OrderH_strEmailConfirmationSent,
SUM(case when OrderH_strEmailConfirmationSent is NULL then 1 else 0 end) as EmailHavingNull
FROM [VISTAIT].[dbo].[tblOrderHistory]
WHERE OrderH_dtmInitiated >= '2015-05-07'
GROUP BY Convert(char(8), OrderH_dtmInitiated, 112)
ORDER by Convert(char(8), OrderH_dtmInitiated, 112)

SQL Server: better / faster way of combining multiple counts in select

I am using the below stored procedure in order to combine multiple counts.
This works fine so far and returns the following XML, i.e. a count of records for each of the last 6 months.
As I am pretty new to SQL and all these counts are done on the same table I was wondering if there is a better / faster way to achieve the same.
Example result (XML):
<ranks>
<groupCount>18</groupCount>
<groupCount>15</groupCount>
<groupCount>21</groupCount>
<groupCount>13</groupCount>
<groupCount>15</groupCount>
<groupCount>19</groupCount>
</ranks>
My stored procedure:
BEGIN
SET NOCOUNT ON;
SELECT COUNT(*) AS groupCount
FROM Log_PE
WHERE CONVERT(DATE, dateEsc, 120) >= CONVERT(DATE, CONVERT(VARCHAR(6), GETDATE(), 112) + '01', 112)
UNION ALL
SELECT COUNT(*) AS groupCount
FROM Log_PE
WHERE CONVERT(DATE, dateEsc, 120) >= CONVERT(DATE, CONVERT(VARCHAR(6), DATEADD(month, -1, GETDATE()), 112) + '01', 112)
UNION ALL
SELECT COUNT(*) AS groupCount
FROM Log_PE
WHERE CONVERT(DATE, dateEsc, 120) >= CONVERT(DATE, CONVERT(VARCHAR(6), DATEADD(month, -2, GETDATE()), 112) + '01', 112)
UNION ALL
SELECT COUNT(*) AS groupCount
FROM Log_PE
WHERE CONVERT(DATE, dateEsc, 120) >= CONVERT(DATE, CONVERT(VARCHAR(6), DATEADD(month, -3, GETDATE()), 112) + '01', 112)
UNION ALL
SELECT COUNT(*) AS groupCount
FROM Log_PE
WHERE CONVERT(DATE, dateEsc, 120) >= CONVERT(DATE, CONVERT(VARCHAR(6), DATEADD(month, -4, GETDATE()), 112) + '01', 112)
UNION ALL
SELECT COUNT(*) AS groupCount
FROM Log_PE
WHERE CONVERT(DATE, dateEsc, 120) >= CONVERT(DATE, CONVERT(VARCHAR(6), DATEADD(month, -5, GETDATE()), 112) + '01', 112)
FOR XML PATH(''), ROOT('ranks')
END
Many thanks for any help with this, Tim.
Your requirements seem to conflict with what you are doing in your SQL
select CONVERT(DATE, CONVERT(VARCHAR(6), GETDATE(), 112) + '01', 112)
will get the first day of the current month
select CONVERT(DATE, CONVERT(VARCHAR(6), GETDATE(), 112) + '02', 112)
will get the second day of the current month
To get the count of the last 6 complete months of records grouped by month
SELECT COUNT(*) AS groupCount
FROM Log_PE
WHERE dateEsc >= CAST(DATEADD(day, 1, DATEADD(month, -6, DATEADD(day, day(GETDATE())*-1, GETDATE()))) as DATE) --the first day of the month, 6 months ago
AND dateEsc < DATEADD(day, (day(GETDATE())*-1)+1, GETDATE()) -- the first day of current month
GROUP BY year(dateEsc), month(dateEsc)
ORDER BY year(dateEsc), month(dateEsc)
FOR XML PATH(''), ROOT('ranks')
Here is a SQL Fiddle: http://www.sqlfiddle.com/#!3/3ff71/7