Oracle 10g to know the timedifference between two rows in one table - oracle-sqldeveloper

requestid Date
2 12/22/2016 23:21
3 12/22/2016 23:21
1 12/22/2016 23:21
37 12/22/2016 23:20
156 12/22/2016 23:20
Could someone please help I want to know the time Difference between requestid 1 and 156?
I have tried the below query but not getting the proper output.
Select A.IFCOMPONENTUID,A.FPROCSTAGESTARTDT, (A.FPROCSTAGESTARTDT - B.FPROCSTAGESTARTDT) AS timedifference from XA_CASA.CFX_FILE_PROC_STAT A
where INNER JOIN XA_CASA.CFX_FILE_PROC_STAT B On A.IFCOMPONENTUID = (B.IFCOMPONENTUID + 155) and
order by FILERUNTIMEUID desc

similar to your construct...
SELECT
A.IFCOMPONENTUID,
A.FPROCSTAGESTARTDT,
B.IFCOMPONENTUID CompareID
(A.FPROCSTAGESTARTDT - B.FPROCSTAGESTARTDT) TimeDiff
FROM XA_CASA.CFX_FILE_PROC_STAT A
INNER JOIN XA_CASA.CFX_FILE_PROC_STAT B
ON A.IFCOMPONENTUID = (B.IFCOMPONENTUID + 155)
WHERE A.IFCOMPONENTUID = 1
I would prefer having explicit IDs in the where clause for more flexibility to change IDs:
SELECT
A.IFCOMPONENTUID,
A.FPROCSTAGESTARTDT,
B.IFCOMPONENTUID CompareID,
(A.FPROCSTAGESTARTDT - B.FPROCSTAGESTARTDT) TimeDiff
FROM XA_CASA.CFX_FILE_PROC_STAT A
INNER JOIN XA_CASA.CFX_FILE_PROC_STAT B
ON 1 = 1
WHERE A.IFCOMPONENTUID = 1
AND B.IFCOMPONENTUID = 156

Related

Getting data from alternate dates of same ID column

I've a table data as below, now I need to fetch the record with in same code, where (Value2-Value1)*2 of one row >= (Value2-Value1) of consequtive date row. (all dates are uniform with in all codes)
---------------------------------------
code Date Value1 Value2
---------------------------------------
1 1-1-2018 13 14
1 2-1-2018 14 16
1 4-1-2018 15 18
2 1-1-2019 1 3
2 2-1-2018 2 3
2 4-1-2018 3 7
ex: output needs to be
1 1-1-2018 13 14
as I am begginer to SQL coding, tried my best, but cannot get through with compare only on consequtive dates.
Use a self join.
You can specify all the conditions you've listed in the ON clause:
SELECT T0.code, T0.Date, T0.Value1, T0.Value2
FROM Table As T0
JOIN Table As T1
ON T0.code = T1.code
AND T0.Date = DateAdd(Day, 1, T1.Date)
AND (T0.Value2 - T0.Value1) * 2 >= T1.Value2 - T1.Value1

PostgreSQL non-overlapping ranges

I use PostgreSQL database and have a cards table.
Each record(card) in this table have card_drop_rate integer value.
For example:
id | card_name |card_drop_rate
-------------------------------
1 |card1 |34
2 |card2 |16
3 |card3 |54
max drop rate is 34 + 16 + 54 = 104.
In accordance to my application logic I need to find a random value between 0 and 104 and then retrieve card according to this number, for example:
random value: 71
card1 range: 0 - 34(0 + 34)
card2 range: 34 - 50(34 + 16)
card3 range: 50 - 104(50 + 54)
So, my card is card3 because 71 is placed in the range 50 - 104
What is the proper way to reflect this structure in PostgreSQL ? I'll need to query this data often under so the performance is a criterion number one for this solution.
Following query works fine:
SELECT
b.id,
b.card_drop_rate
FROM (SELECT a.id, sum(a.card_drop_rate) OVER(ORDER BY id) - a.card_drop_rate as rate, card_drop_rate FROM cards as a) b
WHERE b.rate < 299 ORDER BY id DESC LIMIT 1
You can do this using cumulative sums and random. The "+ 1"s might be throwing me off, but it is something like this:
with c as (
select c.*,
sum(card_drop_rate + 1) - card_drop_rate as threshhold
from cards c
),
r as (
select random() * (sum(card_drop_rate) + count(*) - 1) as which_card
from cards c
)
select c.*
from c cross join
r
where which_card >= threshhold
order by threshhold
limit 1;
For performance, I would simply take the cards and generate a new table with 106 slots. Assign the card value to the slots and build an index on the slot number. Then get a value using:
select s.*
from slots s
where s.slotid = floor(random() * 107);

