I have a table named
Ship(Date datetime,name varchar(50),Type char(1)).
In table Ship The "Date" Column is of datetime datatype. I want to select rows from ship table when minute value in Date column (of Datetime datatype) changes. For this i used the following query:
;WITH x AS
(
SELECT Name, Date,Type, rn = ROW_NUMBER() OVER
(PARTITION BY Date ORDER BY Date desc)
FROM Ship
)
SELECT * FROM x WHERE rn = 1
But the desired output is not coming. The Result coming is:
Date Name Type
2017-05-08 14:59:13.000 sumit A
2017-05-08 14:59:23.000 sumit B
2017-05-08 14:59:33.000 sumit A
2017-05-08 15:00:05.000 Ajay B
2017-05-08 15:00:13.000 Deep G
2017-05-08 15:01:03.000 Suri D
2017-05-08 15:01:13.000 Faiz E
Here in above output those rows are also coming when there is a change in second value of Date column. But i want to select rows when there is change in minute value of Date Column.Can anyone solve this?
You could use datediff minute on partition by clause
;WITH x AS
(
SELECT Name, Date,Type, rn = ROW_NUMBER() OVER
(PARTITION BY datediff(min,0,[Date]) ORDER BY Date desc)
FROM Ship
)
SELECT * FROM x WHERE rn = 1
Or it is shorter version
SELECT TOP 1 WITH TIES
Name, Date,Type
FROM Ship
ORDER BY ROW_NUMBER() OVER (PARTITION BY datediff(min,0,[Date]) ORDER BY [date] desc)
Can you add the DATEPART in the PARTITION BY to get the change in the minutes section only.
;WITH x AS
(
SELECT Name, Date,Type, rn = ROW_NUMBER() OVER
(PARTITION BY DATEPART(N, Date) ORDER BY Date desc)
FROM Ship
)
SELECT * FROM x WHERE rn = 1
Refer the Demo: http://rextester.com/YZW84894
Related
I'm in Snowflake and am trying to mark the first occurrence of a unique ID in a column. I've been playing around with first_value but am not really getting anywhere.
So my data looks something like this:
ID Date
123 1/2019
123 2/2019
123 3/2019
234 2/2019
234 3/2019
And ideally I want something like this:
ID Date First?
123 1/2019 1
123 2/2019 0
123 3/2019 0
234 2/2019 1
234 3/2019 0
How do I accomplish this?
You want ROW_NUMBER:
SELECT
ID,
Date,
IFF(ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Date) = 1, 1, 0) AS First
FROM
schema.table
ORDER BY ID, Date
;
This checks whether the current row is the first date for the ID, and if it is, assigns a value of 1 (otherwise 0).
LAG can also be used to solve this..
SELECT id
,date
,lag(id) over (partition by id order by date) is null as first
FROM table_name;
Which can be also done with FIRST_VALUE like
SELECT id
,date
,first_value(id) over (partition by id order by date) = date as first
FROM table_name;
If your intention is to retrieve the first occurrence of a unique ID in a column then the row_number() or the dense_rank() function can help.
with cte as
(
select ID, Date,
row_number() over (partition by ID order by date) as row_number
from table1
)
select * from cte where row_number = 1;
with cte as
(
select ID, Date,
dense_rank() over (partition by ID order by date) as rank
from stack1
)
select * from cte where rank = 1;
I’m struggling a bit here. The data is fabricated, but the query concept is very real.
I need to select the Customer, Current Amount, Previous Amount, Sequence and Date
WHERE DATE < 1190105
AND the DATE/SEQ is the maximum date/seq prior to that date point grouping by customer.
I’ve spent quite a few days trying all sorts of things using HAVING, nested select to try and obtain the max-date/amount and min-date/amount by customer and can’t quite get my head around it. I’m sure it should be quite easy, but any help you can offer would be really appreciated.
Thanks
**SEQ DATE CUSTOMER AMOUNT**
1 1181225 Bob 400
2 1181226 Fred 300
3 1190101 Bob 100
4 1190104 Fred 500
5 1190104 George 200
6 1190105 Bob 150
7 1190106 Bob 200
8 1190110 Fred 160
9 1190110 Bob 300
10 1190112 Fred 400
Opt 1 use row number and lag functions
SELECT
ROW_NUMBER() OVER (Partition By CustomerID Order By [Date]) as Sec,
[Date],
Customer,
Amount as CurrentAmount,
Lead(Amount) OVER (Partition By CustomerID, Order By [Date]) as PreviousAmount
FROM
YourTable
WHERE
[DATE] < 1190105
Opt use outer apply
SELECT
ROW_NUMBER() OVER (Partition By Customer Order By [Date]) as Sec,
[Date],
Customer,
Amount as CurrentAmount,
Prev.Amount as PreviousAmount
FROM
YourTable T
OUTER APPLY (
SELECT TOP 1 Amount FROM YourTable
WHERE Customer = T.Customer AND [Date] < T.[Date]
ORDER BY [DATE] DESC
) Prev
WHERE
DATE < 1190105
Opt 3 use a correlated subquery
SELECT
ROW_NUMBER() OVER (Partition By Customer Order By [Date]) as Sec,
[Date],
Customer,
Amount as CurrentAmount,
(
SELECT TOP 1 Amount FROM YourTable
WHERE Customer = T.Customer AND [Date] < T.[Date]
ORDER BY [DATE] DESC
) as PreviousAmount
FROM YourTable
WHERE
DATE < 1190105
First restrict the rows with the date filter, then search for the max by customer.
Using GROUP BY:
DECLARE #FilterDate INT = 1190105
;WITH MaxDateByCustomer AS
(
SELECT
T.CUSTOMER,
MaxSEQ = MAX(T.SEQ)
FROM
YourTable AS T
WHERE
T.Date < #FilterDate
GROUP BY
T.CUSTOMER
)
SELECT
T.*
FROM
YourTable AS T
INNER JOIN MaxDateByCustomer AS M ON
T.CUSTOMER = M.CUSTOMER AND
T.SEQ = M.MaxSEQ
Using ROW_NUMBER window function:
DECLARE #FilterDate INT = 1190105
;WITH DateRankingByCustomer AS
(
SELECT
T.*,
DateRanking = ROW_NUMBER() OVER (PARTITION BY T.CUSTOMER ORDER BY T.SEQ DESC)
FROM
YourTable AS T
WHERE
T.Date < #FilterDate
)
SELECT
D.*
FROM
DateRankingByCustomer AS D
WHERE
D.DateRanking = 1
Hi I have a table: T1 that contains two columns Date and Price
T1
---------------------------
DATE | PRICE |
---------------------------
2018-07-25 |2.00 |
---------------------------
2018-06-20 |3.00 |
---------------------------
2017-05-10 |3.00 |
---------------------------
Here are my requirements:
If a user enters a date that is not in the DB I need to return the last price and date in the table T1.
If a user enters a date that is superior or inferior to one of the dates in the table T1 -- for example if a user enters '2017-05-09' which is not in the table; I have to return the next date above the given date. In this case'2017-05-10'
I am using UNION in my script but it returns empty when one of the SELECT statements returns empty.
I am using a CTE table:
DECLARE #DateEntered DATE
WITH HistoricalCTE (Date, Price, RowNumber) AS (
SELECT R.Date,
R.Price,
ROW_NUMBER() OVER (PARTITION BY R.Date, R.Price ORDER BY Date DESC)
FROM T1 R
WHERE Date = #DateEntered
UNION
SELECT R.Date,
R.Price,
ROW_NUMBER() OVER (PARTITION BY R.Date, R.Price ORDER BY Date DESC)
FROM T1 R
WHERE Date < #DateEntered
UNION
SELECT R.Date,
R.Price,
ROW_NUMBER() OVER (PARTITION BY R.Date, R.Price ORDER BY Date DESC)
FROM T1 R
WHERE Date > #DateEntered
)
The issue is when I enter superior to all the dates in the table T1, I get an empty result because the first select is returning empty. Any idea about how I would solve this?
You might be overcomplicating this. If I read your question correctly, we can just take the smallest value greater than the input, or if that doesn't exist, then just take the max of the table.
WITH cte AS (
SELECT *,
ROW_NUMBER() OVER (ORDER BY Date) rn
FROM T1
WHERE Date > #DateEntered
)
SELECT
CASE WHEN EXISTS (SELECT 1 FROM cte WHERE rn = 1)
THEN (SELECT Date FROM cte WHERE rn = 1)
ELSE (SELECT MAX(Date) FROM T1) END AS Date,
CASE WHEN EXISTS (SELECT 1 FROM cte WHERE rn = 1)
THEN (SELECT Price FROM cte WHERE rn = 1)
ELSE (SELECT Price FROM T1 WHERE Date = (SELECT MAX(Date) FROM T1)) END AS Price;
Demo
All the edge cases seem to be working in the above demo, and you may test any input date against your sample data.
I have a table that has families_id, date, metric_id
A record gets inserted for each families_id there will be a date & metric_id 1-10.
So there should be 10 records for each families_id, the records get inserted with a date an each should follow on from each other. So metric_id 10 date should be greater than metric_id 6 date.
On mass how can I select where they have
Missed a metric_id
The date for the metric_id 6 is before the date for metric_id 2
use row_number to assign an ordinal to the metric_id and date for each family, then they should match - also metric_id, 1,2,3,4... should match with its calculated row_number(), also 1,2,3,4....
SELECT IQ.* FROM (SELECT families_id, [date], metric_id,
ROW_NUMBER() OVER (PARTITION BY families_id ORDER BY [date]) rn_date,
ROW_NUMBER() OVER (PARTITION BY families_id ORDER BY metricid) rn_metric FROM YourTable) IQ
WHERE IQ.rn_date != IQ.rn_metric;
--should detect wrongly ordered metric_ids
SELECT IQ.* FROM (SELECT families_id, [date], metric_id,
ROW_NUMBER() OVER (PARTITION BY families_id ORDER BY [date]) rn_date,
ROW_NUMBER() OVER (PARTITION BY families_id ORDER BY metricid) rn_metric FROM YourTable) IQ
WHERE IQ.metric_id != IQ.rn_metric;
Another possibility - detect a metricID where the date is earlier for a higher id
SELECT y1.families_id, y1.metric_id FROM yourtable y1
WHERE
EXISTS(SELECT 0 FROM yourtable y2 WHERE y1.families_id = y2.families_id
AND
y2.date < y1.date
AND
y2.metricid > y1.metricid)
This is a question using SQL Server. Is there a more elegant way of doing this?
Considering a table mytable (I'm using Unix timestamps, I've converted these to readable dates for ease of reading)
ID Foreign_ID Date
-------------------------
1 1 01-Jul-15
2 2 01-Sep-16
3 3 05-Aug-16
4 2 01-Sep-15
I would like to extract the Foreign_ID where the most recent record's (highest ID) date is in a range, which is this example is the 1st January 2016 to 31st December 2016. The following works if substituting the dates for timestamps:
select distinct
Foreign_ID
from
mytable l1
where
(select top 1 Date
from mytable l2
where l2.Foreign_ID = l1.Foreign_ID
order by ID desc) >= **1 Jan 2016**
and
(select top 1 Date
from mytable l2
where l2.Foreign_ID = l1.Foreign_ID
order by ID desc) <= **31 Dec 2016**
That should only return Foreign_ID = 3. A simpler query would also return Foreign_ID 2 which would be wrong, as it has a more recent record dated out of the above ranges
This will all form part of a bigger query
Assuming SQL Server 2005+, you can use ROW_NUMBER:
WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER( PARTITION BY Foreign_ID
ORDER BY ID DESC)
FROM dbo.YourTable
WHERE [Date] >= '01-Jan-2016' -- you need to use the right
AND [Date] <= '31-Dec-2016' -- date format here
)
SELECT Foreign_ID
FROM CTE
WHERE RN = 1;
If it's SQL Server 2008+, you can use this:
select foreign_id
from (
select foreign_id, row_number() over (order by id desc) as rseq
from myTable
where Date >= value1 and Date <= value2
) as x
where rseq = 1
Just fill in the date values, and you might have to put brackets or quotes around the column named "Date", since it is also a keyword.