SQL select between two dates - sql

Hi i looking for a query that get records between two dates
Start-date should be OrderDate + 28 days
End-date should be result of Start-date + 4 days
Select query
SELECT dbo.Orders.*, dbo.Customer.* FROM dbo.Orders INNER JOIN dbo.Customer ON dbo.Orders.Cust_ID = dbo.Customer.Cust_ID

using DATEADD() fundtion
SELECT dbo.Orders.*, dbo.Customer.*
FROM dbo.Orders INNER JOIN dbo.Customer ON dbo.Orders.Cust_ID = dbo.Customer.Cust_ID
WHERE [Start-date] DATEADD(day,28,OrderDate) AND [End-date] = DATEADD(day,4,[Start-date])

Related

Duplicate records while retrieving using inner join in SQL Server

I am facing issues as I get records from SQL. The output of records was not right and numbers returned are much bigger than what I expected it to be.
Here is my query:
var query=
$#"select CAST(CustomerAssignedTaskExec.ScheduledDispatchedDateTime as DATE) as 'Date',
CustomerTaskDetails.CustomerTaskTypeId, COUNT(*) as 'Count' from CustomerAssignedTaskExec
inner join CustomerAssignedTask on CustomerAssignedTask.Id = CustomerAssignedTaskExec.CustomerAssignedTaskId
inner join CustomerTaskDetails on CustomerTaskDetails.Id = CustomerAssignedTaskExec.CustomerTaskDetailsId
inner join CustomerAssignedTaskItemStatus on CustomerAssignedTaskItemStatus.Id =
CustomerAssignedTaskExec.AssignedTaskItemStatusId
inner join customers on customers.CustomerId = CustomerAssignedTask.CustomerId
where Customers.StoreId = #storeId and CustomerAssignedTask.TaskStatusId = #runningTaskStatusId
group by CAST(CustomerAssignedTaskExec.ScheduledDispatchedDateTime AS DATE),
CustomerTaskTypeId, CustomerAssignedTaskItemStatus.Id";
This is my expected result :
Count CustomerTaskTypeId ScheduledDispatchedDateTime
852 7 2019-08-20
but what I get is :
Count CustomerTaskTypeId ScheduledDispatchedDateTime
4694 7 2019-08-20
What are the reasons why this is happening? Thank you for the help.
You may try this. You may use 1 instead of *, it will count only the distinct rows created by your group by clause.
var query= $#"select CAST(CustomerAssignedTaskExec.ScheduledDispatchedDateTime as DATE) as 'Date',
CustomerTaskDetails.CustomerTaskTypeId, COUNT(1) as 'Count'
from CustomerAssignedTaskExec
inner join CustomerAssignedTask on CustomerAssignedTask.Id = CustomerAssignedTaskExec.CustomerAssignedTaskId
inner join CustomerTaskDetails on CustomerTaskDetails.Id = CustomerAssignedTaskExec.CustomerTaskDetailsId
inner join CustomerAssignedTaskItemStatus on CustomerAssignedTaskItemStatus.Id = CustomerAssignedTaskExec.AssignedTaskItemStatusId
inner join customers on customers.CustomerId = CustomerAssignedTask.CustomerId
where Customers.StoreId = #storeId and CustomerAssignedTask.TaskStatusId = #runningTaskStatusId
group by CAST(CustomerAssignedTaskExec.ScheduledDispatchedDateTime AS DATE), CustomerTaskTypeId, CustomerAssignedTaskItemStatus.Id";
try remove your CustomerAssignedTaskItemStatus.Id and CustomerTaskTypeId in your grouping and give me the results.
select CAST(CustomerAssignedTaskExec.ScheduledDispatchedDateTime as DATE) as 'Date',
COUNT(1) as 'Count'
from CustomerAssignedTaskExec
inner join CustomerAssignedTask on CustomerAssignedTask.Id = CustomerAssignedTaskExec.CustomerAssignedTaskId
inner join CustomerTaskDetails on CustomerTaskDetails.Id = CustomerAssignedTaskExec.CustomerTaskDetailsId
inner join CustomerAssignedTaskItemStatus on CustomerAssignedTaskItemStatus.Id = CustomerAssignedTaskExec.AssignedTaskItemStatusId
inner join customers on customers.CustomerId = CustomerAssignedTask.CustomerId
where Customers.StoreId = #storeId and CustomerAssignedTask.TaskStatusId = #runningTaskStatusId
group by CAST(CustomerAssignedTaskExec.ScheduledDispatchedDateTime AS DATE)
Try to use count(distinct <value>) instead of count(*) maybe that could help as there might be other columns associated leading to redundant data