Column of counts for time intervals

I want to get a table that constructs a column that tracks how many times an id appears in a given week. If the id appears once it is given a 1, if it appears twice it is given a 2, but if it appears more than two times it is given a 0.
id date
a 2015-11-10
a 2015-11-25
a 2015-11-09
b 2015-11-10
b 2015-11-09
a 2015-11-05
b 2015-11-23
b 2015-11-28
b 2015-12-04
a 2015-11-10
b 2015-12-04
a 2015-12-07
a 2015-12-09
c 2015-11-30
a 2015-12-06
c 2015-10-31
c 2015-11-04
b 2015-12-01
a 2015-10-30
a 2015-12-14
the one week intervals are given as follows
1 - 2015-10-30 to 2015-11-05
2 - 2015-11-06 to 2015-11-12
3 - 2015-11-13 to 2015-11-19
4 - 2015-11-20 to 2015-11-26
5 - 2015-11-27 to 2015-12-03
6 - 2015-12-04 to 2015-12-10
7 - 2015-12-11 to 2015-12-17
The table should look like this.
id interval count
a 1 2
b 1 0
c 1 2
a 2 0
b 2 2
c 2 0
a 3 0
b 3 0
c 3 0
a 4 1
b 4 1
c 4 0
a 5 0
b 5 2
c 5 1
a 6 0
b 6 2
c 6 0
a 7 1
b 7 0
c 7 0
The interval column doesn't have to be there, I simply added it for clarity.
I am new to sql and am unsure how to break the dates into intervals. The only thing I have is grouping by date and counting.
Select id ,date, count (*) as frequency
from data_1
group by id, date having frequency <= 2;
Looking at just the data you provided, this does the trick:
SELECT v.id,
i.interval,
coalesce((CASE WHEN sub.cnt < 3 THEN sub.cnt ELSE 0 END), 0) AS count
FROM (VALUES('a'), ('b'), ('c')) v(id)
CROSS JOIN generate_series(1, 7) i(interval)
LEFT JOIN (
SELECT id, ((date - '2015-10-30')/7 + 1)::int AS interval, count(*) AS cnt
FROM my_table
GROUP BY 1, 2) sub USING (id, interval)
ORDER BY 2, 1;
A few words of explanation:
You have three id values which are here recreated with a VALUES clause. If you have many more or don't know beforehand which id's to enumerate, you can always replace the VALUES clause with a sub-query.
You provide a specific date range over 7 weeks. Since you might have weeks where a certain id is not present you need to generate a series of the interval values and CROSS JOIN that to the id values above. This yields the 21 rows you are looking for.
Then you calculate the occurrences of ids in intervals. You can subtract a date from another date which will give you the number of days in between. So subtract the date of the row from the earliest date, divide that by 7 to get the interval period, add 1 to make the interval 1-based and convert to integer. You can then convert counts of > 2 to 0 and NULL to 0 with a combination of CASE and coalesce().
The query outputs the interval too, otherwise you will have no clue what the data refers to. Optionally, you can turn this into a column which shows the date range of the interval.
More flexible solution
If you have more ids and a larger date range, you can use the below version which first determines the distinct ids and the date range. Note that the interval is now 0-based to make calculations easier. Not that it matters much because instead of the interval number, the corresponding date range is displayed.
WITH mi AS (
SELECT min(date) AS min, ((max(date) - min(date))/7)::int AS intv FROM my_table)
SELECT v.id,
to_char((mi.min + i.intv * 7)::timestamp, 'YYYY-mm-dd') || ' - ' ||
to_char((mi.min + i.intv * 7 + 6)::timestamp, 'YYYY-mm-dd') AS period,
coalesce((CASE WHEN sub.cnt < 3 THEN sub.cnt ELSE 0 END), 0) AS count
FROM mi,
(SELECT DISTINCT id FROM my_table) v
CROSS JOIN LATERAL generate_series(0, mi.intv) i(intv)
LEFT JOIN LATERAL (
SELECT id, ((date - mi.min)/7)::int AS intv, count(*) AS cnt
FROM my_table
GROUP BY 1, 2) sub USING (id, intv)
ORDER BY 2, 1;
SQLFiddle with both solutions.
Assuming you have a table of all users, this will do the trick.
select
users.id,
interval_table.id,
CASE
WHEN count(log_table.user_id)>2 THEN 0
ELSE count(log_table.user_id)
END
from users
cross join interval_table
left outer join log_table
on users.id = log_table.user_id
and log_table.event_date >= interval_table.start_interval
and log_table.event_date < interval_table.stop_interval
group by users.id, interval_table.id
order by interval_table.id, users.id
Check it out: http://sqlfiddle.com/#!15/1a822/21

SQL - Select max week from a group

