Oracle 10g sql query - sql

I have some data like this ↓
T_ID T_PERIOD T_COUNT T_SUM T_UPDATE_COUNT
1 2013-2014 3436 20118043 0
2 2014-2015 4298 27101356 0
3 2015-2016 5577 38844640 0
4 2016-2017 5764 40701339 0
5 2017-2018 6997 54316874 0
6 2018-2019 13315 151012820 0
7 2019-2020 13933 162731044 0
8 2018-2019 13300 150000000 1
9 2013-2014 3600 21000000 1
10 2018-2019 13500 155000000 2
This table only has insert,during insert T_UPDATE_COUNT = max(T_UPDATE_COUNT) + 1 ;
I want the data to look like this ↓
T_ID T_PERIOD T_COUNT T_SUM T_UPDATE_COUNT
9 2013-2014 3600 21000000 1
2 2014-2015 4298 27101356 0
3 2015-2016 5577 38844640 0
4 2016-2017 5764 40701339 0
5 2017-2018 6997 54316874 0
10 2018-2019 13500 155000000 2
7 2019-2020 13933 162731044 0
How do i write SQL statement ?

Assuming that you need to get all the rows with the maximum value of T_UPDATE_COUNT for each T_PERIOD , you may try:
select T_ID, T_PERIOD, T_COUNT, T_SUM, T_UPDATE_COUNT
from
(
select T_ID, T_PERIOD, T_COUNT, T_SUM, T_UPDATE_COUNT,
row_number() over (partition by T_PERIOD order by T_UPDATE_COUNT desc) as RN
from yourData x
)
where RN = 1
There are different ways to do this; I believe this one is clear enough: the inner query is used to compute the row number in the set of all the rows with the same value of T_PERIOD (partition by T_PERIOD) and name it RN.
The external one simply filters this result to only get the first rows (RN = 1) of each group.

Related

Need YTD and MTD calculations in SQL

Date Amt ytd mtd
01-Jan-21 1 2 2
01-Jan-21 1 2 2
02-Jan-21 1 3 3
03-Jan-21 1 4 4
01-Feb-21 1 5 1
02-Feb-21 1 6 2
03-Feb-21 1 7 3
04-Feb-21 1 8 4
05-Feb-21 1 9 5
01-Mar-21 1 10 1
02-Mar-21 1 11 2
03-Mar-21 1 12 3
04-Mar-21 1 13 4
01-Apr-21 1 14 1
02-Apr-21 1 15 2
03-Apr-21 1 16 3
01-May-21 1 17 1
02-May-21 1 18 2
03-May-21 1 19 3
04-May-21 1 20 4
05-May-21 1 21 5
06-May-21 1 22 6
I have the first two columns (Date, Amt) and i need the YTD and MTD columns in MS SQL so that i can show the above table.
Seems like a rolling COUNT OVER was used to calculate the ytd & mtd in the Oracle source.
(Personally, I would prefere RANK or DENSE_RANK)
And since Oracle datestamps can be casted to a DATE as-is.
SELECT [Date], Amt
, ytd = COUNT(*) OVER (ORDER BY CAST([Date] AS DATE))
, mtd = COUNT(*) OVER (PARTITION BY EOMONTH(CAST([Date] AS DATE)) ORDER BY CAST([Date] AS DATE))
FROM your_table
ORDER BY CAST([Date] AS DATE)
Date
Amt
ytd
mtd
01-Jan-21
1
2
2
01-Jan-21
1
2
2
02-Jan-21
1
3
3
03-Jan-21
1
4
4
01-Feb-21
1
5
1
02-Feb-21
1
6
2
03-Feb-21
1
7
3
04-Feb-21
1
8
4
05-Feb-21
1
9
5
db<>fiddle here

Distinguish the first rows where a given column's value changes in a grouped result