SQL - Tracking Monthly Sales

I am writing a query to summarize sales by month. My problem is that my query only returns records for months with sales. For example, I am looking over a 15 month range. But for one specific part in the example below only 3 of the 15 months had sales.
I'm hoping to have 15 records show up and the other ones have 0's for sales. The reason I am hoping for the additional records is I want to take the standard deviation of this, and dropping records impacts that calculation.
Sample Code:
SELECT I.PartNumber as PartNumber,
YEAR(O.CreateDate) as CreateDateYear,
MONTH(O.CreateDate) as CreateDateMonth,
COUNT(*) as TotalDemand
FROM OrderDetails OD
INNER JOIN Orders O on O.Id = OD.OrderId
INNER JOIN Items I on I.Id = OD.ItemId
WHERE
O.CreateDate >= '1-1-2016'
AND O.CreateDate <= '3-31-2017'
AND I.PartNumber = '5144831-2'
GROUP BY I.PartNumber, YEAR(O.CreateDate) , MONTH(O.CreateDate);
Sample Current Output:
Part # | Year | Month | Demand
5144831-2 2017 1 1
5144831-2 2017 2 3
5144831-2 2016 3 1
Desired Output:
I would want an additional row such as:
5144831-2 2016 11 0
To show there were no sales in Nov 2016.
I do have a temp table #_date_array2 with the possible months/years, I think I need help incorporating a LEFT JOIN.
If you want to use left join, you would not be able to use it directly with the inner join. You can do the inner join inside the parenthesis and then do the left join outside to avoid messing with the results of left join. Try this:
SELECT Z.PartNumber as PartNumber,
YEAR(O.CreateDate) as CreateDateYear,
MONTH(O.CreateDate) as CreateDateMonth,
COUNT(Z.OrderId) as TotalDemand
FROM Orders O
LEFT JOIN
(
SELECT OrderId, PartNumber
FROM
OrderDetails OD
INNER JOIN Items I ON I.Id = OD.ItemId
AND I.PartNumber = '5144831-2'
) Z
ON O.Id = Z.OrderId
AND O.CreateDate >= '1-1-2016'
AND O.CreateDate <= '3-31-2017'
GROUP BY Z.PartNumber, YEAR(O.CreateDate) , MONTH(O.CreateDate);
To get a count of 0 for months with no order, avoid using count(*) and use count(OrderId) as given above.
Note - You will have to make sure the Orders table has all months and years available i.e. if there is no CreateDate value of, say, November 2016 in the Orders table(left table in the join), the output will also not produce this month's entry.
Edit:
Can you try this:
SELECT Z.PartNumber as PartNumber,
YEAR(O.CreateDate) as CreateDateYear,
MONTH(O.CreateDate) as CreateDateMonth,
COUNT(O.OrderId) as TotalDemand
FROM Orders O
RIGHT JOIN
(
SELECT OrderId, PartNumber
FROM
OrderDetails OD
INNER JOIN Items I ON I.Id = OD.ItemId
AND I.PartNumber = '5144831-2'
) Z
ON O.Id = Z.OrderId
AND O.CreateDate >= '1-1-2016'
AND O.CreateDate <= '3-31-2017'
GROUP BY Z.PartNumber, YEAR(O.CreateDate) , MONTH(O.CreateDate);
Assuming you have sales of something in every month, the simplest solution is to switch to conditional aggregation:
SELECT '5144831-2' as PartNumber,
YEAR(O.CreateDate) as CreateDateYear,
MONTH(O.CreateDate) as CreateDateMonth,
SUM(CASE WHEN I.PartNumber = '5144831-2' THEN 1 ELSE 0 END) as TotalDemand
FROM OrderDetails OD INNER JOIN
Orders O
ON O.Id = OD.OrderId INNER JOIN
Items I
ON I.Id = OD.ItemId
WHERE O.CreateDate >= '2016-01-01' AND
O.CreateDate <= '2017-03-31'
GROUP BY YEAR(O.CreateDate) , MONTH(O.CreateDate);
Note: This is something of a hack for solving the problem. More robust solutions involve generating the dates and using LEFT JOIN (or similar functionality). However, this is often the fastest way to get the result.
based on all of your comments on other posts etc it seems like you have a table that has a date range you want and you want to be able to run the analysis for multiple/all of the part numbers. So the main issue is you will need a cartesian join between your date table and partnumbers that were sold during that time in order to accomplish you "0"s when not sold.
;WITH cteMaxMinDates AS (
SELECT
MinDate = MIN(DATEFROMPARTS(CreateDateYear,CreateDateMonth,1))
,MaxDate = MAX(DATEFROMPARTS(CreateDateYear,CreateDateMonth,1))
FROM
#_date_array2
)
;WITH cteOrderDetails AS (
SELECT
d.CreateDateYear
,d.CreateDateMonth
,I.PartNumber
FROM
#_date_array2 d
INNER JOIN Orders o
ON d.CreateDateMonth = MONTH(o.CreateDate)
AND d.CreateDateYear = YEAR(o.CreateDate)
INNER JOIN OrderDetails od
ON o.Id = od.OrderId
INNER JOIN Items i
ON od.ItemId = i.Id
AND i.PartNumber = '5144831-2'
)
, cteDistinctParts AS (
SELECT DISTINCT PartNumber
FROM
cteOrderDetails
)
SELECT
d.CreateDateYear
,d.CreateDateMonth
,I.PartNumber
,COUNT(od.PartNumber) as TotalDemand
FROM
#_date_array2 d
CROSS JOIN cteDistinctParts p
LEFT JOIN cteOrderDetails od
ON d.CreateDateYear = od.CreateDateYear
AND d.CreateDateMonth = od.CreateDateMonth
AND p.PartNumber = od.PartNumber
GROUP BY
d.CreateDateYear
,d.CreateDateMonth
,I.PartNumber
To get ALL part numbers simply remove AND i.PartNumber = '5144831-2' join condition.

