I have the following data in Sybase ASE
id effectiveDate lastModificationDate rateValue
----- ---------------- -------------------- ------------
1 20130627 6/27/2013 3:27:09 AM 0
1 20130627 6/27/2013 4:39:10 AM 2.75
1 20130627 6/28/2013 3:48:15 AM 0
1 20130627 6/28/2013 4:36:43 AM 2.75
1 20130628 6/28/2013 3:48:14 AM 0
1 20130628 6/28/2013 4:36:42 AM 2.75
2 20130628 6/28/2013 4:36:42 AM .75
2 20130628 6/28/2013 3:48:14 AM 0
How do I group it, so that I get only the last row, ie I get the row which has the max lastModificationDate for the same id+effectiveDate.
So output would be :
id effectiveDate lastModificationDate value
----- ---------------- -------------------- ------------
1 20130627 6/28/2013 4:36:43 AM 2.75
1 20130628 6/28/2013 4:36:42 AM 2.75
2 20130628 6/28/2013 4:36:42 AM .75
Please note that this would be on TSQL (Sybase ASE 15).
EDIT: Have changed the data to make it more realistic
Try:
SELECT t1.*
FROM Table1 t1
WHERE t1.lastModificationDate = (SELECT MAX(t2.lastModificationDate)
FROM Table1 t2
WHERE t2.effectiveDate = t1.effectiveDate
AND t2.id = t1.id)
Sybase documentation:
Subqueries can be nested inside the where or having clause of an outer
select, insert, update, or delete statement, inside another subquery,
or in a select list. Alternatively, you can write many statements that
contain subqueries as joins; Adaptive Server processes such statements
as joins.
Another answer avoiding the use of a subquery would be ...
select id, effectiveDate, lastModificationDate, rateValue
from #mydata
group by id, effectiveDate
having lastModificationDate = max(lastModificationDate)
If I suppose your data is stored in a #mydata temporary table
create table #mydata(
id int null,
effectiveDate char(8) null,
lastModificationDate datetime null,
rateValue money null
)
insert into #mydata(id, effectiveDate, lastModificationDate, rateValue) select 1, "20130627", "6/27/2013 3:27:09 AM", 0
insert into #mydata(id, effectiveDate, lastModificationDate, rateValue) select 1, "20130627", "6/27/2013 4:39:10 AM", 2.75
insert into #mydata(id, effectiveDate, lastModificationDate, rateValue) select 1, "20130627", "6/28/2013 3:48:15 AM", 0
insert into #mydata(id, effectiveDate, lastModificationDate, rateValue) select 1, "20130627", "6/28/2013 4:36:43 AM", 2.75
insert into #mydata(id, effectiveDate, lastModificationDate, rateValue) select 1, "20130628", "6/28/2013 3:48:14 AM", 0
insert into #mydata(id, effectiveDate, lastModificationDate, rateValue) select 1, "20130628", "6/28/2013 4:36:42 AM", 2.75
insert into #mydata(id, effectiveDate, lastModificationDate, rateValue) select 2, "20130628", "6/28/2013 4:36:42 AM", .75
insert into #mydata(id, effectiveDate, lastModificationDate, rateValue) select 2, "20130628", "6/28/2013 3:48:14 AM", 0
Related
I have a table of datestamped events that I need to bundle into 7-day groups, starting with the earliest occurrence of each event_id.
The final output should return each bundle's start and end date and 'value' column of the most recent event from each bundle.
There is no predetermined start date, and the '7-day' windows are arbitrary, not 'week of the year'.
I've tried a ton of examples from other posts but none quite fit my needs or use things I'm not sure how to refactor for BigQuery
Sample Data;
Event_Id
Event_Date
Value
1
2022-01-01
010203
1
2022-01-02
040506
1
2022-01-03
070809
1
2022-01-20
101112
1
2022-01-23
131415
2
2022-01-02
161718
2
2022-01-08
192021
3
2022-02-12
212223
Expected output;
Event_Id
Start_Date
End_Date
Value
1
2022-01-01
2022-01-03
070809
1
2022-01-20
2022-01-23
131415
2
2022-01-02
2022-01-08
192021
3
2022-02-12
2022-02-12
212223
You might consider below.
CREATE TEMP FUNCTION cumsumbin(a ARRAY<INT64>) RETURNS INT64
LANGUAGE js AS """
bin = 0;
a.reduce((c, v) => {
if (c + Number(v) > 6) { bin += 1; return 0; }
else return c += Number(v);
}, 0);
return bin;
""";
WITH sample_data AS (
select 1 event_id, DATE '2022-01-01' event_date, '010203' value union all
select 1 event_id, '2022-01-02' event_date, '040506' value union all
select 1 event_id, '2022-01-03' event_date, '070809' value union all
select 1 event_id, '2022-01-20' event_date, '101112' value union all
select 1 event_id, '2022-01-23' event_date, '131415' value union all
select 2 event_id, '2022-01-02' event_date, '161718' value union all
select 2 event_id, '2022-01-08' event_date, '192021' value union all
select 3 event_id, '2022-02-12' event_date, '212223' value
),
binning AS (
SELECT *, cumsumbin(ARRAY_AGG(diff) OVER w1) bin
FROM (
SELECT *, DATE_DIFF(event_date, LAG(event_date) OVER w0, DAY) AS diff
FROM sample_data
WINDOW w0 AS (PARTITION BY event_id ORDER BY event_date)
) WINDOW w1 AS (PARTITION BY event_id ORDER BY event_date)
)
SELECT event_id,
MIN(event_date) start_date,
ARRAY_AGG(
STRUCT(event_date AS end_date, value) ORDER BY event_date DESC LIMIT 1
)[OFFSET(0)].*
FROM binning GROUP BY event_id, bin;
I have query that pulls data by week and groups it together. But i does not display weeks that doesn't have any data. I want show all weeks even if they don't have data as null maybe
Here is the query if someone can help me with this it will awesome
SELECT
DATEADD (week, datediff(week, 0, StartDate), -1) as 'WeekOf'
,DATEADD (week, datediff(week, 0, StartDate), +5) as 'to'
,DATEPART(wk, StartDate) as 'WeekNumber'
FROM [DESOutage].[dbo].[OPSInterruption]
Where StartDate > '2020-01-01' and EndDate <'2020-02-01'
Group by DATEADD (week, datediff(week, 0, StartDate), -1),DATEPART(wk, StartDate),DATEADD (week, datediff(week, 0, StartDate), +5)
***************Output***************
As you could see week 2 and 4 is missing out since there is no data being returned. I would still like to see week 2 and 4 in the output with maybe 0 as result.
WeekOf to WeekNumber
2019-12-29 00:00:00.000 2020-01-04 00:00:00.000 1
2020-01-12 00:00:00.000 2020-01-18 00:00:00.000 3
2020-01-26 00:00:00.000 2020-02-01 00:00:00.000 5
You probably need a calendar table. Here is a quick way of generating one, with an untested implementation of your code. I am assuming that the StartDate may contain a time component thus the need to coalesce the dates.
DECLARE #StartYear DATETIME = '20200101'
DECLARE #days INT = 366
;WITH
E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), -- 1*10^1 or 10 rows
E2(N) AS (SELECT 1 FROM E1 a, E1 b), -- 1*10^2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), -- 1*10^4 or 10,000 rows
E8(N) AS (SELECT 1 FROM E4 a, E4 b), -- 1*10^8 or 100,000,000 rows
Tally(N) AS (SELECT TOP (#Days) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E8),
Calendar AS (
SELECT StartOfDay = DATEADD(dd,N-1,#StartYear),
EndOfDay = DATEADD(second, -1, DATEADD(dd,N ,#StartYear))
FROM Tally)
SELECT DATEADD (week, datediff(week, 0, COALESCE(x.StartDate, c.StartOfDay) ), -1) as 'WeekOf'
, DATEADD (week, datediff(week, 0, COALESCE(x.StartDate, c.StartOfDay)), +5) as 'to'
, DATEPART(wk, COALESCE(x.StartDate, c.StartOfDay)) as 'WeekNumber'
FROM Calendar c
INNER JOIN [DESOutage].[dbo].[OPSInterruption] x
ON x.StartDate > c.StartOfDay AND x.StartDate <= c.EndOfDay
WHERE c.StartOfDay > '2020-01-01' AND c.StartOfDay <'2020-02-01'
GROUP BY DATEADD (week, datediff(week, 0, COALESCE(x.StartDate, c.StartOfDay)), -1),
DATEPART(wk, COALESCE(x.StartDate, c.StartOfDay)),
DATEADD (week, datediff(week, 0, COALESCE(x.StartDate, c.StartOfDay)), +5)
is it possible to make a statistic with the queries starting from the data so configured?
Table a: registry
id (key)
name
able b: holidays
id (key)
id_anagrafica (foreign key)
data_start
data_end
Query:
SELECT b.id, a.name, b.start_date, b.end_date
FROM registry to INNER JOIN
holidays b ON (a.id = b.id_anagrafica)
WHERE b.start_date> = getdate ()
So doing I get:
id, name, start_date, end_date
1, Mario, 01/06/2018, 30/06/2018
2, Marino, 08/06/2018, 25/06/2018
3, Maria, 01/07/2018, 05/07/2018
-
-
-
Having only a start_date and end_date I can not know in a day how many people are on holidays.
What I need is:
data, num_pers_in_ferie
01/06/2018, 1
06/02/2018, 1
03/06/2018, 1
-
-
08/06/2018, 2
Can you help me?
Thanks in advance
Check the approach below
create table #registry (id int, name nvarchar(50))
insert into #registry values
(1, 'Mario'),
(2, 'Marino'),
(3, 'Maria')
create table #holidays (id int,id_anagrafica int,data_start date,data_end date)
insert into #holidays
select id, id, '2018-06-01', '2018-06-30'
from #registry
update #holidays set data_start = dateadd(day, 20, data_start), data_end = dateadd(day, -5, data_end)
where id = 2
update #holidays set data_start = dateadd(day, 14, data_start)--, data_end = dateadd(day, -10, data_end)
where id = 3
SELECT b.id, a.name, b.data_start, b.data_end
FROM #registry a
INNER JOIN
#holidays b ON (a.id = b.id_anagrafica)
WHERE b.data_start > = getdate ()
DECLARE #startDate DATETIME=CAST(MONTH(GETDATE()) AS VARCHAR) + '/' + '01/' + + CAST(YEAR(GETDATE()) AS VARCHAR) -- mm/dd/yyyy
DECLARE #endDate DATETIME= GETDATE() -- mm/dd/yyyy
select [DATA] = convert(date, DATEADD(Day,Number,#startDate)),
--se ti serve in italiano usa la riga sotto
--[DATA] = CONVERT(varchar, DATEADD(Day,Number,#startDate), 103)
SUM(case when DATEADD(Day,Number,#startDate) between data_start and data_end then 1 else 0 end) Pers_in_Ferie
from master..spt_values c,
#registry a
INNER JOIN
#holidays b ON (a.id = b.id_anagrafica)
where c.Type='P' and DATEADD(Day,Number,#startDate) >=data_start and DATEADD(Day,Number,#startDate) <=data_end
group by DATEADD(Day,Number,#startDate)
order by [DATA]
drop table #holidays
drop table #registry
Output:
DATA Pers_in_Ferie
---------- -------------
2018-06-01 1
2018-06-02 1
2018-06-03 1
2018-06-04 1
2018-06-05 1
2018-06-06 1
2018-06-07 1
2018-06-08 1
2018-06-09 1
2018-06-10 1
2018-06-11 1
2018-06-12 1
2018-06-13 1
2018-06-14 1
2018-06-15 2
2018-06-16 2
2018-06-17 2
2018-06-18 2
2018-06-19 2
2018-06-20 2
2018-06-21 3
2018-06-22 3
2018-06-23 3
2018-06-24 3
2018-06-25 3
2018-06-26 2
2018-06-27 2
2018-06-28 2
2018-06-29 2
2018-06-30 2
(30 rows affected)
Table1
sub-id ref-id Name
1 1 Project 1
2 1 Project 2
3 2 Project 3
4 2 Project 4
Table2
sub-id ref-id log_stamp Recepient log_type
----------------------------------------------------
1 1 06/06/2011 person A 1
1 1 06/14/2011 person B 2
1 1 06/16/2011 person C 2
1 1 06/17/2011 person D 3
2 1 06/18/2011 person E 2
2 1 06/19/2011 person F 2
3 2 06/20/2011 person G 1
4 2 06/23/2011 person H 3
Result
Name ref-id start_date Recepient latest_comment Recepient completion_date Receipient
Project1 1 06/06/2011 person A 06/19/2011 person F 06/17/2011 person D
Project3 2 06/20/2011 person G NULL NULL 06/23/2011 person H
log_type of 1 stands for start_date
log_type of 2 stands for latest_comment
log_type of 3 stands for completion_date
The Name of the project is just the name of the top-most name in the same group of ref-id
have tried this for now
;with T as (select
Table2.ref-id,
Table2.log_stamp,
Table2 log.log_type
when 1 then '1'
when 2 then '2'
when 3 then '3'
end as title
from
Submission sb inner join submission_log log on Table1.[sub-id] = Table2.[sub-id]
)
select * from T
pivot (
max(log_stamp)
for title IN ([1],[2],[3],[5],[6],[9],[11])
I was unable to do it as a pivot, I dont think it is possible as described
DECLARE #table1 TABLE (sub_id INT, ref_id INT, name VARCHAR(50))
INSERT #table1 VALUES (1, 1, 'Project 1')
INSERT #table1 VALUES (2, 1, 'Project 2')
INSERT #table1 VALUES (3, 2, 'Project 3' )
INSERT #table1 VALUES (4, 2, 'Project 4')
DECLARE #Table2 TABLE (sub_id INT, ref_id INT, log_stamp DATETIME, recepient VARCHAR(10), logtype INT)
INSERT #table2 VALUES(1,1,'06/06/2011','person A',1)
INSERT #table2 VALUES(1,1,'06/14/2011','person B',2)
INSERT #table2 VALUES(1,1,'06/16/2011','person C',2)
INSERT #table2 VALUES(1,1,'06/17/2011','person D',3)
INSERT #table2 VALUES(2,1,'06/18/2011','person E',2)
INSERT #table2 VALUES(2,1,'06/19/2011','person F',2)
INSERT #table2 VALUES(3,2,'06/20/2011','person G',1)
INSERT #table2 VALUES(3,2,'06/23/2011','person H',3)
;WITH a as (
SELECT RN = ROW_NUMBER() OVER (PARTITION BY t1.sub_id, t1.ref_id, t1.name, t2.logtype ORDER BY log_stamp DESC), t1.sub_id, t1.ref_id, t1.name, t2.Recepient , t2.logtype ,log_stamp
FROM #table1 t1 JOIN #table2 t2 ON t1.ref_id = t2.ref_id AND
t1.sub_id = t2.sub_id),
b as (SELECT * FROM a WHERE RN = 1)
SELECT b1.name, b1.ref_id,b1.log_stamp start_date , b1.Recepient, b2.log_stamp latest_comment , b2.Recepient, b3.log_stamp completion_date , b3.Recepient
FROM b b1
LEFT JOIN b b2 ON b1.sub_id=b2.sub_id AND b1.ref_id = b2.ref_id AND b2.logtype = 2
LEFT JOIN b b3 ON b1.sub_id=b3.sub_id AND b1.ref_id = b3.ref_id AND b3.logtype = 3
WHERE b1.logtype = 1
Result:
name ref_id start_date Recepient latest_comment Recepient completion_date Recepient
------------ ----------- ----------------------- ---------- ----------------------- ---------- ----------------------- ----------
Project 1 1 2011-06-06 00:00:00.000 person A 2011-06-16 00:00:00.000 person C 2011-06-17 00:00:00.000 person D
Project 3 2 2011-06-20 00:00:00.000 person G NULL NULL 2011-06-23 00:00:00.000 person H
I am stuck with generating a new column. The table has three columns(C_ID, C_rank, Date).
C_ID C_ Rank NewColumn(Cycle) Date
42 A 1 October 14, 2010
42 B 1 October 26, 2010
42 A 2 February 16, 2011
43 A 1 December 17, 2010
44 A 1 July 28, 2010
44 B 1 August 10, 2010
44 A 2 January 11, 2011
44 B 2 January 28, 2011
45 A 1 July 30, 2010
45 B 1 August 9, 2010
45 B 1 September 24, 2010
45 A 2 April 5, 2011
45 B 2 April 26, 2011
I want to generate one more column called Cycle in such a way that for each C_ID, it should generate the number start from one and increment the number from next C_rank = 'A' (a shown above).
I tried using row_number, but no luck.
Maybe some loop option till next C_Rank = 'A' works.
How can this be done?
You should be able to get this done using ROW_NUMBER() and PARTITION BY
;WITH YourDataCTE AS
(
SELECT
C_ID, C_Rank, Date,
ROW_NUMBER() OVER(PARTITION BY C_ID,C_Rank ORDER BY Date DESC) AS 'Cycle'
FROM
dbo.YourTable
)
SELECT *
FROM YourDataCTE
Does that do what you're looking for??
The PARTITION BY C_ID,C_Rank will cause the ROW_NUMBER to start at 1 again for each different value of C_ID,C_Rank - I didn't know what ORDER BY clause within a single partition (a single value of C_ID,C_Rank) you're looking for and just guessed it might be Date DESC (newest date first).
You could count the number of previous A's in a subquery:
select *
, (
select count(*)
from #YourTable yt2
where yt2.C_ID = yt1.C_ID
and yt2.C_Rank = 'A'
and yt2.Date <= yt1.Date
) as Cycle
from #YourTable yt1
order by
C_ID, Date
Example at ODATA.
Do a self join for all records with the same C_ID, a previous date, and a C_Rank='A' and count them.
select t1.C_ID, t1.C_Rank, count(t2.C_Rank) Cycle, t1.Date
from MyTable t1
left join MyTable t2 on t1.C_ID=t2.C_ID
and t2.Date<=t1.Date
and t2.C_Rank='A'
group by t1.C_ID, t1.C_Rank, t1.Date
order by t1.C_ID, t1.Date
Below code fulfill the requirement:
create table #Temp_Table
(
C_ID int
, C_Rank char(1)
, Date datetime
, NewColumn int
)
insert into #Temp_Table
(
C_ID
, C_Rank
, Date
)
select 42, ‘A’, ’10/14/2010′
union all
select 42, ‘B’, ’10/26/2010′
union all
select 42, ‘B’, ’10/14/2010′
union all
select 42, ‘C’, ’10/26/2010′
union all
select 42, ‘A’,’02/16/2011′
union all
select 43, ‘A’, ’12/17/2010′
union all
select 44, ‘A’, ’07/28/2010′
union all
select 44, ‘B’, ’08/10/2010′
union all
select 44, ‘A’, ’01/11/2011′
union all
select 44, ‘B’, ’01/28/2011′
union all
select 44, ‘C’, ’10/14/2010′
union all
select 44, ‘D’, ’10/26/2010′
Select ‘Original Data’ Comment
,*
from #Temp_Table
/*
This would be Actual Script to get the New ID based on information you provided
*/
Declare #Count int
,#C_ID int
,#C_Rank char(1)
,#total_Count int
,#Count_Partition int
,#Previous_ID int
Declare #Table Table (ID int IDENTITY(1,1), C_ID int, C_Rank char(1), Date datetime, NewColumn int )
Set #Count = 1
Set #Count_Partition = 0
insert into #Table
Select *
from #Temp_Table
Select #total_Count = ISNULL(MAX(ID),0)
from #Table
While #Count < = #total_Count
Begin
Select #C_ID = C_ID
,#C_Rank = C_Rank
From #Table
Where ID = #Count
If #Count = 1
Set #Previous_ID = #C_ID
If #Previous_ID != #C_ID
Set #Count_Partition = 1
Else If #C_Rank = 'A'
Set #Count_Partition = #Count_Partition + 1
update #Table
Set NewColumn = #Count_Partition
Where ID = #Count
Set #Previous_ID = #C_ID
Set #Count = #Count + 1
End
Select C_ID
, C_Rank
, [Date]
, NewColumn
from #Table
–Drop table #Temp_Table