I'd like to have a plsql request that count the number of row by date and the sum of row up to the date.
The source will be somethings like this (hundreds of dates):
2019.05.01
2019.05.01
2019.05.02
2019.05.03
2019.05.03
2019.05.03
...
and the result:
date nb sum
-------------------
2019.05.01 2 2
2019.05.02 1 3
2019.05.03 3 6
. . .
The key here is to use an Aggregate Function as an Analytical function which is what the SUM(COUNT(dt)) OVER (ORDER BY dt) in the query below is doing.
WITH dates AS
(
SELECT to_date('2019.05.01', 'YYYY.MM.DD') AS dt FROM dual UNION ALL
SELECT to_date('2019.05.01', 'YYYY.MM.DD') AS dt FROM dual UNION ALL
SELECT to_date('2019.05.02', 'YYYY.MM.DD') AS dt FROM dual UNION ALL
SELECT to_date('2019.05.03', 'YYYY.MM.DD') AS dt FROM dual UNION ALL
SELECT to_date('2019.05.03', 'YYYY.MM.DD') AS dt FROM dual UNION ALL
SELECT to_date('2019.05.03', 'YYYY.MM.DD') AS dt FROM dual
)
SELECT dt, COUNT(dt) AS nb, SUM(COUNT(dt)) OVER (ORDER BY dt) AS sum
FROM dates
GROUP BY dt
;
First half is relatively easy. Something like
SELECT date, count(*) from table GROUP BY date ORDER BY date;
But I'm not sure about the cumulative sum. If it's a manual process then I'd probably just import into Excel and do it there to be honest.
Related
An Oracle SQL question that seems simple to me, but I just can't do it (without manually making several successive queries)... I would like to use a SQL "recursive" approach or any other method that would avoid me to manually use "n" times the same query.
Here is a very simplified example of my data:
row
ID
Value
Result
1
135
AAA
AAA
2
246
BBB
BBB
3
357
135
AAA
4
468
357
AAA
5
578
EEE
EEE
If a value refers to an ID, then we need to fetch the value of that ID. If the value of an ID is another ID, then you have to keep looking for an "true" value. If the value is not an ID, then we can take it directly.
The column "Result" gives the expected result:
For the row 3, you have to look for the value of the ID 135.
For the line 4, you have to get the value of the ID 357, which corresponds to the value of the ID 135.
Here, what I don't want to do:
with my_data as(
select '135' as id, 'AAA' as value from dual union all
select '246', 'BBB' from dual union all
select '357', '135' from dual union all
select '468', '357' from dual union all
select '578', 'EEE' from dual
)
,step as(
select d1.*
,nvl((select d2.value from my_data d2 where d1.value=d2.id),d1.value) as step_1
from my_data d1
)
-- steps to do again and again...
select step.*
,nvl((select my_data.value from my_data where step.step_1=my_data.id),step.step_1) as step_n
from step
order by 1
;
Thank you for your help.
In addition to Carlos S anwser:
It does exactly what I want in my "very simplified" example. However, with a sub-set of real data, there is something wrong (a little too much data). On the other hand, if I remove the results that refer to IDs, it gives exactly what I want. I can't find the problem.
Note: as shown in my initial example, IDs will always start with a number and a "real" value will always start with a letter. So the regex strategy is "ok".
Here is a real example:
with my_data as(
select '116554226_2' as id, '116554226_1' as value from dual union all
select '119675285_2' as id, '119675285_1' as value from dual union all
select '119675285_3' as id, '119675285_2' as value from dual union all
select '13656777_1' as id, '119675471_1' as value from dual union all
select '13656777_5001' as id, '119675471_1' as value from dual union all
select '13656777_2' as id, '13656777_1' as value from dual union all
select '13656155_1' as id, '13657581_1' as value from dual union all
select '13657581_2' as id, '13657581_1' as value from dual union all
select '13657015_1' as id, '13657759_1' as value from dual union all
select '13657759_2' as id, '13657759_1' as value from dual union all
select '116554226_1' as id, '471502681_1' as value from dual union all
select '462721769_1' as id, 'O7X5J' as value from dual union all
select '471502681_1' as id, 'T3L8L' as value from dual union all
select '119675471_1' as id, 'T8Q0G' as value from dual union all
select '119675471_5001' as id, 'T8Q0G' as value from dual union all
select '116555133_1' as id, 'T9J2Q' as value from dual union all
select '13657581_1' as id, 'U5H5Z' as value from dual union all
select '119674049_1' as id, 'Y5G7V' as value from dual union all
select '13657759_1' as id, 'Z0Y9C' as value from dual union all
select '119675285_1' as id, 'Z7E0D' as value from dual
)
SELECT my_data.*, CONNECT_BY_ROOT value result
FROM my_data
CONNECT BY PRIOR id = value
START WITH REGEXP_LIKE(value,'[^0-9]')
;
The boxed data is unwanted, otherwise everything below it is ok.
I think this query may help you:
with my_data as(
select '135' as id, 'AAA' as value from dual union all
select '246', 'BBB' from dual union all
select '357', '135' from dual union all
select '468', '357' from dual union all
select '578', 'EEE' from dual
)
SELECT rownum, id, value, CONNECT_BY_ROOT value result
FROM my_data
CONNECT BY PRIOR id = value
START WITH REGEXP_LIKE(value,'[^0-9]')
ROWNUM
ID
VALUE
RESULT
1
135
AAA
AAA
2
357
135
AAA
3
468
357
AAA
4
246
BBB
BBB
5
578
EEE
EEE
I have these data
I want to do two rolling count:
Count by every (id,refund) by rolling. When it turns into different (id,refund) combination (even with the same id), it will start from 0
Count by every id by rolling.
I want the output to be as follow:
Can you help me to create the query?
I try this one but it fails...
SELECT
date,
id,
refund,
COUNT(CONCAT(id,refund)) OVER (PARTITION BY rn) AS count_id_refund,
COUNT(id) OVER (PARTITION BY rn) AS count_id
FROM table1
You can use row_number() function. Here is my query with some sample data
with sample as (
select 1 as id, TRUE as refund,
union all select 1, true
union all select 1, false
union all select 2,true
union all select 3,true
union all select 3, false
union all select 3, false
)
select id,refund,
row_number() over(partition by id order by id) as row_id,
row_number() over(partition by concat(id,refund) order by concat(id,refund)) as row_id_rf
from sample order by id,refund desc;
and the result is:
I have a table call PAYMENT_DET with the fields PAYMENT_DATE DATE, PAYMENT_TIME VARCHAR2 and its data is as shown below where date format is MM/DD/YYYY
PAYMENT_DATE PAYMENT_TIME
2/13/2017 13:03:59
2/13/2017 14:03:59
2/14/2017 01:03:59
2/14/2017 04:03:00
My requirement is, I have two input dates like from date with time and To Date with time. Between the given inputs range i want get details from the above table.
Please suggest me query for this.
A very simple example to help you out. Hope this helps.
SELECT *
FROM
(SELECT 1 col1, '02/13/2017' col2, '13:03:59' col3 FROM dual
UNION
SELECT 2 col1, '02/13/2017' col2, '14:03:59' col3 FROM dual
UNION
SELECT 3 col1, '02/14/2017' col2, '01:03:59' col3 FROM dual
)a
WHERE to_date(a.col2
||' '
||col3,'mM/dd/yyyy hh24:mi:ss') BETWEEN TO_DATE('01/01/2017 00:00:00','mm/dd/yyyy hh24:mi:ss') AND TO_DATE('01/01/2018 00:00:00','mm/dd/yyyy hh24:mi:ss');
If I query:
select max(date_created) date_created
on a datefield in PL/SQL (Oracle 11g), and there are records that were created on the same date but at different times, Max() returns only the latest times on that date. What I would like to do is have the times be ignored and return ALL records that match the max date, regardless of their associated timestamp in that column. What is the best practice for doing this?
Edit: what I'm looking to do is return all records for the most recent date that matches my criteria, regardless of varying timestamps for that day. Below is what I'm doing now and it only returns records from the latest date AND time on that date.
SELECT r."ID",
r."DATE_CREATED"
FROM schema.survey_response r
JOIN
(SELECT S.CUSTOMERID ,
MAX (S.DATE_CREATED) date_created
FROM schema.SURVEY_RESPONSE s
WHERE S.CATEGORY IN ('Yellow', 'Blue','Green')
GROUP BY CUSTOMERID
) recs
ON R.CUSTOMERID = recs.CUSTOMERID
AND R.DATE_CREATED = recs.date_created
WHERE R.CATEGORY IN ('Yellow', 'Blue','Green')
Final Edit: Got it working via the query below.
SELECT r."ID",
r."DATE_CREATED"
FROM schema.survey_response r
JOIN
(SELECT S.CUSTOMERID ,
MAX (trunc(S.DATE_CREATED)) date_created
FROM schema.SURVEY_RESPONSE s
WHERE S.CATEGORY IN ('Yellow', 'Blue','Green')
GROUP BY CUSTOMERID
) recs
ON R.CUSTOMERID = recs.CUSTOMERID
AND trunc(R.DATE_CREATED) = recs.date_created
WHERE R.CATEGORY IN ('Yellow', 'Blue','Green')
In Oracle, you can get the latest date ignoring the time
SELECT max( trunc( date_created ) ) date_created
FROM your_table
You can get all rows that have the latest date ignoring the time in a couple of ways. Using analytic functions (preferrable)
SELECT *
FROM (SELECT a.*,
rank() over (order by trunc(date_created) desc) rnk
FROM your_table a)
WHERE rnk = 1
or the more conventional but less efficient
SELECT *
FROM your_table
WHERE trunc(date_created) = (SELECT max( trunc(date_created) )
FROM your_table)
I need some help to build SQL Query. I have table having data like:
ID Date Name
1 1/1/2009 a
2 1/2/2009 b
3 1/3/2009 c
I need to get result something like...
1 1/1/2009 a
2 1/2/2009 b
3 1/3/2009 c
4 1/4/2009 Null
5 1/5/2009 Null
6 1/6/2009 Null
7 1/7/2009 Null
8 1/8/2009 Null
............................
............................
............................
30 1/30/2009 Null
31 1/31/2009 Null
I want query something like..
Select * from tbl **where month(Date)=1 AND year(Date)=2010**
Above is not completed query.
I need to get all the record of particular month, even if some date missing..
I guess there must be equi Join in the query, I am trying to build this query using Equi join
Thanks
BIG EDIT
Now understand the OPs question.
Use a common table expression and a left join to get this effect.
DECLARE #FirstDay DATETIME;
-- Set start time
SELECT #FirstDay = '2009-01-01';
WITH Days AS
(
SELECT #FirstDay as CalendarDay
UNION ALL
SELECT DATEADD(d, 1, CalendarDay) as CalendarDay
FROM Days
WHERE DATEADD(d, 1, CalendarDay) < DATEADD(m, 1, #FirstDay)
)
SELECT DATEPART(d,d.CalendarDay), **t.date should be (d.CalendarDay)**, t.Name FROM Days d
LEFT JOIN tbl t
ON
d.CalendarDay = t.Date
ORDER BY
d.CalendarDay;
Left this original answer at bottom
You need DATEPART, sir.
SELECT * FROM tbl WHERE DATEPART(m,Date) = 1
If you want to choose month and year, then you can use DATEPART twice or go for a range.
SELECT * FROM tbl WHERE DATEPART(m,Date) = 1 AND DATEPART(yyyy,Date) = 2009
Range :-
SELECT * FROM tbl WHERE Date >= '2009-01-01' AND Date < '2009-02-01'
See this link for more info on DATEPART.
http://msdn.microsoft.com/en-us/library/ms174420.aspx
You can use less or equal to.
Like so:
select * from tbl where date > '2009-01-01' and date < '2009-02-01'
However, it is unclear if you want month 1 from all years?
You can check more examples and functions on "Date and Time Functions" from MSDN
Create a temporary table containing all days of that certain month,
Do left outer join between that table and your data table on tempTable.month = #month.
now you have a big table with all days of the desired month and all the records matching the proper dates + empty records for those dates who have no data.
i hope that's what you want.