Getting average difference between two dates in minutes

I am trying to get avg receiving time in minutes for each outlet.
I have tow tables Orders and ReceivedOrders.
Orders
OrderID OutletID OrderDate
1 1 2017-04-10 17:04:41.000
ReceivedOrders
ReceivingID OrderID ReceivingDate
1 1 2017-04-10 17:06:31.000
i have tried the below query but its reruns zero as avg receiving time
SQL Query
SELECT Outlets.OutletName , avg(datediff(MM, Orders.OrderDate, ReceivedOrders.ReceivingDate)) as Receive
FROM dbo.Orders INNER JOIN
dbo.Outlets ON dbo.Orders.OutletID = dbo.Outlets.OutletID INNER JOIN
dbo.ReceivedOrders ON dbo.Orders.OrderID = dbo.ReceivedOrders.OrderID
group by dbo.Outlets.OutletName
Output
OutletName Receive
Outlet1 0
Use datediff with millisecond option:
select Outlets.OutletName,
avg(datediff(ms, Orders.OrderDate, ReceivedOrders.ReceivingDate)) / 60000 as Receive
from dbo.Orders
inner join dbo.Outlets on dbo.Orders.OutletID = dbo.Outlets.OutletID
inner join dbo.ReceivedOrders on dbo.Orders.OrderID = dbo.ReceivedOrders.OrderID
group by dbo.Outlets.OutletName
Your code is doing exactly what you are specifying. You are getting the date diff in months, not minutes.
When using date parts, just spell out the full name of the date part:
SELECT ol.OutletName,
avg(datediff(minute, o.OrderDate, ro.ReceivingDate)) as Receive
FROM dbo.Orders o INNER JOIN
dbo.Outlets ol
ON o.OutletID = ol.OutletID INNER JOIN
dbo.ReceivedOrders ro
ONo.OrderID = ro.OrderID
GROUP BY ol.OutletName;
The above counts minute boundaries between two values. You may want parts of minutes, in which case I would use a smaller unit. Milliseconds are definitely an option, but they can overflow pretty easily if the dates are even a few months apart. So, you might really want something more like this:
SELECT ol.OutletName,
avg(datediff(second, o.OrderDate, ro.ReceivingDate)/60.0) as minutesToReceive
FROM dbo.Orders o INNER JOIN
dbo.Outlets ol
ON o.OutletID = ol.OutletID INNER JOIN
dbo.ReceivedOrders ro
ONo.OrderID = ro.OrderID
GROUP BY ol.OutletName;
Note the use of 60.0 rather than 60 to force non-integer arithmetic.

