SQL find the oldest date from a range of dates where attributes repeat from month to month - sql

Need help isolating the oldest date from a table where the following attributes:[process id],[tracking id],[bp] are identical in the previous months.
I run a recon report once a month. Need to identify if records in this month Recon Report appeared in previous months. If the record appeard in a previous report than I need to identify the oldest date an Issue has been opened, so I can identify delinquents. The last time the report ran was 6/31/2020, but the issue has been open for the last three months.
Here are the results that I would I like to see.
Below is they query that I am running.
declare #date datetime
set #date= '6/30/2020'
select
DATEDIFF(d,date, #date) as [Number of days outstanding],
[Business Profile Name],
[Unit],
[Tracking ID],
[Owner],
[Issue]
from
[Recon_Report]
where
concat ([process id],[tracking id],[bp]) in
(
select
(concat ([process id],[tracking id],[bp]))
from
[Recon_Report]
where
date = #date
)
and date < #date
order by [process id],[tracking id],[bp], Date asc
I tried adding this to query:
min(DATEDIFF(d,date, #date))
But I get an error mesage:
Msg 8120, Level 16, State 1, Line 19
Column 'Recon_Report.Date' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

Just use window functions. I think you want:
select DATEDIFF(d,date, #date) as [Number of days outstanding],
rr.*
from (select rr.*,
max(case when date = #date then 1 else 0 end) over (partition by [process id], [tracking id], [bp]) as on_date,
dense_rank() over (partition by [process id], [tracking id], [bp] order by date) as seqnum
from Recon_Report rr
where date <= #date
) rr
where seqnum = 1
order by [process id], [tracking id], [bp], Date asc

Here is a solution that worked for me.
declare #date datetime
set #date= '6/30/2020'
select
DATEDIFF(d,min(date), #date) as [Number of days outstanding],
[Business Profile Name],
[Unit],
[Tracking ID],
[Owner],
[Issue]
from
[Recon_Report]
where
concat ([process id],[tracking id],[bp]) in
(
select
(concat ([process id],[tracking id],[bp]))
from
[Recon_Report]
where
date = #date
)
and date < #date
group by
[Business Profile Name],
[Unit],
[Tracking ID],
[Owner],
[Issue]

Related

SQL query to find last date before and all dates after a condition using CASE statement

• Suppliers having PO date before 01 Jan 21 won’t be considered
• Exception-If all suppliers have PO date before 1 Jan 21, supplier with latest PO date will be considered.
Check the image for reference
SELECT
A.IPN,
A.[Manufacturer/Supplier],
A.[Last PO#],
A.[Last PO Date]
FROM (
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY IPN,[Manufacturer/Supplier]
ORDER BY
(CASE
WHEN [Last PO Date] >= '01/01/2021'
THEN [Last PO Date]
WHEN [Last PO Date] < '01/01/2021'
THEN MAX([Last PO Date])
ELSE NULL
END)
DESC, IPN DESC) AS rn
FROM dbo.Sheet1$
) A
WHERE rn = 1
Can anyone explain?
I used a common table expression (CTE) for selecting records when there are no rows after 2021-01-01, ordering by date.
WITH DATA_CTE AS (
SELECT
A.IPN,
A.[Manufacturer/Supplier],
A.[PO#],
A.[PO Date]
FROM
dbo.Sheet1$ A
WHERE
A.[PO Date] < '2021-01-01'
AND NOT EXISTS(
SELECT B.IPN
FROM dbo.Sheet1$ B
WHERE B.[PO Date] >= '2021-01-01'
)
ORDER BY A.[PO Date] DESC
)
SELECT
A.IPN,
A.[Manufacturer/Supplier],
A.[PO#],
A.[PO Date]
FROM
dbo.Sheet1$
WHERE
A.[Last PO Date] >= '2021-01-01'
UNION
SELECT
TOP 1
A.IPN,
A.[Manufacturer/Supplier],
A.[PO#],
A.[PO Date]
FROM
DATA_CTE

How to select max date over the year function

I am trying to select the max date over the year, but it is not working. Any ideas on what to do?
SELECT a.tkinit [TK ID],
YEAR(a.tkeffdate) [Rate Year],
max(a.tkeffdate) [Max Date],
tkrt03 [Standard Rate]
FROM stageElite.dbo.timerate a
join stageElite.dbo.timekeep b ON b.tkinit = a.tkinit
WHERE a.tkinit = '02672'
and tkeffdate BETWEEN '2014-01-01' and '12-31-2014'
GROUP BY a.tkinit,
tkrt03,
a.tkeffdate
Perhaps you only want it by year and not rolled up by calendar date. For SQL server you can try this.
SELECT
…
MaxDate = MAX(a.tkeffdate) OVER (PARTITION BY a.tkinit, YEAR(a.tkeffdate)))
…
Or you could modify the query above to group by the year instead of date-->
GROUP BY a.tkinit,
tkrt03,
YEAR(a.tkeffdate)
You seem to want only one row and all the columns. Use ORDER BY and TOP:
SELECT TOP (1) tr.tkinit as [TK ID],
YEAR(tr.tkeffdate) as [Rate Year],
a.tkeffdate as [Max Date],
tkrt03 as [Standard Rate]
FROM stageElite.dbo.timerate tr JOIN
stageElite.dbo.timekeep tk
ON tk.tkinit = tr.tkinit
WHERE tr.tkinit = '02672' AND
tr.tkeffdate >= '2014-01-01' AND
tr.tkeffdate < '2015-01-01'
ORDER tr.tkeffdate DESC;
Note that I also fixed your date comparisons and table aliases.

New to SQL. Would like to convert an IF(COUNTIFS()) Excel formula to SQL code and have SQL calculate it instead of Excel

I am running SQL Server 2008 R2 (RTM).
I have a SQL query that pulls Dates, Products, Customers and Units:
select
[Transaction Date] as Date,
[SKU] as Product,
[Customer Name] as Customer,
sum(Qty) as Units
from dataset
where [Transaction Date] < '2019-03-01' and [Transaction Date] >= '2016-01-01'
group by [Transaction Date], [SKU], [Customer Name]
order by [Transaction Date]
This pulls hundreds of thousands of records and I wanted to determine if a certain transaction was a new order or reorder based on the following logic:
Reorder: That specific Customer has ordered that specific product in the last 6 months
New Order: That specific Customer hasn’t ordered that specific product in the last 6 months
For that I have this formula in Excel that seems to be working:
=IF(COUNTIFS(A$1:A1,">="&DATE(YEAR(A2),MONTH(A2)-6,DAY(A2)),C$1:C1,C2,B$1:B1,B2),"Reorder","New Order")
The formula works when I paste it individually or in a smaller dataset, but when I try to copy paste it to all 500K+ rows, Excel gives up because it loops for each calculation.
This could probably be done in SQL, but I don’t have the knowledge on how to convert this excel formula to SQL, I just started studying it.
You're doing pretty well with the start of your query there. There are three additional functions you're looking to add to your query.
The first thing you'll need is the easiest. GETDATE() simply returns the current date. You'll need that when you're comparing the current date to the transaction date.
The second function is DATEDIFF, which will give you a unit of time between two dates (months, days, years, quarters, etc). Using DATEDIFF, you can say "is this date within the last 6 months". The format for this is pretty easy. It's DATEDIFF(interval, date1, date2).
The thrid function you're looking for is CASE, which allows you to tell SQL to give you one answer if one condition is met, but a different answer if a different condition is met. For your example, you can say "if the difference in days is < 60, return 'Reorder', if not give me 'New Order'".
Putting it all together:
SELECT CASE
WHEN DATEDIFF(MONTH, [Transaction Date], GETDATE()) <= 6
THEN 'Reorder'
ELSE 'New Order'
END as ORDER_TYPE
,[Transaction Date] AS DATE
,[SKU] AS PRODUCT
,[Customer Name] AS CUSTOMER
,Qty AS UNITS
FROM DATASET
For additonal examples on CASE, take a look at this site: https://www.w3schools.com/sql/sql_ref_case.asp
For additional examples on DATEDIFF, take a look here: See the
following webpage for examples and a chance to try it out:
https://www.w3schools.com/sql/func_sqlserver_datediff.asp
SELECT CASE
WHEN Datediff(day, [transaction date], Getdate()) <= 180 THEN 'reorder'
ELSE 'Neworder'
END,
[transaction date] AS Date,
[sku] AS Product,
[customer name] AS Customer,
qty AS Units
FROM datase
If I understand correctly, you want to peak at the previous date and make a comparison. This suggests lag():
select (case when lag([Transaction Date]) over (partition by SKU, [Customer Name] order by [Transaction Date]) >
dateadd(month, -6, [Transaction Date])
then 'Reorder'
else 'New Order'
end) as Order_Type
[Transaction Date] as Date,
[SKU] as Product,
[Customer Name] as Customer,
sum(Qty) as Units
from dataset d
group by [Transaction Date], [SKU], [Customer Name];
EDIT:
In SQL Server 2008, you can emulate the LAG() using OUTER APPLY:
select (case when dprev.[Transaction Date] >
dateadd(month, -6, d.[Transaction Date])
then 'Reorder'
else 'New Order'
end) as Order_Type
d.[Transaction Date] as Date,
d.[SKU] as Product,
d.[Customer Name] as Customer,
sum(d.Qty) as Units
from dataset d outer apply
(select top (1) dprev.*
from dataset dprev
where dprev.SKU = d.SKU and
dprev.[Customer Name] = d.[Customer Name] and
dprev.[Transaction Date] < d.[Transaction Date]
order by dprev.[Transaction Date] desc
) dprev
group by d.[Transaction Date], d.[SKU], d.[Customer Name];

SQL Query: 1 Employee Position/Post as 2 results

I have a list of employees in their current post/position with their start date in the position and their employment start date.
I need a query to generate current position as one result and if the start date of the position does not match start date of employment show a historic position as a second result.
Data
[Employee Number] Position [Start Date] [Employment Start Date]
-----------------------------------------------------------------------
12345 Admin 01/01/2017 01/01/2016
Output
[Employee Number] Position [Start Date] [End Date]
-----------------------------------------------------------
12345 Admin 01/01/2017 NULL
12345 Historic 01/01/2016 31/12/2017
SELECT
[Employee Number],
[Position],
[Start Date],
NULL AS [End Date]
FROM
TABLE_NAME
UNION ALL
SELECT
[Employee Number],
'Historic' AS [Position],
[Employment Start Date] AS [Start Date],
DATEADD( DAY,-1,[Start Date] ) AS [End Date]
FROM
TABLE_NAME
WHERE
[Start Date] <> [Employment Start Date]
You can use union all:
select employee_number, position, start_date, cast(null as date) end_date
from data
union all
select employee_number, position, employment_start_date, dateadd(day, -1, start_date)
from data
where employment_start_date < start_date;
WITH table1 AS (
SELECT * FROM (
VALUES
('12345', 'Admin','2017-01-01','2016-01-01')
) AS a (EmployeeNumber, position,StartDate,EmploymentStartDate)
)
select EmployeeNumber, position,StartDate, CASE WHEN StartDate!=EmploymentStartDate THEN NULL ELSE EmploymentStartDate END AS EndDate from table1
union
Select EmployeeNumber,'Historic',EmploymentStartDate as StartDate,DATEADD(dd,-1,DATEADD(yy,1,StartDate)) AS EndDate
From table1 where StartDate!=EmploymentStartDate

Scripting the latest month in the data set [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
In the following view,instead of specifying the actual dates in the where condition,I want sql server to recognize June and May as the latest month and the (latest month-1) as the view gets refreshed on a monthly basis and so does latest month and (latest month -1).
PS:- The latest Report month is June in the table
SELECT (A.[First Name])
,A.[Last Name]
,A.[Report Month]
FROM (
(
SELECT DISTINCT [First Name]
,[Last Name]
,[Report Month]
,[Bill To Code]
,[Region]
,[Area]
FROM dbo.Data
WHERE (
[Report Month] BETWEEN '2015-06-01'
AND '2015-06-30'
AND [FTE Status] = 'Inactive'
)
) A INNER JOIN (
SELECT DISTINCT [First Name]
,[Last Name]
,[Report Month]
,[Bill To Code]
,[Region]
,[Area]
FROM dbo.Data
WHERE (
[Report Month] BETWEEN '2015-05-01'
AND '2015-05-31'
AND [FTE Status] = 'Active'
)
) B ON A.[First Name] = B.[First Name]
AND A.[Last Name] = B.[Last Name]
)
Thank you,just learnt how to format better in SO.Thanks to Sean.Learning from my mistakes guys..:)
Hence i should write some function so that sql server reads the start
and end date of the latest month in the data set.
You say you need to read the start and end date, but if what you really need is just to get all the data that is in the latest month in your table, then this will do it:
select *
from dbo.Data
where DATEDIFF(month,[Report Month],(SELECT MAX([Report Month] FROM dbo.Data))=0
and [FTE Status]='Active'
Despite your rather vague question, I think this is what you are looking for.
This will return the first and last day for the max date in YourTable.
;with cte as (
select convert(date,left(convert(varchar,Max(Report_Month),112),6) + '01') startDate,
month(Max(Report_Month)) n
from YourTable
union all
select dateadd(month,n,convert(date,convert(varchar,year(startDate)) + '0101')) startDate,
(n+1) n
from cte
where n < month(startDate)
)
select startdate, dateadd(day,-1,dateadd(month,1,startdate)) enddate
from cte
How about:
SELECT MAX(MONTH(Report_Month))
FROM YourTable
GROUP BY YEAR(Report_Month)
HAVING YEAR(Report_Month) = MAX(YEAR(Report_Month))