I need to be able to get a result set which shows the last teacher for a course, for which I have the following SQL query:
SELECT
a.acad_period, MAX(a.start_week) as start_week,
a.staff_code, b.aos_code, b.aos_period
FROM
qlsdat.dbo.sttstaff a
INNER JOIN
qlsdat..sttrgaos b ON a.acad_period = b.acad_period
AND a.register_id = b.register_id
AND a.register_group = b.register_group
WHERE
a.acad_period = '14/15'
GROUP BY
a.acad_period, a.staff_code, b.aos_code, b.aos_period
However, the issue is that it returns to me the maximum start week for a teacher on that course, whereas I want the maximum start week for a course, and the teacher that happens to be teaching for that start week.
Here is a sample result set returned from the above query:
14/15 37 HKARUNATHIL A2ES 001A
14/15 37 CSHUKLA A2ES 001B
14/15 37 PSEDOV A2ES 002A
14/15 37 BBANFIELD A2ES 002B
14/15 14 VKRISHNASWA A2EX BL1 X
14/15 14 VKRISHNASWA A2EX BL2 X
14/15 6 BODAMEKENTO ACA2 BL1 A
14/15 41 SKLER ACA2 BL1 A
14/15 44 BODAMEKENTO ACAS BL1 F
14/15 37 MMILLER ARA2 BL1 C
14/15 45 MMILLER ARAS BL1 E
14/15 44 SHOULTON ARAS BL1 E
Here is an example of the problem within the result set:
14/15 10 HMALIK MMGX GB2F3
14/15 44 JMULLANEY MMGX GB2F3
In the above example I only want:
14/15 44 JMULLANEY MMGX GB2F3
The query produced is going to be used as a subquery in another query.
This will get the row for highest start_week, however you may encounter some problems if you have data from more than 1 year, this can be resolved by putting your your field in addition to your week column in this part
row_number() over (partition by
a.acad_period, b.aos_code, b.aos_period
order by
a.start_year desc,
a.start_date desc) rn
Query:
;WITH CTE AS
(
SELECT
a.acad_period, a.start_week,
a.staff_code, b.aos_code, b.aos_period,
row_number() over (partition by
a.acad_period, b.aos_code,
b.aos_period
order by a.start_week desc) rn
FROM
qlsdat.dbo.sttstaff a
INNER JOIN
qlsdat..sttrgaos b ON a.acad_period = b.acad_period
AND a.register_id = b.register_id
AND a.register_group = b.register_group
WHERE
a.acad_period = '14/15'
)
SELECT
acad_period, start_week,
staff_code, aos_code, aos_period,
FROM CTE
WHERE rn = 1

t-sql subquery and groupby

Under the my query.I select this way all job count by fullname.
SELECT COUNT(sy.FullName) [Count Job],
sy.FullName [FullName],
MIN(CAST(i.vrp_notificationdate AS DATE)) [Oldest Date]
FROM BusinessUnit AS b
INNER JOIN SystemUser AS sy
ON b.BusinessUnitId = sy.BusinessUnitId
INNER JOIN Incident AS i
ON i.OwnerId = sy.SystemUserId
GROUP BY f.sy.FullName
This query show this table
---------------------------------
Count Job FullName Oldest Date
10 a 2011-10-11
20 B 2011-10-11
55 C 2011-10-11
---------------------------------
But i want to make under table for example.
--------------------------------------------------------------
Count Job FullName Oldest Date Open Job Close Job
10 A 2011-10-11 5 5
20 B 2011-10-11 13 7
55 C 2011-10-11 48 7
------------------------------------------------------------
I have status of columnname on my Incident Table,if status code is 5 that the job is closed.when i used group by condition statuscode,then table is under .And i dont want show this showing table.
---------------------------------
Count Job FullName Oldest Date
10 a 2011-10-11
13 B 2011-10-11
48 C 2011-10-11
7 B 2011-10-11
7 C 2011-10-11
---------------------------------
when i use union on my t-sql,i take this error "all queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists."
how to exactly solve this query.Any suggestion.
Thanks.
How about using CASE and SUM?
SELECT COUNT(sy.FullName) [Count Job],
sy.FullName [FullName],
MIN(CAST(i.vrp_notificationdate AS DATE)) [Oldest Date],
SUM(CASE i.status
WHEN 5 THEN 1
ELSE 0) [Open Jobs],
SUM(CASE i.status
WHEN 5 THEN 0
ELSE 1) [Closed Jobs]
FROM BusinessUnit AS b
INNER JOIN SystemUser AS sy
ON b.BusinessUnitId = sy.BusinessUnitId
INNER JOIN Incident AS i
ON i.OwnerId = sy.SystemUserId
GROUP BY f.sy.FullName