SQL-92 Query to find earliest date dependent on column value changing - sql

I am querying a data system with an OLEDB interface that supports SQL92. My query problem is equivalent to the one solved here: SQL Query to find earliest date dependent on column value changing,
but the solution provided there and copied below is too advanced for SQL92:
SELECT JobCodeId, MIN(LastEffectiveDate) AS mindate
FROM (
SELECT *,
prn - rn AS diff
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY JobCodeID
ORDER BY LastEffectiveDate) AS prn,
ROW_NUMBER() OVER (ORDER BY LastEffectiveDate) AS rn
FROM #tmp
) q
) q2
GROUP BY
JobCodeId, diff
ORDER BY
mindate
What would a SQL92-compliant version of this solution look like?

Use:
SELECT JobCodeId,
MIN(LastEffectiveDate) AS mindate
FROM (SELECT *,
prn - rn AS diff
FROM (SELECT *,
(SELECT CASE WHEN COUNT(*) = 0 THEN 1 ELSE COUNT(*) END
FROM #tmp t
WHERE t.JobCodeID = r.JobCodeID
AND t.LastEffectiveDate <= x.LastEffectiveDate) AS prn,
(SELECT COUNT(*) + 1
FROM #tmp t
WHERE t.LastEffectiveDate <= x.LastEffectiveDate) AS rn
FROM #tmp x) q
) q2
GROUP BY JobCodeId, diff
ORDER BY mindate

Related

Get Earliest Date corresponding to the latest occurrence of a recurring name

I have a table with Name and Date columns. I want to get the earliest date when the current name appeared. For example:
Name
Date
X
30-Jan-2021
X
29-Jan-2021
X
28-Jan-2021
Y
27-Jan-2021
Y
26-Jan-2021
Y
25-Jan-2021
Y
24-Jan-2021
X
23-Jan-2021
X
22-Jan-2021
Now when I try to get the earliest date when current name (X) started to appear, I want 28-Jan, but the sql query would give 22-Jan-2021 because that's when X appeared originally for the first time.
Update: This was the query I was using:
Select min(Date) from myTable where Name='X'
I am using older SQL Server 2008 (in the process of upgrading), so do not have access to LEAD/LAG functions.
The solutions suggested below do work as intended. Thanks.
This is a type of gaps-and-islands problem.
There are many solutions. Here is one that is optimized for your case
Use LEAD/LAG to identify the first row in each grouping
Filter to only those rows
Number them rows and take the first one
WITH StartPoints AS (
SELECT *,
IsStart = CASE WHEN Name <> LEAD(Name, 1, '') OVER (ORDER BY Date DESC) THEN 1 END
FROM YourTable
),
Numbered AS (
SELECT *,
rn = ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Date DESC)
FROM StartPoints
WHERE IsStart = 1 AND Name = 'X'
)
SELECT
Name, Date
FROM Numbered
WHERE rn = 1;
db<>fiddle
For SQL Server 2008 or earlier (which I strongly suggest you upgrade from), you can use a self-join with row-numbering to simulate LEAD/LAG
WITH RowNumbered AS (
SELECT *,
AllRn = ROW_NUMBER() OVER (ORDER BY Date ASC)
FROM YourTable
),
StartPoints AS (
SELECT r1.*,
IsStart = CASE WHEN r1.Name <> ISNULL(r2.Name, '') THEN 1 END
FROM RowNumbered r1
LEFT JOIN RowNumbered r2 ON r2.AllRn = r1.AllRn - 1
),
Numbered AS (
SELECT *,
rn = ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Date DESC)
FROM StartPoints
WHERE IsStart = 1
)
SELECT
Name, Date
FROM Numbered
WHERE rn = 1;
This is a gaps and island problem. Based on the sample data, this will work:
WITH Groups AS(
SELECT YT.[Name],
YT.[Date],
ROW_NUMBER() OVER (ORDER BY YT.Date DESC) -
ROW_NUMBER() OVER (PARTITION BY YT.[Name] ORDER BY Date DESC) AS Grp
FROM dbo.YourTable YT),
FirstGroup AS(
SELECT TOP (1) WITH TIES
G.[Name],
G.[Date]
FROM Groups G
WHERE [Name] = 'X'
ORDER BY Grp ASC)
SELECT MIN(FG.[Date]) AS Mi
db<>fiddle
If i did understand, you want to know when the X disappeared and reappeared again. in that case you can search for gaps in dates by group.
this and example how to detect that
SELECT name
,DATE
FROM (
SELECT *
,DATEDIFF(day, lead(DATE) OVER (
PARTITION BY name ORDER BY DATE DESC
), DATE) DIF
FROM YourTable
) a
WHERE DIF > 1

Selecting the latest order