I want to create a select query in SQL Server where I group the rows by a column (BaseId) and also order them by Status, RTime and Version. I want to add a column "isFirst" that has the value 1 if the BaseId value is the first in the group, and 0 if it's not.
My sample table:
Table name: Head
Id BaseId Name RTime Status Version
2 2 abc 04-12 12:34 1 1
3 3 xyz 04-12 13:10 9 1
4 2 abc 04-13 14:25 0 2
5 3 xyz 04-14 12:34 0 2
6 3 xyz 04-14 13:10 9 3
7 3 xyz 04-16 14:25 1 4
8 2 abc 04-16 17:40 1 3
9 9 sql 04-17 02:23 9 1
10 9 sql 04-17 07:31 0 2
Expected result:
isFirst Id BaseId Name RTime Status Version
1 10 9 sql 04-17 07:31 0 2
0 9 9 sql 04-17 02:23 9 1
1 5 3 xyz 04-14 12:34 0 2
0 7 3 xyz 04-16 14:25 1 4
0 6 3 xyz 04-14 13:10 9 3
0 3 3 xyz 04-12 13:10 9 1
1 4 2 abc 04-13 14:25 0 2
0 8 2 abc 04-16 17:40 1 3
0 2 2 abc 04-12 12:34 1 1
My query now looks like this:
SELECT *
FROM Head
ORDER BY BaseId desc, Status, RTime desc, Version desc
I think I should use CASE to create the isFirst column, but I've had no luck so far. Anyone could help me?
You can use row_number() and a case expression:
select
case when row_number() over(
partition by BaseId
order by Status, RTime desc, Version desc
) = 1
then 1
else 0
end isFirst,
h.*
from head h
order by BaseId desc, Status, RTime desc, Version desc

Restart Row Number Based on Date and Increments of N

