I have the following scenario:
Using SQLDbx - database: DB2
The following SQL
WITH priceanddates AS
(
SELECT a.*
FROM FPRICE a
INNER JOIN
(
SELECT edate, MAX(idx) maxIdx
FROM FPRICE
WHERE price>0
GROUP BY edate
) b ON a.edate = b.edate AND a.idx = b.maxIdx
)
SELECT *
FROM priceanddates
WHERE fcode='XYZ'
ORDER BY edate
yields:
fcode edate idx price
XYZ 2010-09-17 2 34,3
XYZ 2010-09-20 2 34,3
XYZ 2010-09-21 2 34,3
XYZ 2010-09-22 2 34,3
XYZ 2010-09-23 2 35,7
XYZ 2010-09-24 2 34,5
XYZ 2010-09-27 2 35,5
BUT - I need something more...I would like to add a column in the final select which says something about the date's validity, like this:
fcode edate_from edate_to idx price
XYZ 2010-09-17 2010-09-20 2 34,3
XYZ 2010-09-20 2010-09-21 2 34,3
XYZ 2010-09-21 2010-09-22 2 34,3
XYZ 2010-09-22 2010-09-23 2 34,3
XYZ 2010-09-23 2010-09-24 2 35,7
XYZ 2010-09-24 2010-09-27 2 34,5
XYZ 2010-09-27 2010-09-30 2 35,5
So, edate_to is based on the "next" edate_from (as the view is currently ordered by date), or (as I hopefully deduced correctly) edate_to is simply the MIN(edate larger than "current" edate)
The final cutoff date for all dates in the DB is 2010-09-30, alas the last edate_to must always be 2010-09-30.
Obviously, I am not very skilled when it comes to writing SQL, hopefully someone can point me in the right direction - or even better - provide a solution :)
I did search around SO for a while, but I couldn't really find what I was looking for...
Cheers, Dritt.
Maybe:
WITH priceanddates AS
(
SELECT a.*,
(SELECT COALESCE(MIN(aa.edate), '2010-09-30')
FROM FPRICE aa
WHERE aa.edate > a.edate) AS edate_to
FROM FPRICE a
INNER JOIN
(
SELECT edate, MAX(idx) maxIdx
FROM FPRICE
WHERE price>0
GROUP BY edate
) b ON a.edate = b.edate AND a.idx = b.maxIdx
)
SELECT *
FROM priceanddates
WHERE fcode='XYZ'
ORDER BY edate
Use the new LEAD function.
More on it here.
WITH priceanddates AS
(
SELECT a.*
FROM FPRICE a
INNER JOIN
(
SELECT edate, MAX(idx) maxIdx
FROM FPRICE
WHERE price>0
GROUP BY edate
) b ON a.edate = b.edate AND a.idx = b.maxIdx
)
SELECT fcode
, edate AS edate_from
, LEAD (edate) OVER (ORDER BY edate) AS edate_to
, idx
, price
FROM priceanddates
WHERE fcode='XYZ'
ORDER BY edate
Related
I need a bit of help with a SQL query.
Imagine I've got the following table
id | date | price
1 | 1999-01-01 | 10
2 | 1999-01-01 | 10
3 | 2000-02-02 | 15
4 | 2011-03-03 | 15
5 | 2011-04-04 | 16
6 | 2011-04-04 | 20
7 | 2017-08-15 | 20
What I need is all dates where only one price is present.
In this example I need to get rid of row 5 and 6 (because there is two difference prices for the same date) and either 1 or 2(because they're duplicate).
How do I do that?
select date,
count(distinct price) as prices -- included to test
from MyTable
group by date
having count(distinct price) = 1 -- distinct for the duplicate pricing
The following should work with any DBMS
SELECT id, date, price
FROM TheTable o
WHERE NOT EXISTS (
SELECT *
FROM TheTable i
WHERE i.date = o.date
AND (
i.price <> o.price
OR (i.price = o.price AND i.id < o.id)
)
)
;
JohnHC answer is more readable and delivers the information the OP asked for ("[...] I need all the dates [...]").
My answer, though less readable at first, is more general (allows for more complexes tie-breaking criteria) and also is capable of returning the full row (with id and price, not just date).
;WITH CTE_1(ID ,DATE,PRICE)
AS
(
SELECT 1 , '1999-01-01',10 UNION ALL
SELECT 2 , '1999-01-01',10 UNION ALL
SELECT 3 , '2000-02-02',15 UNION ALL
SELECT 4 , '2011-03-03',15 UNION ALL
SELECT 5 , '2011-04-04',16 UNION ALL
SELECT 6 , '2011-04-04',20 UNION ALL
SELECT 7 , '2017-08-15',20
)
,CTE2
AS
(
SELECT A.*
FROM CTE_1 A
INNER JOIN
CTE_1 B
ON A.DATE=B.DATE AND A.PRICE!=B.PRICE
)
SELECT * FROM CTE_1 WHERE ID NOT IN (SELECT ID FROM CTE2)
I have a scenario to get the respective field value of "Max" and "Min" records
Please find the sample data below
-----------------------------------------------------------------------
ID Label ProcessedDate
-----------------------------------------------------------------------
1 Label1 11/01/2016
2 Label2 11/02/2016
3 Label3 11/03/2016
4 Label4 11/04/2016
5 Label5 11/05/2016
I have the "ID" field populated in another table as a foreign key. While querying those records in that table based on the "ID" field I need to get the "Label" field of "Max" Processed date and "Min" processed date.
-----------------------------------------------------------------------
ID LabelID GroupingField
-----------------------------------------------------------------------
1 1 101
2 2 101
3 3 101
4 4 101
5 5 101
6 1 102
7 2 102
8 3 102
9 4 102
And the final result set I expect it to look something like this.
-----------------------------------------------------------------------
GroupingField FirstProcessed LastProcessed
-----------------------------------------------------------------------
101 Label1 Label5
102 Label1 Label4
I have 'almost' managed to get this above result using rank function but still not satisfied with it. So I am looking if someone can provide me with a better option.
Thanks,
Prakazz
CREATE TABLE #Details (ID INT,LabelID INT,GroupingField INT)
CREATE TABLE #Details1 (ID INT,Label VARCHAR(100),ProcessedDate VARCHAR(100))
INSERT INTO #Details1 (ID ,Label ,ProcessedDate )
SELECT 1,'Label1','11/01/2016' UNION ALL
SELECT 2,'Label2','11/02/2016' UNION ALL
SELECT 3,'Label3','11/03/2016' UNION ALL
SELECT 4,'Label4','11/04/2016' UNION ALL
SELECT 5,'Label5','11/05/2016'
INSERT INTO #Details (ID ,LabelID ,GroupingField )
SELECT 1,1,101 UNION ALL
SELECT 2,2,101 UNION ALL
SELECT 3,3,101 UNION ALL
SELECT 4,4,101 UNION ALL
SELECT 5,5,101 UNION ALL
SELECT 6,1,102 UNION ALL
SELECT 7,2,102 UNION ALL
SELECT 8,3,102 UNION ALL
SELECT 9,4,102
;WITH CTE (GroupingField , MAXId ,MinId) AS
(
SELECT GroupingField,MAX(LabelID) MAXId,MIN(LabelID) MinId
FROM #Details
GROUP BY GroupingField
)
SELECT GroupingField ,B.Label FirstProcessed, A.Label LastProcessed
FROM CTE
JOIN #Details1 A ON MAXId = A.ID
JOIN #Details1 B ON MinId = B.ID
You can use SQL Row_Number() function using Partition By as follows with a combination of Group By
;with cte as (
select
t.Label, t.ProcessedDate,
g.GroupingField,
ROW_NUMBER() over (partition by GroupingField Order By ProcessedDate ASC) minD,
ROW_NUMBER() over (partition by GroupingField Order By ProcessedDate DESC) maxD
from tbl t
inner join GroupingFieldTbl g
on t.ID = g.LabelID
)
select GroupingField, max(FirstProcessed) FirstProcessed, max(LastProcessed) LastProcessed
from (
select
GroupingField,
FirstProcessed = CASE when minD = 1 then Label else null end,
LastProcessed = CASE when maxD = 1 then Label else null end
from cte
where
minD = 1 or maxD = 1
) t
group by GroupingField
order by GroupingField
I also used CTE expression to make coding easier and understandable
Output is as
I have a table like
Id WID AID DateValue
1 1 12 2015-07-10 15:14:46.770
2 1 13 2015-07-10 14:14:46.770
3 2 13 2015-07-10 13:14:46.770
4 2 13 2015-07-10 12:14:46.770
5 2 13 2015-07-10 11:14:46.770
Now, I want to get the Id value by grouping WIDAND AID, then taking the MAX value from DateValue.
The desired output is
Output:
Id
1
2
3
I tried something like this
SELECT Id, MAX(DateValue)
FROM Table1
GROUP BY WID, AID`
Though I don't want DateValue in the select but it is fine.
Can anyone help me on this
I think you want a query like this:
SELECT Id --or *
FROM (
SELECT *
, ROW_NUMBER() OVER (PARTITION BY WID, AID ORDER BY DateValue DESC) AS seqNum
FROM yourTable) dt
WHERE (SeqNum =1);
You can use a correlated subquery like so:
SELECT Id FROM Table1 t1
WHERE NOT EXISTS (
SELECT 1 FROM Table1 t2
WHERE t1.WID = t2.WID AND t1.AID = t2.AID AND t1.DateValue < t2.DateValue
)
I have a history of records (multiple records per update all with the exact same datetime) that share an IdString.
I want a query to determine which of these records are part of the most recent update group.
This query will show me one of the records having the most recent update date, but for each partition, I need all the records with that max date.
;with cte as(
select ROW_NUMBER() over (partition by IdString order by UpdateDate desc) as [rn], *
from MyTable
)
select CASE WHEN (cte.rn = 1) THEN 0 ELSE 1 END [IsOld], *
from MyTable m
inner join cte on cte.RecordId= m.RecordId
Would someone please help me figure out an appropriate query?
EDIT: Sample
(IsOld is the desired calculated value)
IsOld RecordId IdString UpdateDate
1 1 ABC 2011-06-16
1 2 ABC 2012-05-30
1 3 ABC 2008-12-31
0 4 ABC 2012-06-08
1 5 ABC 2011-01-16
0 6 ABC 2012-06-08
1 7 ABC 2012-06-07
1 8 XYZ 2001-01-16
1 9 XYZ 2013-01-30
0 10 XYZ 2001-01-31
1 11 XYZ 2013-06-01
1 12 XYZ 2001-05-04
0 13 XYZ 2013-01-30
SELECT CASE WHEN updateDate = maxDate THEN 0 ELSE 1 END isOldRecord, RecordID, IDString, UpdateDate
FROM
(
select m.RecordID, m.IDString, m.updateDate, MAX(UpdateDate) OVER (PARTITION BY IDString) maxDate
from MyTable m
) A
Try this -
;WITH cte AS(
SELECT RANK() OVER(PARTITION BY IdString ORDER BY UpdateDate DESC) AS [row_num], *
FROM MyTable
)
SELECT CASE WHEN m.[row_num] = 1 THEN 0 ELSE 1 END isOld, *
from cte m
I have a large table with the following columns and sample values:
ID Ser Reg Date
1 12345 001 1/3/2011
1 12345 001 2/2/2011
1 12345 002 1/3/2011
1 12345 002 2/2/2011
2 23456 001 1/3/2011
2 23456 001 2/7/2011
2 23456 001 3/5/2011
I tried this query from a previous post SQL - Select next date query - but did not get the desired results:
SELECT
mytable.id,
mytable.date,
(
SELECT
MIN(mytablemin.date)
FROM mytable AS mytablemin
WHERE mytablemin.date > mytable.date
) AS NextDate
FROM mytable
This is what I am trying to accomplish:
ID Ser Reg curr_Date prev_Date
1 12345 001 2/2/2011 1/3/2011
1 12345 002 2/2/2011 1/3/2011
2 23456 001 2/7/2011 1/5/2011
2 23456 001 3/5/2011 2/7/2011
I would appreciate any help with this task.
if you are using oracle database (as you have not mentioned then I can assume anything)
then you can use lead and lag function/command for this ..
select id,ser, reg, curr_date ,prev_date
from
(
select id,ser, reg, ser, date curr_date
LEAD(date, 1, 0) OVER (PARTITION BY id,ser, reg, curr_date ORDER BY date DESC NULLS LAST) prev_date,
)
where prev_date is not null;
There was a condition missing from correlated subquery joining mytablemin copy of mytable table with mytable. Also you would eliminate records which do not have NextDate - but this might give incorrect results in case when only one record in group (Id, Ser, Reg) exists by eliminating it from result set.
select * from
(
SELECT
mytable.id,
mytable.date,
(
SELECT
MIN(mytablemin.date)
FROM mytable AS mytablemin
WHERE mytablemin.date > mytable.date
and mytablemin.id = mytable.id
and mytablemin.Ser = mytable.Ser
and mytablemin.Reg = mytable.Reg
) AS NextDate
FROM mytable
) a
where a.NextDate is not null
And here is version using derived table with aggregation:
SELECT
mytable.id,
mytable.date,
mytablemin.minDate
FROM mytable
inner join
(
SELECT mytablemin.id,
mytablemin.Ser,
mytablemin.Reg,
MIN(mytablemin.date) minDate
FROM mytable AS mytablemin
group by mytablemin.id,
mytablemin.Ser,
mytablemin.Reg
having MIN(mytablemin.date) is not null
) AS mytablemin
on mytablemin.id = mytable.id
and mytablemin.Ser = mytable.Ser
and mytablemin.Reg = mytable.Reg