I need to select the data of all my customers with the records displayed in the image. But I need to get the most recent record only, for example I need to get the order # E987 for John and E888 for Adam. As you can see from the example, when I do the select statement, I get all the order records.
You don't mention the specific database, so I'll answer with a generic solution.
You can do:
select *
from (
select t.*,
row_number() over(partition by name order by order_date desc) as rn
from t
) x
where rn = 1
You can use analytical function row_number.
Select * from
(Select t.*,
Row_number() over (partition by customer_id order by order_date desc) as rn
From your_table t) t
Where rn = 1
Or you can use not exists as follows:
Select *
From yoir_table t
Where not exists
(Select 1 from your_table tt
Where t.customer_id = tt.custome_id
And tt.order_date > t.order_date)
You can do it with a subquery that finds the last order date.
SELECT t.*
FROM yoir_table t
JOIN (SELECT tt.custome_id,
MAX(tt.order_date) MaxOrderDate
FROM yoir_table tt
GROUP BY tt.custome_id) AS tt
ON t.custome_id = tt.custome_id
AND t.order_date = tt.MaxOrderDate

Filter the table with latest date having duplicate OrderId

I have following table:
I need to filter out the rows for which start date is latest corresponding to its order id .With reference to given table row no 2 and 3 should be the output.
As row 1 and row 2 has same order id and order date but start date is later than first row. And same goes with row number 3 and 4 hence I need to take out row no 3 . I am trying to write the query in SQL server. Any help is appreciated.Please let me know if you need more details.Apologies for poor English
You can do this easily with a ROW_NUMBER() windowed function:
;With Cte As
(
Select *,
Row_Number() Over (Partition By OrderId Order By StartDate Desc) RN
From YourTable
)
Select *
From Cte
Where RN = 1
But I question the StartDate datatype. It looks like these are being stored as VARCHAR. If that is the case, you need to CONVERT the value to a DATETIME:
;With Cte As
(
Select *,
Row_Number() Over (Partition By OrderId
Order By Convert(DateTime, StartDate) Desc) RN
From YourTable
)
Select *
From Cte
Where RN = 1
Another way using a derived table.
select
t.*
from
YourTable t
inner join
(select OrderId, max(StartDate) dt
from YourTable
group by OrderId) t2 on t2.dt = t.StartDate and t2.OrderId = t.OrderId

Sort result when using ROW_NUMBER()

This is a follow-up to this question I asked yesterday.
I did not know if I should expand my original question, I decided to start a new one (bear with me...)
My SELECT is like this at the moment:
SELECT *
FROM
(
SELECT
a.guid_column1, b.guidID_column1, c.date_column1, d.guid_column1
ROW_NUMBER() OVER (PARTITION BY a.guid_column1, b.guid_column1 ORDER BY c.date_column1 DESC) as rn
...
-- JOINS AND WHERE STUFF HERE
....
) t
WHERE t.rn = 1
I get the (expected) result like this:
a.guid_column1 b.guid_column1 c.date_column1 d.guid_column1
-------------------------------------------------------------------
a1 b1 07/08/2013 someUniqueID
a2 b2 05/06/2012 someUniqueID
The tricky part is that I would like to sort that result by a dateadd, something like this ORDER BY dateadd(month, a.float_column, c.date_column1) asca.float_column is of course not always the same (and is in fact entered by the user later on).
Is there a way to accomplish this in SQL (I'm using SQL Server 2005)
Below query will calculate the new date in the SELECT-CLAUSE.
If a.float_column is NULL nothing will be added to the original date.
SELECT dateadd(month, ISNULL(t.float_column,0), t.date_column1) as newDate
, *
FROM
(
SELECT
a.guid_column1, b.guidID_column1, c.date_column1, d.guid_column1, a.float_column
ROW_NUMBER() OVER (PARTITION BY a.guid_column1, b.guid_column1 ORDER BY c.date_column1 DESC) as rn
...
-- JOINS AND WHERE STUFF HERE
....
) t
WHERE t.rn = 1
ORDER BY newDate ASC
why don't you just add column into your subquery?
select *
from
(
select
a.guid_column1, b.guidID_column1, c.date_column1, d.guid_column1,
dateadd(month, a.float_column, c.date_column1) as sort_order,
row_number() over (partition by a.guid_column1, b.guid_column1 order by c.date_column1 desc) as rn
--
-- JOINS AND WHERE STUFF HERE
--
) t
where t.rn = 1
order by t.sort_order asc

how to query the occuring time of the max wind from a database?

I want to find the occuring time of the max wind, the max wind, and total rain from a database. The database have three columns: observerTime, wind and rain, how to generate the SQL statement to get the result ?
select observerTime from t where wind = (select max(wind) from t)
or if you need the last date when it occures
select max(observerTime) from t where wind = (select max(wind) from t)
You don't mention the database, but one of the following is likely to work:
select top 1 *, (select sum(rain) from t) as TotalRain
order by wind desc
or:
select *, (select sum(rain) from t) as TotalRain
from t
order by wind desc
limit 1
or
select *, (select sum(rain) from t) as TotalRain
from (select *
from t
order by wind desc
) t
where rownum = 1
You should be able to use something like this:
select t1.observerTime,
t1.wind,
(select sum(rain) from yourtable) TotalRain
from yourtable t1
inner join
(
select max(wind) MaxWind
from yourtable
) t2
on t1.wind = t2.maxwind
See SQL Fiddle with Demo
Since you are using SQL Server, you can also use row_number():
select observertime,
wind,
(select sum(rain) from yourtable) TotalRain
from
(
select observertime,
wind,
rain,
row_number() over(order by wind desc) rn
from yourtable
) src
where rn = 1
See SQL Fiddle with Demo