SQL add max and second max date to query that includes with - sql

Posted a question yesterday about SQL append distinct values from two columns and two tables that resulted in the following code:
with cte1 as
(Select Distinct "Tra.".cus_outnum As "account number" from table1 "Tra." Where "Tra.".invdat >= DATEADD(year, -1, GETDATE())
union
Select Distinct "Sal.".outnum As "account number" From table2 "Sal." Where "Sal.".deldat>= DATEADD(year, -1, GETDATE()))
,cte2 as
(Select Distinct "Tra.".artnum As "article number" from tabel1 “Tra.” Where "Tra.".invdat >= DATEADD(year, -1, GETDATE())
union
Select Distinct ISNULL("Sal.".org_artnum, "Sal.".artnum) As "article number" From table2 "Sal." Where "Sal.".deldat>= DATEADD(year, -1, GETDATE()))
Select * from cte1 cross join cte2
It produces a table with all distinct combination of account numbers and article numbers from two different tables where orders are done later than one year ago.
Next object that I'm struggling with is to include the latest and second latest purchase date in two new columns. If no purchase is done for any combination of account and article, it should result in a null(blank) value. And the latest/second latest date (i.e max date) should come from either one or the other of the tables. End result should be along the lines of:
<table><tbody><tr><th>Account</th><th>Article</th><th>Latest Date</th><th>Second to latest Date</th></tr><tr><td>1</td><td>1</td><td>26.06.2018</td><td>13.03.2018</td></tr><tr><td>1</td><td>2</td><td>15.05.2018</td><td>Blank (no purchase)</td></tr><tr><td>2</td><td>1</td><td>23.06.2018</td><td>30.06.2017</td></tr><tr><td>2</td><td>2</td><td>Blank (no purchase)</td><td>Blank (no purchase)</td></tr></tbody></table>
Many thanks for all the help, it is much appreciated!

Partially pseudeo. To get more detailed help please offer a db-fiddle.
SELECT
a.Account as Account,
b.Article as Article,
(<SUBSELECT> MAX(DATE) FROM ... WHERE ... ) as LatestDate,
(<SUBSELECT> MAX(DATE) FROM ... WHERE ... < LatestDate ) as 'SecondToLatestDate')
FROM
accounts a JOIN articles b
+ some IFNULL's

Related

Customers who placed order both in this month and previous month for a list of dates

So I am trying to find count of customers who placed order both in this month and previous month. I have to find this from the beginning of last year. I came up with a query which obviously doesn't work. Can I get some help with this please?
Query:
SELECT DATE_TRUNC('month', month_column), COUNT(DISTINCT(customer_id))
FROM table
WHERE month_column >= '2021-01-01' AND customer_id IN (
SELECT customer_id
FROM table
WHERE month_column = month_column - INTERVAL '1 month')
GROUP BY 1
NOTE: month_column has only month number i.e., '2021-01-01', '2021-02-01' etc.
I am using postgresql.
This is my first stack overflow question. So, if I didn't abide by any rules, I apologize.
To make this trivial, you can use 2 queries. Get customerID's from this month (insert into temp table 1) and customerID's from last month (insert into temp table 2). Lastly just inner join both tables on customerID
something like the below
SELECT customer_id
INTO #thisMonth
FROM customer
WHERE month_column > DATEADD(month, 0, GETDATE())
SELECT customer_id
INTO #prevMonth
FROM customer
WHERE month_column > DATEADD(month, -1, GETDATE())
SELECT COUNT(customer_id)
FROM #thisMonth tm
INNERJOIN #prevMonth pm ON tm.customer_id = pm.customerID

Match between tables with New, Not New

