A user gave me a table that looks like the following.
Name HH08 HH09 HH10 HH11 HH12 HH13
Bob 2 3 4 2 7 1
Steve 2 9 3 2 2 5
Mike 2 2 2 2 3 2
Pat 1 0 2 0 0 0
I need some sql that will select the row based on the name, and the column based on the current hour of sysdate when the query is run.
If it is 9:27 am and the user is Steve, the sql needs to select the 9 value.
Is there any simple sql that will do this, or do I need to restructure the table the user gives me, which will be occassionally.
Thanks in advance.
Try:
select case to_char(sysdate,'hh24')
when '08' then hh08
when '09' then hh09
when '10' then hh10
when '11' then hh11
when '12' then hh12
when '13' then hh13
end OutputValue
from TableName
WHERE Name = 'Steve'
SELECT 'HH'+convert(char(2),DATEPART(hour,getdate()))
FROM TableName
WHERE Name = 'Steve'
try this out
with t as (
select 'Bob' name, 2 hh08, 3 hh09, 4 hh10, 2 hh11, 7 hh12, 1 hh13 from dual union all
select 'Steve', 2, 9, 3, 2, 2, 5 from dual union all
select 'Mike', 2, 2, 2, 2, 3, 2 from dual union all
select 'Pat', 1, 0, 2, 0, 0, 0 from dual
)
--/\-- Data sample --/\--
select value from t
unpivot(value for hr in (hh08 as '08', hh09 as '09', hh10 as '10', hh11 as '11', hh12 as '12', hh13 as '13') )
where hr = to_char(sysdate, 'HH24')
and name = 'Pat';
Related
I am trying to formulate a query in Oracle DB such that it computes the start_date value for the rows having it as null based on the numoddays , lvl (level), and the previous level's start_date column.
For an example:
Linenumber 3 and item 123:
Start_date = Start_date of previous level (2) + numofdays of current row
i.e Start_date = 03-FEB-23 01:54:00 PM + 1 = 04-FEB-23 01:54:00 PM
Notice that the non-null start date can be any arbitrary date and we have to compute the subsequent null rows for that item and the trailing non-null start_date wont follow the same pattern
ie Start_date of line number 2 is 03-FEB-23 01:54:00 PM which is not equal to 24-JAN-23 01:54:00 PM + 2 (from line number 2)
Sample table code:
select 1 LineNumber, 123 item, 1 lvl, 2 numofdays, sysdate start_date from dual
union all
select 2 , 123 , 2, 2, sysdate + 10 from dual
union all
select 3 , 123 , 3, 1, null from dual
union all
select 4 , 123 , 4, 3, null from dual
union all
select 5 , 123 , 5, 2, null from dual
union all
select 6 , 345 , 1, 1, sysdate+2 from dual
union all
select 7 , 345 , 2, 2, null from dual
union all
select 8 , 345 , 3, 1, null from dual
Desired Result:
select 1 LineNumber, 123 item, 1 lvl, 2 numofdays, sysdate start_date from dual
union all
select 2 , 123 , 2, 2, sysdate + 10 from dual
union all
select 3 , 123 , 3, 1, sysdate +10 +1 from dual
union all
select 4 , 123 , 4, 3, sysdate +10 +1+3 from dual
union all
select 5 , 123 , 5, 2, sysdate +10 +3+1+2 from dual
union all
select 6 , 345 , 1, 1, sysdate+2 from dual
union all
select 7 , 345 , 2, 2, sysdate +2 +2 from dual
union all
select 8 , 345 , 3, 1, sysdate +2 +2+1 from dual
Any help would be greatly appreciated
This is an ideal case for using MODEL clause. Your instruction to "... compute the start_date value for the rows having it as null based on the numoddays , lvl (level), and the previous level's start_date column." could be modeled just like that:
Select LINE_NUM, ITEM, LVL, NUM_OF_DAYS, START_DATE
From tbl
MODEL Partition By (ITEM)
Dimension By (LVL)
Measures (LINE_NUM, NUM_OF_DAYS, START_DATE)
Rules ( START_DATE[ANY] = CASE WHEN START_DATE[CV()] Is Not Null
THEN START_DATE[CV()]
ELSE START_DATE[CV() -1 ] + NUM_OF_DAYS[CV()] END )
In this case modeling is partitioned by ITEM column saying that for ANY (Dimension) LVL the START_DATE which Is Not Null stays as it is in that LVL (CV() - Current Value of LVL) and ELSE when START_DATE Is Null then take the date from previous LVL ( CV()-1 ) and add NUM_OF_DAYS from current LVL.
With Your sample data:
WITH
tbl (LINE_NUM, ITEM, LVL, NUM_OF_DAYS, START_DATE) AS
(
Select 1, 123 , 1, 2, SYSDATE From Dual Union All
Select 2, 123 , 2, 2, SYSDATE + 10 From Dual Union All
Select 3, 123 , 3, 1, null From Dual Union All
Select 4, 123 , 4, 3, null From Dual Union All
Select 5, 123 , 5, 2, null From Dual Union All
Select 6, 345 , 1, 1, SYSDATE+2 From Dual Union All
Select 7, 345 , 2, 2, null From Dual Union All
Select 8, 345 , 3, 1, null From Dual
)
... the result would be:
LINE_NUM ITEM LVL NUM_OF_DAYS START_DATE
---------- ---------- ---------- ----------- ----------
1 123 1 2 24-JAN-23
2 123 2 2 03-FEB-23
3 123 3 1 04-FEB-23
4 123 4 3 07-FEB-23
5 123 5 2 09-FEB-23
6 345 1 1 26-JAN-23
7 345 2 2 28-JAN-23
8 345 3 1 29-JAN-23
From Oracle 12, you can use MATCH_RECOGNIZE for row-by-row pattern matching:
SELECT LineNumber,
item,
lvl,
numofdays,
first_start_date + COALESCE(total_days, 0) AS start_date
FROM table_name
MATCH_RECOGNIZE(
PARTITION BY item
ORDER BY lvl
MEASURES
FIRST(start_date) AS first_start_date,
SUM(null_start_date.numofdays) AS total_days
ALL ROWS PER MATCH
PATTERN (not_null_start_date null_start_date*)
DEFINE
not_null_start_date AS start_date IS NOT NULL,
null_start_date AS start_date IS NULL
)
Which, for the sample data:
CREATE TABLE table_name (LineNumber, item, lvl, numofdays, start_date) AS
select 1, 123, 1, 2, sysdate from dual union all
select 2, 123, 2, 2, sysdate + 10 from dual union all
select 3, 123, 3, 1, null from dual union all
select 4, 123, 4, 3, null from dual union all
select 5, 123, 5, 2, null from dual union all
select 6, 345, 1, 1, sysdate+2 from dual union all
select 7, 345, 2, 2, null from dual union all
select 8, 345, 3, 1, null from dual;
Outputs:
LINENUMBER
ITEM
LVL
NUMOFDAYS
START_DATE
1
123
1
2
2023-01-24 18:23:54
2
123
2
2
2023-02-03 18:23:54
3
123
3
1
2023-02-04 18:23:54
4
123
4
3
2023-02-07 18:23:54
5
123
5
2
2023-02-09 18:23:54
6
345
1
1
2023-01-26 18:23:54
7
345
2
2
2023-01-28 18:23:54
8
345
3
1
2023-01-29 18:23:54
fiddle
I have some data in table like:
CSF
ID
seqNum
Data
rs_id
1
14176159
1
ABC
0x000055.0001882a.017c
1
14176160
2
DEF
0x000055.0001882c.0010
1
14176161
3
GHI
0x000055.0001882d.00ac
1
14176162
4
JKL
0x000055.0001882d.0164
0
14176163
5
MNO
0x000055.0001882f.001c
0
14176163
1
ABC
0x000055.0001882f.00d4
1
14176164
1
ABC
0x000055.00018830.0144
1
14176165
2
DEF
0x000055.00018831.0010
1
14176166
3
GHI
0x000055.00018832.00e4
1
14176166
4
JKL
0x000055.00018832.019c
0
14176167
5
MNO
0x000055.00018834.001c
I want to execute select in a way to obtain the result as:
CSF
ID
seqNum
Data
rs_id
0
14176159
5
ABCDEFGHIJKLMNO
0x000055.0001882f.001c
0
14176163
1
ABC
0x000055.0001882f.00d4
0
14176164
5
ABCDEFGHIJKLMNO
0x000055.00018834.001c
So the logic should work like:
whenever CSF encountered is 1, we need to append data column until CSF is 0.
In the result, the ID should be of the record where CSF was first encountered as 1.
In the result, the SeqNum and rs_id should be of the record where CSF is 0.
So in short, CSF 1 indicates that data column is appended in next record and 0 indicates that the data column is not further split in to records and is an independent record.
From Oracle 12, you can use MATCH_RECOGNIZE to perform row-by-row processing:
SELECT MIN(last_csf) AS csf,
MIN(first_id) AS id,
MIN(last_seqnum) AS seqnum,
LISTAGG(data) WITHIN GROUP (ORDER BY seqnum) AS data,
MIN(last_rs_id) AS rs_id
FROM table_name
MATCH_RECOGNIZE(
ORDER BY id, seqnum
MEASURES
LAST(csf) AS last_csf,
FIRST(id) AS first_id,
LAST(seqNum) AS last_seqnum,
LAST(rs_id) AS last_rs_id,
MATCH_NUMBER() AS mno
ALL ROWS PER MATCH
PATTERN (one_csf* zero_csf)
DEFINE
one_csf AS csf = 1,
zero_csf AS csf = 0
)
GROUP BY mno
Which, for the sample data:
CREATE TABLE table_name (csf, id, seqNum, data, rs_id) AS
SELECT 1, 1, 1, 'ABC', '01' FROM DUAL UNION ALL
SELECT 1, 2, 2, 'DEF', '02' FROM DUAL UNION ALL
SELECT 1, 3, 3, 'GHI', '03' FROM DUAL UNION ALL
SELECT 1, 4, 4, 'JKL', '04' FROM DUAL UNION ALL
SELECT 0, 5, 5, 'MNO', '05' FROM DUAL UNION ALL
SELECT 0, 5, 1, 'ABC', '06' FROM DUAL UNION ALL
SELECT 1, 6, 1, 'ABC', '07' FROM DUAL UNION ALL
SELECT 1, 7, 2, 'DEF', '08' FROM DUAL UNION ALL
SELECT 1, 8, 3, 'GHI', '09' FROM DUAL UNION ALL
SELECT 1, 8, 4, 'JKL', '10' FROM DUAL UNION ALL
SELECT 0, 9, 5, 'MNO', '11' FROM DUAL;
Outputs:
CSF
ID
SEQNUM
DATA
RS_ID
0
1
1
ABCABCDEFGHIJKL
01
0
5
5
MNO
05
0
6
1
ABCDEFGHIJKLMNO
07
db<>fiddle here
In SQL, can someone help me understand what the query may look like if I'm trying to remove the red-highlighted rows from the image? Based on the logic I need, I need to remove records with different priority values within an option, where as the ones we want to keep have the same priority. Each item/cntry combination has it's own option values (typically 4 like you see here).
I feel like this is just a join to itself, but my mind is mush right now. Help would be appreciated!
You can use the analytic COUNT(DISTINCT ...) function and then you do not need to use a self-join:
SELECT *
FROM (
SELECT t.*,
COUNT(DISTINCT priority) OVER (PARTITION BY cntry, item, "OPTION")
AS cnt
FROM table_name t
)
WHERE cnt = 1;
Which, for the sample data:
CREATE TABLE table_name ("OPTION", priority, item, cntry) AS
SELECT 1, 1, 'ABCDEF', 'USA' FROM DUAL UNION ALL
SELECT 1, 1, 'ABCDEF', 'USA' FROM DUAL UNION ALL
SELECT 2, 2, 'ABCDEF', 'USA' FROM DUAL UNION ALL
SELECT 2, 1, 'ABCDEF', 'USA' FROM DUAL UNION ALL
SELECT 3, 1, 'ABCDEF', 'USA' FROM DUAL UNION ALL
SELECT 3, 2, 'ABCDEF', 'USA' FROM DUAL UNION ALL
SELECT 4, 2, 'ABCDEF', 'USA' FROM DUAL UNION ALL
SELECT 4, 2, 'ABCDEF', 'USA' FROM DUAL UNION ALL
SELECT 1, 1, 'HIJKLM', 'CAN' FROM DUAL UNION ALL
SELECT 2, 2, 'HIJKLM', 'CAN' FROM DUAL UNION ALL
SELECT 2, 2, 'HIJKLM', 'CAN' FROM DUAL UNION ALL
SELECT 2, 1, 'HIJKLM', 'CAN' FROM DUAL UNION ALL
SELECT 3, 1, 'HIJKLM', 'CAN' FROM DUAL UNION ALL
SELECT 3, 1, 'HIJKLM', 'CAN' FROM DUAL UNION ALL
SELECT 3, 1, 'HIJKLM', 'CAN' FROM DUAL UNION ALL
SELECT 4, 2, 'HIJKLM', 'CAN' FROM DUAL;
Outputs:
OPTION
PRIORITY
ITEM
CNTRY
CNT
1
1
HIJKLM
CAN
1
3
1
HIJKLM
CAN
1
3
1
HIJKLM
CAN
1
3
1
HIJKLM
CAN
1
4
2
HIJKLM
CAN
1
1
1
ABCDEF
USA
1
1
1
ABCDEF
USA
1
4
2
ABCDEF
USA
1
4
2
ABCDEF
USA
1
db<>fiddle here
use exists and distinct count()
select t1.* from table_name t1 where
exists (
select 1
from table_name t2
where t1.option=t2.option
group by option
having count (distinct priority)=1
)
Noob question. I'm writing a script to execute a report showing:
Student last name and first name (comma separated), years enrolled, academic advisor last name and first name (comma separated)
Sort: years enrolled
Filter: only include currently active students
Struggling with calculating years enrolled and filtering by active students.
The tables I'm using:
SELECT CONCAT(CONCAT(Student.Last_Name, ', '), Student.First_Name) AS "Student",
Student_Enrollment_Status.Date_Status_Updated,
CONCAT(CONCAT(Faculty.Last_Name, ', '), Faculty.First_Name) AS "Advisor"
FROM Student
WHERE Faculty.Faculty_ID = Student.Advisor_ID
AND Student(Student_ID) = Student_Enrollment_Status(Student_ID)
AND Student_Enrollment_Status(Status_ID) = Enrollment_Status (Status_ID);
It would be something like this:
lines #1 - 22 represent sample data (you don't type that)
query you need begins at line #24
years enrolled is calculated by subtracting current year and year of enrollment; that's rather inaccurate, but - you didn't explain what exactly it means
I presumed that active statuses are IDs (2, 3, 5)
SQL> with
2 student (student_id, first_name, last_name, advisor_id) as
3 (select 1, 'ash', 'smith', 9 from dual union all
4 select 2, 'tash', 'paul', 8 from dual union all
5 select 3, 'carl', 'wall', 6 from dual union all
6 select 4, 'fred', 'john', 3 from dual),
7 student_enrollment_status (student_id, status_id, date_status_updated) as
8 (select 1, 2, date '2017-09-04' from dual union all
9 select 2, 3, date '2018-09-05' from dual union all
10 select 3, 3, date '2018-09-05' from dual union all
11 select 4, 2, date '2019-09-04' from dual),
12 enrollment_status (status_id, status) as
13 (select 2, 'enrolled' from dual union all
14 select 3, 'on leave' from dual union all
15 select 4, 'full time' from dual union all
16 select 5, 'part time' from dual union all
17 select 6, 'withdrawn' from dual),
18 faculty (faculty_id, first_name, last_name) as
19 (select 9, 'jane', 'gold' from dual union all
20 select 8, 'sam', 'greene' from dual union all
21 select 6, 'mark', 'west' from dual union all
22 select 3, 'jen', 'dash' from dual)
23 --
24 select s.last_name ||', '|| s.first_name student,
25 extract(year from sysdate) - extract(year from ses.date_status_updated)
26 years_enrolled,
27 f.last_name ||', '|| f.first_name advisor
28 from student s join student_enrollment_status ses on ses.student_id = s.student_id
29 join enrollment_status es on es.status_id = ses.status_id
30 join faculty f on f.faculty_id = s.advisor_id
31 where es.status_id in (2, 3, 5)
32 order by years_enrolled;
STUDENT YEARS_ENROLLED ADVISOR
----------- -------------- ------------
john, fred 1 dash, jen
paul, tash 2 greene, sam
wall, carl 2 west, mark
smith, ash 3 gold, jane
SQL>
Imagine the following table
DEPARTURE_ID ARRIVE_ID ORDER
------------- --------- -----
1 3 1
2 3 2
3 (null) 3
10 12 1
11 13 2
12 15 3
13 15 4
14 15 5
15 (null) 6
25 27 1
26 27 2
27 (null) 3
I want to keep the departure_id(s) connected by the prior arrive_id(s)
In oracle11g, I do this
Sample Table
create table dep_arrives ( departureid, arrriveid, ord) as
select '1', '3', 1 from dual union all
select '2', '3', 2 from dual union all
select '3', null, 3 from dual union all
select '10', '12', 1 from dual union all
select '11', '13', 2 from dual union all
select '12', '15', 3 from dual union all
select '13', '15', 4 from dual union all
select '14', '15', 5 from dual union all
select '15', null, 6 from dual union all
select '25', '27', 1 from dual union all
select '26', '27', 2 from dual union all
select '27', null, 3 from dual
;
Select statement
select departureid
from dep_arrives
start with ord = 1
connect by departureid = prior arrriveid
Result
DEPARTURE_ID
1
3
10
12
15
25
27
I know there is no start with connect by in netezza so I'm looking for a workaround with netezza sql.
Thanks in advance.