sql select records between today date plus 16 hours

I am trying to get the records between today order date plus 16 hours.
OrderDate data type is datetime
i have records in database between that period but is not showing using the below query.
For example i have the below records.
2017-03-05 10:20:30.000
2017-03-06 10:20:30.000
query should return the second record.
any suggestions to solve this issue?
SQL Query
SELECT
dbo.Areas.AreaName,
dbo.Brands.BrandName,
dbo.Orders.OrderID,
dbo.Orders.OrderStatus,
dbo.Customers.CustomerName,
dbo.Customers.CustomerID,
dbo.Customers.Phone,
dbo.Customers.Mobile,
dbo.Orders.OrderDate,
dbo.Outlets.OutletName,
dbo.Users.FirstName,
dbo.Users.LastName,
dbo.Sources.SourceName,
SUM((OrderDetails.Quantity * OrderDetails.UnitPrice)) + Orders.DeliveryCharge - ((SUM((OrderDetails.Quantity * OrderDetails.UnitPrice)) + Orders.DeliveryCharge) * Orders.Discount / 100) AS Amount,
ReceivedOrders.ReceivingDate
FROM dbo.Orders
INNER JOIN dbo.Customers
ON dbo.Orders.CustomerID = dbo.Customers.CustomerID
INNER JOIN dbo.Outlets
ON dbo.Orders.OutletID = dbo.Outlets.OutletID
INNER JOIN dbo.Users
ON dbo.Orders.UserID = dbo.Users.UserID
INNER JOIN dbo.Sources
ON dbo.Orders.SourceID = dbo.Sources.SourceID
INNER JOIN dbo.OrderDetails
ON dbo.OrderDetails.OrderID = dbo.Orders.OrderID
INNER JOIN dbo.Brands
ON dbo.Brands.BrandID = dbo.Outlets.BrandID
INNER JOIN dbo.Areas
ON dbo.Areas.AreaID = dbo.Customers.AreaID
LEFT JOIN dbo.ReceivedOrders
ON dbo.ReceivedOrders.OrderID = dbo.Orders.OrderID
WHERE BETWEEN OrderDate AND DATEADD(HOUR, 16, OrderDate) and OrderDate=GETDATE()
GROUP BY dbo.Orders.OrderID,
dbo.Orders.OrderStatus,
dbo.Customers.CustomerName,
dbo.Customers.CustomerID,
dbo.Customers.Phone,
dbo.Customers.Mobile,
dbo.Orders.OrderDate,
dbo.Outlets.OutletName,
dbo.Users.FirstName,
dbo.Users.LastName,
dbo.Sources.SourceName,
dbo.Orders.DeliveryCharge,
Orders.Discount,
dbo.Brands.BrandName,
dbo.Areas.AreaName,
ReceivedOrders.ReceivingDate
ORDER BY dbo.Orders.OrderID
Try this:
GETDATE() BETWEEN Orders.OrderDate AND DATEADD(HOUR, 16, Orders.OrderDate)
use this to get today's date instead of just getdate() which returns present time
select cast(cast(getdate() as varchar(12)) as datetime)
You can use CONVERT(VARCHAR(8),GETDATE(),112) instead of GETDATE() this will remove current time and convert the date to varchar with ISO format yyyyMMdd which doesn't need to be converted to datetime again
WHERE OrderDate BETWEEN CONVERT(VARCHAR(8),GETDATE(),112) AND DATEADD(HOUR, 16,CONVERT(VARCHAR(8),GETDATE(),112) )
Read more about sql date formats Here