I am still learning TSQL at the moment and im new to here so forgive me if Ive not done this right.
I have a table that each day loads new days data. Each day that loads has a report date for the previous day.
I want to get yesterdays data (eg - 17/09/2019) from the table, and I want to look at the data in the same table from the day before that (eg - 16/09/2019) and I want to run a check for the reference number and if the Reference number appears on the day before then I want it to say Not New, and if it does match to the day before then I want it to say New.
The columns I have is :
ReferenceNumber, ReportData, NewAppt
NewAppt column will be where it put the outcome of New/Not New
Something like this should work:
WITH Yesterday AS (
SELECT DISTINCT
ReferenceNumber,
CONVERT(DATE, ReportDate) AS ReportDate
FROM
MyTable
WHERE
CONVERT(DATE, ReportDate) = CONVERT(DATE, DATEADD(DAY, -1, GETDATE())),
DayBeforeYesterday AS (
SELECT DISTINCT
ReferenceNumber
FROM
MyTable
WHERE
CONVERT(DATE, ReportDate) = CONVERT(DATE, DATEADD(DAY, -2, GETDATE()))
SELECT
y.ReferenceNumber,
y.ReportDate,
CASE
WHEN x.ReferenceNumber IS NOT NULL THEN 0
ELSE 1
END AS NewAppointment
FROM
Yesterday y
LEFT JOIN DayBeforeYesterday x ON x.ReferenceNumber = y.ReferenceNumber;
Make a list of all the DISTINCT reference numbers from each day, and then join them into one big list, with the logic to see if there was a reference number yesterday that was also in the list from the day before yesterday.
I suppose your column ReportData is some sort of 'date' type and contains only the date (no time).
Furthermore, for each date, there should be at most 1 record for a specific ReferenceNumber.
In that case, try this:
SELECT t1.ReferenceNumber,
t1.ReportData,
CASE
WHEN t2.ReferenceNumber IS NULL THEN 'New'
ELSE 'Not New'
END AS NewAppt
FROM my_table t1
LEFT OUTER JOIN my_table t2
ON t1.ReferenceNumber = t2.ReferenceNumber
AND t2.ReportData = DATEADD(day, -1, t1.ReportData)
WHERE t1.ReportData = '2019-09-17';
Here's an approach using LAG which removes the need to join to the same table several times and instead just checks the preceding row for that Reference Number.
Note that in my interpretation of your request if a Reference Number disappears for a day and then returns then it's flagged as new. You can adapt the query to simply check if the number has appeared at any point in the past if that's not what you need.
CREATE TABLE #TestData (ReferenceNumber int,Reportdata date)
INSERT INTO #TestData
VALUES (1,'2019-01-16'),(1,'2019-01-17'),(1,'2019-01-18'),(2,'2019-01-18'),(3,'2019-01-17'),(3,'2019-01-18'),(4,'2019-01-17')
SELECT
ReferenceNumber
,ReportData
,IIF(
LAG(ReportData) OVER(PARTITION BY ReferenceNumber ORDER BY ReportData)
= dateadd(day,-1,ReportData)
,'Not New'
,'New'
) AS NewAppt
FROM #TestData

How to i find records in the last month that do not have a "Date created" column

Im trying to find records that have not had notes created during the last 1 month. The table only registers when a note is created.
I am trying to find NULL values, but that would not be the correct logic
SELECT *
FROM vpersonnotesalldata AS pn
WHERE pn.flddatecreated > '20190501'
AND pn.fldnotedatecreated < '20190530'
If you want records which don't have a note in last 30 days, try this:
select p.* from person p where personid not in (
select personid from Note where dateCreated < dateadd(d, -30, GetDate())
)
Obviously use your actual table names in your sql
Try this with example last month
SELECT *
FROM vpersonnotesalldata AS pn
WHERE pn.NoteColumnHERE IS NULL
AND pn.CreateDateColumnHERE
BETWEEN '01.05.2019'
AND '31.05.2019'
It picks all pn.NoteColumnHERE which are NULL in the Span of pn.CreateDateColumnHERE BETWEEN 01.05. and 31.05.
I hope the Date Input is correct for your SQL Version. In Microsoft SQL it is working!
The performance will be much better if you use EXISTS / NOT EXISTS instead of IN / NOT IN
SELECT *
FROM Client C
WHERE NOT EXISTS (
SELECT 1
FROM vpersonnotesalldata
WHERE
fldClientNumber = C.fldClientNumber
AND fldnotedatecreated BETWEEN
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-1, 0) --First day of previous month
AND DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1) --Last Day of previous month
)

SQL Select all entries from last two months