I have a table with the following data that I generated with a date table
date day_num (DAY_NUM % 7)
2019-07-09 0 0
2019-07-10 1 1
2019-07-11 2 2
2019-07-12 3 3
2019-07-13 4 4
2019-07-14 5 5
2019-07-15 6 6
2019-07-16 7 0
I basically want to get a week number that restarts at 0 and I need help figuring out the last part
The final output would look like this
date day_num (DAY_NUM % 7) week num
2019-07-09 0 0 1
2019-07-10 1 1 1
2019-07-11 2 2 1
2019-07-12 3 3 1
2019-07-13 4 4 1
2019-07-14 5 5 1
2019-07-15 6 6 1
2019-07-16 7 0 2
This is the sql I have so far
select
SUB.*,
DAY_NUM%7
FROM(
SELECT
DISTINCT
id_date,
row_number() over(order by id_date) -1 as day_num
FROM schema.date_tbl
WHERE Id_date BETWEEN "2019-07-09" AND date_add("2019-07-09",146)
Building on your query:
select SUB.*, DAY_NUM%7,
DENSE_RANK() OVER (ORDER BY FLOOR(DAY_NUM / 7)) as weeknum
FROM (SELECT DISTINCT id_date,
row_number() over(order by id_date) -1 as day_num
FROM schema.date_tbl
WHERE Id_date BETWEEN "2019-07-09" AND date_add("2019-07-09", 146)
) x

Extract first ocurrence of an item in column A based on column B using SQL

I have the following data, and I would like to create a result set that includes the rows that are the change in Item and the first ocurrence of Code == 1. Note that the first Code seen after a chnage in Item does not always have to be 1 (see the *):
The input data:
DateTime Item Code
*2016-12-02 16:34:00 1 1
2016-12-02 16:35:00 1 4
2016-12-02 16:36:00 1 1
2016-12-02 16:37:00 1 1
2016-12-02 16:38:00 1 7
2016-12-02 16:39:00 1 5
2016-12-02 16:40:00 1 6
2016-12-02 16:41:00 2 5
*2016-12-02 16:42:00 2 1
2016-12-02 16:43:00 2 4
2016-12-02 16:44:00 2 1
2016-12-02 16:45:00 2 5
2016-12-02 16:46:00 2 8
2016-12-02 16:47:00 2 1
2016-12-02 16:48:00 5 7
2016-12-02 16:49:00 5 7
*2016-12-02 16:50:00 5 1
2016-12-02 16:51:00 5 1
2016-12-02 16:52:00 5 4
2016-12-02 16:53:00 5 3
*2016-12-02 16:54:00 1 1
2016-12-02 16:55:00 1 1
2016-12-02 16:56:00 1 1
2016-12-02 16:57:00 1 8
2016-12-02 16:58:00 1 9
2016-12-02 16:59:00 1 3
2016-12-02 17:00:00 1 2
2016-12-02 17:01:00 1 4
Expected output data:
DateTime Item Code
*2016-12-02 16:34:00 1 1
*2016-12-02 16:42:00 2 1
*2016-12-02 16:50:00 5 1
*2016-12-02 16:54:00 1 1
I am using SQL Server 2012 Express. If anyone has recommendations of a good reference to learn these things, that would be great too.
You can use difference of ROW_NUMBERs to get the determine where the value of Item has changed and then another ROW_NUMBER from that to get the first occurrence of Code = 1:
WITH CteGrp AS(
SELECT *,
grp = ROW_NUMBER() OVER(ORDER BY Datetime) -
ROW_NUMBER() OVER(PARTITION BY Item ORDER BY Datetime)
FROM #Tbl
),
Cte AS(
SELECT *,
rn = ROW_NUMBER() OVER(PARTITION BY Item, grp ORDER BY Code, Datetime)
FROM CteGrp
)
SELECT
Datetime, Item, Code
FROM Cte
WHERE rn = 1
ORDER BY Datetime;
ONLINE DEMO
The first CTE is a common solution to Grouping Islands of Contiguous Dates. Here is an article by Jeff Moden for explanation:
Group Islands of Contiguous Dates (SQL Spackle)
WITH cte AS (
SELECT
[DateTime]
, Item
, Code
, ROW_NUMBER() OVER (PARTITION BY Item ORDER BY [DateTime]) AS RowNum
)
SELECT
[DateTime]
, Item
, Code
FROM
cte
WHERE
RowNum = 1
AND Code = 1;
Try this
select min( dateTime) dateTime, item, code from (
select dateTime, item, code from theTableName where code = 1
) code_1s
group by item, code
EDIT
To get every instance of an item where a new sequence has started .. and code = 1 is the flag for the new sequence instance ... it is a simple select statement with a where clause.
select dateTime, item, code from theTableName where code = 1

T-SQL recursion

I have a set of data that looks like below
Name Time Perc Group Mode Control Cancelled
A 10:52 10.10 10 0 1 0
B 09:00 10.23 10 1 1 1
C 12:02 12.01 12 0 1 1
D 10:45 12.12 12 1 7 1
E 12:54 12.56 12 1 3 0
F 01:01 13.90 13 0 11 1
G 02:45 13.23 13 1 12 1
H 09:10 13.21 13 1 1 0
I need an output like below;
Group Perc Cancelled
10 20.33 1
12 36.69 2
13 40.34 2
What I'm getting was something like;
Group Perc Cancelled
10 20.33 5
12 36.69 5
13 40.34 5
I don't know what to call this, I have something in my mind to call it like CTE?, but I really can't figure it out.
Here's my source;
SELECT Group, SUM(Perc), Cancelled FROM
(SELECT Group, Perc, (SELECT COUNT(*) FROM tblName WHERE Cancelled=1) AS Cancelled FROM tblName WHERE 1=1 AND Group>=10)dt
GROUP BY Group, Cancelled
From your example, you don't need the nested query, any recursion, etc...
SELECT
Group,
SUM(Perc) AS total_perc,
SUM(cancelled) AS total_cancelled
FROM
tblName
WHERE
1=1
AND Group >= 10
GROUP BY
Group
If you did have some different data, then you might want to use something like...
SUM(CASE WHEN cancelled > 0 THEN 1 ELSE 0 END) AS total_cancelled