Query to get the customers active in Aug month and inactive in Sep month in SQL

Please help me to find the customers who were active in the month of aug 15 (in terms of transaction ) and inactive in SEP 15.
The query is taking more than 45 min ..Kindly help ..
SELECT DISTINCT C.CustomerCode--,x.CustomerCode
FROM Customer.Customer(nolock) c
INNER JOIN Customer.Card (nolock)cd ON c.CustomerId=cd.CustomerId
INNER JOIN Trans.vwValidRawTransactions rt (nolock) ON rt.AccountNumber=cd.CardNumber AND rt.AccountTypeId=3
where c.CustomerCode not in (
SELECT DISTINCT ca.customercode
FROM Customer.customer Ca (nolock)
INNER JOIN Customer.Card cd (nolock) ON ca.CustomerId=cd.CustomerId
INNER JOIN trans.vwValidRawTransactions ra (nolock) ON cd.CardNumber=ra.AccountNumber AND ra.AccountTypeId=3 AND ra.IsLive=1
WHERE Ra.TransactionDate>='01-09-2015' AND Ra.TransactionDate <'01-10-2015' )
and rt.TransactionDate>='01-08-2015' and rt.TransactionDate<'01-09-2015'
Try using between,
SELECT DISTINCT C.CustomerCode,
x.CustomerCode
FROM Customer.Customer(NOLOCK) c
INNER JOIN Customer.Card (NOLOCK)cd
ON c.CustomerId = cd.CustomerId
INNER JOIN Trans.vwValidRawTransactions rt(NOLOCK)
ON rt.AccountNumber = cd.CardNumber
AND rt.AccountTypeId = 3
WHERE c.CustomerCode NOT
IN (SELECT DISTINCT ca.customercode
FROM Customer.customer Ca(NOLOCK)
INNER JOIN Customer.Card cd(NOLOCK)
ON ca.CustomerId = cd.CustomerId
INNER JOIN trans.vwValidRawTransactions ra(NOLOCK)
ON cd.CardNumber = ra.AccountNumber
AND ra.AccountTypeId = 3
AND ra.IsLive = 1
WHERE Ra.TransactionDate BETWEEN '01-09-2015' AND '01-10-2015')
AND rt.TransactionDate BETWEEN '01-08-2015' AND '01-09-2015'
Your question is a bit unclear because your query is way more complicated than what the question asks.
If you are looking at the transaction table, you can do what you want using aggregation and a having clause:
SELECT rt.AccountNumber
FROM Trans.vwValidRawTransactions rt (nolock)
WHERE rt.AccountTypeId = 3 AND
rt.TransactionDate >= '2015-08-01' AND
rt.TransactionDate < '2015-10-01'
GROUP BY rt.AccountNumber
HAVING MONTH(MAX(rt.TransactionDate)) = 8;
That is, take transactions from the two months. Then choose customers where the month of the maximum date is august. These customers have transactions in August, but not September.
Note the use of ISO standard date formats. You should use standard date formats in SQL code.
I'm not sure what the rest of your query is supposed to be doing.
Try this
SELECT DISTINCT C.CustomerCode--,x.CustomerCode
FROM Customer.Customer(nolock) c
INNER JOIN Customer.Card (nolock)cd ON c.CustomerId=cd.CustomerId
INNER JOIN Trans.vwValidRawTransactions rt (nolock)
ON rt.AccountNumber=cd.CardNumber AND rt.AccountTypeId=3 AND
((rt.IsLive =1 and rt.TransactionDate BETWEEN '01-08-2015' AND '01-09-2015')
or (rt.IsLive !=1 and rt.TransactionDate BETWEEN '01-09-2015' AND '01-10-2015'))