I would like to select dynamically all entries from last two months, and without entering date range in my query.
Here is my simple code:
SELECT Customer_Name, Date FROM table_Customer; all data between last two month
Thanks in advance for your help
SELECT
ME.FullName,
R.RuleDefaultName,
PR.ObjectName,
PR.CounterName,
P.DateTime,
P.SampleCount,
P.MinValue,
P.MaxValue,
P.AverageValue,
P.StandardDeviation
FROM
Perf.vPerfHourly P
INNER JOIN vManagedEntity ME ON
P.ManagedEntityRowId = ME.ManagedEntityRowId
INNER JOIN vPerformanceRuleInstance PRI ON
P.PerformanceRuleInstanceRowId = PRI.PerformanceRuleInstanceRowId
INNER JOIN vPerformanceRule PR ON
PRI.RuleRowId = PR.RuleRowId
INNER JOIN vRule R ON
PRI.RuleRowId = R.RuleRowId
SELECT Customer_Name, Dt
FROM table_Customer
where dt >= dateadd(day, -60, getdate())
Or
SELECT Customer_Name, Dt
FROM table_Customer
where dt >= dateadd(month, -2, getdate())
You should make sure not to use reserved keywords as column names.
Make sure you replace dt with the appropriate date column. The solution assumes you would need the previous 2 months data starting with the current date.
Select *
From Customers
Where
OrderDate between Dateadd(M,-2,OrderDate) And Getdate()

Query to check number of records created in a month.

My table creates a new record with timestamp daily when an integration is successful. I am trying to create a query that would check (preferably automated) the number of days in a month vs number of records in the table within a time frame.
For example, January has 31 days, so i would like to know how many days in january my process was not successful. If the number of records is less than 31, than i know the job failed 31 - x times.
I tried the following but was not getting very far:
SELECT COUNT (DISTINCT CompleteDate)
FROM table
WHERE CompleteDate BETWEEN '01/01/2015' AND '01/31/2015'
Every 7 days the system executes the job twice, so i get two records on the same day, but i am trying to determine the number of days that nothing happened (failures), so i assume some truncation of the date field is needed?!
One way to do this is to use a calendar/date table as the main source of dates in the range and left join with that and count the number of null values.
In absence of a proper date table you can generate a range of dates using a number sequence like the one found in the master..spt_values table:
select count(*) failed
from (
select dateadd(day, number, '2015-01-01') date
from master..spt_values where type='P' and number < 365
) a
left join your_table b on a.date = b.CompleteDate
where b.CompleteDate is null
and a.date BETWEEN '01/01/2015' AND '01/31/2015'
Sample SQL Fiddle (with count grouped by month)
Assuming you have an Integers table*. This query will pull all dates where no record is found in the target table:
declare #StartDate datetime = '01/01/2013',
#EndDate datetime = '12/31/2013'
;with d as (
select *, date = dateadd(d, i - 1 , #StartDate)
from dbo.Integers
where i <= datediff(d, #StartDate, #EndDate) + 1
)
select d.date
from d
where not exists (
select 1 from <target> t
where DATEADD(dd, DATEDIFF(dd, 0, t.<timestamp>), 0) = DATEADD(dd, DATEDIFF(dd, 0, d.date), 0)
)
Between is not safe here
SELECT 31 - count(distinct(convert(date, CompleteDate)))
FROM table
WHERE CompleteDate >= '01/01/2015' AND CompleteDate < '02/01/2015'
You can use the following query:
SELECT DATEDIFF(day, t.d, dateadd(month, 1, t.d)) - COUNT(DISTINCT CompleteDate)
FROM mytable
CROSS APPLY (SELECT CAST(YEAR(CompleteDate) AS VARCHAR(4)) +
RIGHT('0' + CAST(MONTH(CompleteDate) AS VARCHAR(2)), 2) +
'01') t(d)
GROUP BY t.d
SQL Fiddle Demo
Explanation:
The value CROSS APPLY-ied, i.e. t.d, is the ANSI string of the first day of the month of CompleteDate, e.g. '20150101' for 12/01/2015, or 18/01/2015.
DATEDIFF uses the above mentioned value, i.e. t.d, in order to calculate the number of days of the month that CompleteDate belongs to.
GROUP BY essentially groups by (Year, Month), hence COUNT(DISTINCT CompleteDate) returns the number of distinct records per month.
The values returned by the query are the differences of [2] - 1, i.e. the number of failures per month, for each (Year, Month) of your initial data.
If you want to query a specific Year, Month then just simply add a WHERE clause to the above:
WHERE YEAR(CompleteDate) = 2015 AND MONTH(CompleteDate) = 1