getting hour in groups - oracle - whats is wrong - oracle
whats is wrong with this query.
I need to get all hours of the 24 hours period to count hits per hour.
I want to make a case when 0-24 but I can not do the first work
SELECT
(
CASE WHEN (
CAST(TO_CHAR(dg_user_acess.dt_user_acess, 'HH24') >= '00')
AND
CAST(TO_CHAR(dg_user_acess.dt_user_acess, 'HH24') < '01')
)
THEN ('00:00 as 01:00')
ELSE '0' END
) as hour,
count(*)
FROM dg_user_acess
GROUP by hour
i get the error
Erro de SQL: ORA-00905: palavra-chave não encontrada
00905. 00000 - "missing keyword"
the table data is like this
pk| dt_user_acess
01| 2014-10-21 08:30:12
02| 2014-10-21 08:40:27
03| 2014-10-21 08:56:18
04| 2014-10-21 09:15:19
05| 2014-10-21 10:42:48
...
and the result I would like something like this (not write the case when all schedulesin query to not pollute the code)
'00:00 as 01:00' 0
'01:00 as 02:00' 0
'02:00 as 03:00' 0
'03:00 as 04:00' 0
'04:00 as 05:00' 0
'05:00 as 06:00' 0
'06:00 as 07:00' 0
'07:00 as 08:00' 0
'08:00 as 09:00' 3
'09:00 as 10:00' 1
'10:00 as 11:00' 1
'11:00 as 12:00' 0
'12:00 as 13:00' 0
'13:00 as 14:00' 0
'14:00 as 15:00' 0
'15:00 as 16:00' 0
'16:00 as 17:00' 0
'17:00 as 18:00' 0
'18:00 as 19:00' 0
'19:00 as 20:00' 0
'20:00 as 21:00' 0
'21:00 as 22:00' 0
'22:00 as 23:00' 0
'23:00 as 23:59' 0
whats is wrong with this query [?]
You have many (more or less severe) issues with your query -- in no particular order:
The correct syntax for CAST is CAST(value AS type)
You use hour as a column name, but it is a reserved word
You compare strings where it is probably numbers that you should compare
You seems to expect a "dense" result set, but as you don't use a join, there is no chance for the result set to have more rows than the original table (probably less in fact, as you GROUP BY)
Given your needs, you probably missed the EXTRACT(HOUR FROM ...) function. In order to extract all the "hits" for an hour, you would write that:
SELECT
EXTRACT(HOUR FROM dg_user_acess.dt_user_acess) as "hour"
FROM dg_user_acess
As you need to COUNT them (and since you cannot use an alias in a GROUP BY clause) you might use a sub-query. Don't worry too much about that: Oracle is smart enough to optimize that kind of request:
SELECT "hour", count(*) "cnt"
FROM (
SELECT
EXTRACT(HOUR FROM dg_user_acess.dt_user_acess) as "hour"
FROM dg_user_acess
) V
GROUP BY "hour";
Finally, as you need a dense output (i.e.: with all hours in the range 0-23), my option would be to use a join on a generated table:
SELECT "hour", NVL("cnt",0) "cnt"
FROM (
SELECT LEVEL "hour" FROM DUAL
CONNECT BY LEVEL < 24
) CLOCK
LEFT JOIN (
SELECT "hour", count(*) "cnt"
FROM (
SELECT
EXTRACT(HOUR FROM dg_user_acess.dt_user_acess) as "hour"
FROM dg_user_acess
) V
GROUP BY "hour"
) G
USING ("hour")
ORDER BY "hour";
All of this leads to rather complexly nested queries. But this has the benefit of being easy to write incrementally as you just see it. Now that I showed the basic building blocks, perhaps we could do a better job. Maybe that:
SELECT CLOCK."hour", COUNT(dg_user_acess.dt_user_acess) "cnt"
FROM (
SELECT LEVEL "hour" FROM DUAL
CONNECT BY LEVEL < 24
) CLOCK
LEFT JOIN dg_user_acess
ON CLOCK."hour" = EXTRACT(HOUR FROM dg_user_acess.dt_user_acess)
GROUP BY CLOCK."hour"
ORDER BY CLOCK."hour";
Depending your schema and data, this might or might not perform better than the previous version. Feel free to take some time to experiment all these queries on http://sqlfiddle.com/#!4/678a5/17
i get some result changing the group by and the condition of the case (and remove the cast).
I do not know if it's the best way to do this, but it worked
SELECT
(
CASE WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '00:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '01:00' ) THEN ('00:00 as 01:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '01:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '02:00' ) THEN ('01:00 as 02:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '02:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '03:00' ) THEN ('02:00 as 03:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '03:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '04:00' ) THEN ('03:00 as 04:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '04:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '05:00' ) THEN ('04:00 as 05:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '05:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '06:00' ) THEN ('05:00 as 06:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '06:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '07:00' ) THEN ('06:00 as 07:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '07:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '08:00' ) THEN ('07:00 as 08:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '08:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '09:00' ) THEN ('08:00 as 09:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '09:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '10:00' ) THEN ('09:00 as 10:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '10:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '11:00' ) THEN ('10:00 as 11:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '11:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '12:00' ) THEN ('11:00 as 12:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '12:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '13:00' ) THEN ('12:00 as 13:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '13:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '14:00' ) THEN ('13:00 as 14:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '14:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '15:00' ) THEN ('14:00 as 15:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '15:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '16:00' ) THEN ('15:00 as 16:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '16:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '17:00' ) THEN ('16:00 as 17:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '17:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '18:00' ) THEN ('17:00 as 18:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '18:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '19:00' ) THEN ('18:00 as 19:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '19:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '20:00' ) THEN ('19:00 as 20:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '20:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '21:00' ) THEN ('20:00 as 21:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '21:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '22:00' ) THEN ('21:00 as 22:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '22:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '23:00' ) THEN ('22:00 as 23:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '23:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '23:59' ) THEN ('23:00 as 23:59')
ELSE '0' END
) as hora,
count(*) as total
FROM dg_usuario_acesso
JOIN dg_usuario_sessao
ON dg_usuario_sessao.cd_usuario_sessao = dg_usuario_acesso.cd_usuario_sessao
WHERE dg_usuario_acesso.dt_usuario_acesso >= to_date('2014-09-19 00:00', 'YYYY-MM-DD HH24:Mi')
AND dg_usuario_acesso.dt_usuario_acesso <= to_date('2014-09-20 15:07', 'YYYY-MM-DD HH24:Mi')
AND dg_usuario_sessao.cd_usuario NOT IN (0,1,138)
group by (CASE WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '00:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '01:00' ) THEN ('00:00 as 01:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '01:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '02:00' ) THEN ('01:00 as 02:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '02:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '03:00' ) THEN ('02:00 as 03:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '03:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '04:00' ) THEN ('03:00 as 04:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '04:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '05:00' ) THEN ('04:00 as 05:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '05:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '06:00' ) THEN ('05:00 as 06:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '06:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '07:00' ) THEN ('06:00 as 07:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '07:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '08:00' ) THEN ('07:00 as 08:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '08:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '09:00' ) THEN ('08:00 as 09:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '09:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '10:00' ) THEN ('09:00 as 10:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '10:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '11:00' ) THEN ('10:00 as 11:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '11:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '12:00' ) THEN ('11:00 as 12:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '12:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '13:00' ) THEN ('12:00 as 13:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '13:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '14:00' ) THEN ('13:00 as 14:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '14:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '15:00' ) THEN ('14:00 as 15:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '15:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '16:00' ) THEN ('15:00 as 16:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '16:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '17:00' ) THEN ('16:00 as 17:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '17:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '18:00' ) THEN ('17:00 as 18:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '18:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '19:00' ) THEN ('18:00 as 19:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '19:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '20:00' ) THEN ('19:00 as 20:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '20:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '21:00' ) THEN ('20:00 as 21:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '21:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '22:00' ) THEN ('21:00 as 22:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '22:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '23:00' ) THEN ('22:00 as 23:00')
WHEN (TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') >= '23:00' AND TO_CHAR(dg_usuario_acesso.DT_USUARIO_ACESSO, 'HH24:Mi') < '23:59' ) THEN ('23:00 as 23:59')
ELSE '0' END
)
order by 1
and I got the result I would like
hour Total hits
00:00 as 01:00 10
04:00 as 05:00 8
07:00 as 08:00 4
08:00 as 09:00 14
09:00 as 10:00 84
10:00 as 11:00 25
11:00 as 12:00 14
12:00 as 13:00 7
13:00 as 14:00 5
14:00 as 15:00 7
15:00 as 16:00 22
16:00 as 17:00 19
17:00 as 18:00 28
18:00 as 19:00 7
19:00 as 20:00 16
21:00 as 22:00 2
23:00 as 23:59 2
Related
Need help for Top 10 Products (by Amounts) - weekly
I have create new table and insert sample data into the table. I want to get the top 10 products rank by amount weekly. I tried SQL Query but give the wrong data. I have shared the table, sample data, and SQL Query below. I have a table: CREATE TABLE product_table ( product_name VARCHAR2(20), amount NUMBER, datetime DATE ) Sample Data: INSERT INTO product_table (product_name, amount, datetime) SELECT 'P1', 10000, TRUNC(SYSDATE, 'IW') FROM DUAL UNION ALL SELECT 'P2', 15000, TRUNC(SYSDATE, 'IW') FROM DUAL UNION ALL SELECT 'P3', 18000, TRUNC(SYSDATE, 'IW') FROM DUAL UNION ALL SELECT 'P4', 11000, TRUNC(SYSDATE, 'IW') FROM DUAL UNION ALL SELECT 'P5', 13000, TRUNC(SYSDATE, 'IW') FROM DUAL UNION ALL SELECT 'P6', 16000, TRUNC(SYSDATE, 'IW') FROM DUAL UNION ALL SELECT 'P7', 19000, TRUNC(SYSDATE, 'IW') FROM DUAL UNION ALL SELECT 'P8', 20000, TRUNC(SYSDATE, 'IW') FROM DUAL UNION ALL SELECT 'P9', 24000, TRUNC(SYSDATE, 'IW') FROM DUAL UNION ALL SELECT 'P10',26000, TRUNC(SYSDATE, 'IW') FROM DUAL UNION ALL SELECT 'P11',34000, TRUNC(SYSDATE, 'IW') FROM DUAL UNION ALL SELECT 'P1', 8000, TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL UNION ALL SELECT 'P2', 17000, TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL UNION ALL SELECT 'P3', 22000, TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL UNION ALL SELECT 'P4', 23000, TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL UNION ALL SELECT 'P5', 26000, TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL UNION ALL SELECT 'P6', 34000, TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL UNION ALL SELECT 'P7', 31000, TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL UNION ALL SELECT 'P8', 42000, TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL UNION ALL SELECT 'P9', 54000, TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL UNION ALL SELECT 'P10', 14000, TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL UNION ALL SELECT 'P11', 19000, TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL UNION ALL SELECT 'P1', 8000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -1) FROM DUAL UNION ALL SELECT 'P2', 16000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -1) FROM DUAL UNION ALL SELECT 'P3', 21000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -1) FROM DUAL UNION ALL SELECT 'P4', 22000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -1) FROM DUAL UNION ALL SELECT 'P5', 25000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -1) FROM DUAL UNION ALL SELECT 'P6', 33000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -1) FROM DUAL UNION ALL SELECT 'P7', 32000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -1) FROM DUAL UNION ALL SELECT 'P8', 41000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -1) FROM DUAL UNION ALL SELECT 'P9', 53000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -1) FROM DUAL UNION ALL SELECT 'P10', 24000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -1) FROM DUAL UNION ALL SELECT 'P11', 29000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -1) FROM DUAL UNION ALL SELECT 'P1', 7000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -2) FROM DUAL UNION ALL SELECT 'P2', 15000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -2) FROM DUAL UNION ALL SELECT 'P3', 20000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -2) FROM DUAL UNION ALL SELECT 'P4', 21000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -2) FROM DUAL UNION ALL SELECT 'P5', 24000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -2) FROM DUAL UNION ALL SELECT 'P6', 32000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -2) FROM DUAL UNION ALL SELECT 'P7', 31000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -2) FROM DUAL UNION ALL SELECT 'P8', 40000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -2) FROM DUAL UNION ALL SELECT 'P9', 52000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -2) FROM DUAL UNION ALL SELECT 'P10', 34000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -2) FROM DUAL UNION ALL SELECT 'P11', 39000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -2) FROM DUAL UNION ALL SELECT 'P1', 6000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -3) FROM DUAL UNION ALL SELECT 'P2', 14000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -3) FROM DUAL UNION ALL SELECT 'P3', 19000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -3) FROM DUAL UNION ALL SELECT 'P4', 20000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -3) FROM DUAL UNION ALL SELECT 'P5', 23000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -3) FROM DUAL UNION ALL SELECT 'P6', 31000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -3) FROM DUAL UNION ALL SELECT 'P7', 30000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -3) FROM DUAL UNION ALL SELECT 'P8', 39000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -3) FROM DUAL UNION ALL SELECT 'P9', 51000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -3) FROM DUAL UNION ALL SELECT 'P10', 54000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -3) FROM DUAL UNION ALL SELECT 'P11', 69000, ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -3) FROM DUAL; Query: SELECT RANK() OVER ( ORDER BY SUM( CASE WHEN datetime >= TRUNC(SYSDATE, 'IW') AND datetime < TRUNC(SYSDATE, 'IW') + INTERVAL '7' DAY THEN 1 END ) DESC ) AS rank_this_week, product_name, SUM(AMOUNT) TOTAL_AMOUNT FROM PRODUCT_TABLE GROUP BY product_name, amount ORDER BY AMOUNT DESC FETCH FIRST 10 ROWS ONLY; Result: This query does not show correct Top 10 Products (by Amounts) - weekly Rank db<>fiddle Need Final Output Result in this format:
You haven't said what your expected output is; however, you appear to want to order by the weekly amount so you need to order by the rank_this_week column and not include amount in the GROUP BY clause: SELECT RANK() OVER ( ORDER BY SUM( CASE WHEN datetime >= TRUNC(SYSDATE, 'IW') AND datetime < TRUNC(SYSDATE, 'IW') + INTERVAL '7' DAY THEN amount END ) DESC ) AS rank_this_week, product_name, SUM( CASE WHEN datetime >= TRUNC(SYSDATE, 'IW') AND datetime < TRUNC(SYSDATE, 'IW') + INTERVAL '7' DAY THEN amount END ) AS total_amount_this_week, SUM(AMOUNT) TOTAL_AMOUNT FROM PRODUCT_TABLE GROUP BY product_name ORDER BY rank_this_week FETCH FIRST 10 ROWS ONLY; Which, for the sample data, outputs: RANK_THIS_WEEK PRODUCT_NAME TOTAL_AMOUNT_THIS_WEEK TOTAL_AMOUNT 1 P11 34000 190000 2 P10 26000 152000 3 P9 24000 234000 4 P8 20000 182000 5 P7 19000 143000 6 P3 18000 100000 7 P6 16000 146000 8 P2 15000 77000 9 P5 13000 111000 10 P4 11000 97000 db<>fiddle here
After you posted a comment and displayed desired result, here's one option. Read comments within code. SQL> with 2 -- Each DATES CTE returns desired "date" value 3 dates_tw as (select to_char(sysdate, 'yyyy iw') this_week from dual), 4 dates_pw as (select to_char(sysdate - 7, 'yyyy iw') previous_week from dual), 5 dates_lm as (select trunc(add_months(sysdate, -1), 'mm') last_month from dual), 6 dates_ma2 as (select trunc(add_months(sysdate, -2), 'mm') two_months_ago from dual), 7 dates_ma3 as (select trunc(add_months(sysdate, -3), 'mm') three_months_ago from dual), 8 sums as 9 -- compute total amount for reach "date" value from DATES CTEs, hence CROSS JOIN. 10 -- As DATES CTEs contain a single row, that shouldn't be too bad (performance wise) 11 (select p.product_name, 12 sum(case when to_char(p.datetime, 'yyyy iw') = tw.this_week then amount else 0 end) sum_tw, 13 sum(case when to_char(p.datetime, 'yyyy iw') = pw.previous_week then amount else 0 end) sum_pw, 14 sum(case when trunc(p.datetime, 'mm') = lm.last_month then amount else 0 end) sum_lm, 15 sum(case when trunc(p.datetime, 'mm') = ma2.two_months_ago then amount else 0 end) sum_ma2, 16 sum(case when trunc(p.datetime, 'mm') = ma3.three_months_ago then amount else 0 end) sum_ma3 17 from product_table p cross join dates_tw tw 18 cross join dates_pw pw 19 cross join dates_lm lm 20 cross join dates_ma2 ma2 21 cross join dates_ma3 ma3 22 group by product_name 23 ), 24 ranks as 25 -- rank products per each total amount 26 (select s.product_name, 27 rank() over (order by sum_tw desc) rnk_tw, 28 rank() over (order by sum_pw desc) rnk_pw, 29 rank() over (order by sum_lm desc) rnk_lm, 30 rank() over (order by sum_ma2 desc) rnk_ma2, 31 rank() over (order by sum_ma3 desc) rnk_ma3 32 from sums s 33 ) 34 -- finally, return only product that "now" rank as the first 5 (or as many as you want), 35 -- and display their rank for other dates 36 select rnk_tw as "rank this week", 37 product_name, 38 rnk_pw as "previous week", 39 rnk_lm as "last month", 40 rnk_ma2 as "2 months ago", 41 rnk_ma3 as "3 months ago" 42 from ranks 43 where rnk_tw <= 5 44 order by rnk_tw; rank this week PRODUCT_NAME previous week last month 2 months ago 3 months ago -------------- -------------------- ------------- ---------- ------------ ------------ 1 P11 8 5 3 1 2 P10 10 7 4 2 3 P9 1 1 1 3 4 P8 2 2 2 4 5 P7 4 4 6 6 SQL>
How to get past three months sales continuously?
I have sales data, I need to filter who(Agent id) is done more sales end of the last 3 days of the month, did more than 80 % sales (last three days sales/ Total sale particular month ), and continuously did the past three months. I tried the below query it satisfies only the last three days sales more than the rest of the days and more than 80% sales that particular month((last three days sales/ Total sale particular month) . But I couldn't get who is done continuously for three months. Example: One Agent, he did sales last 3 days sales more compare to the rest day sales and more than 80% sales in the last three days July and continuously did past three months (July, June, May) SELECT a.agent_id,a.agent_name,a.ivr_registered_district,s.agent_type,s.district,s.province,a.parent_level1_id,a.parent_level1,a.sales_channel,TO_CHAR(TRUNC(a.connection_date, 'MONTH'), 'MON-YYYY') AS MONTHYEAR, COUNT( CASE WHEN a.connection_date < TRUNC( LAST_DAY( a.connection_date ) ) - INTERVAL '4' DAY THEN 1 END ) AS not_last_5days_sale_count, COUNT( CASE WHEN a.connection_date >= TRUNC( LAST_DAY( a.connection_date ) ) - INTERVAL '4' DAY THEN 1 END ) AS last_5days_sale_count, COUNT( CASE WHEN a.connection_date >= TRUNC( LAST_DAY( a.connection_date ) ) - INTERVAL '4' DAY THEN 1 END ) / ( COUNT( CASE WHEN a.connection_date < TRUNC( LAST_DAY( a.connection_date ) ) - INTERVAL '4' DAY THEN 1 END ) + COUNT( CASE WHEN a.connection_date >= TRUNC( LAST_DAY( a.connection_date ) ) - INTERVAL '4' DAY THEN 1 END )) as percentage FROM EDW_TGT.FACT_LTE_SALES_CHANNELS a JOIN SFA.sfa_agent_dtl s ON a.agent_id = s.agent_id where a.pre_post = 'LTE-PREPAID' and a.sales_channel in ('BUSINESS PARTNER', 'INSTITUSIONAL', 'REGIONAL TRADE PARTNERS', 'DISTRIBUTOR') --and a.connection_date BETWEEN TO_DATE('2020-07-01 00:00:0', 'YYYY-MM-DD HH24:MI:SS') and TO_DATE('2020-07-31 23:59:59', 'YYYY-MM-DD HH24:MI:SS') and a.connection_date < ADD_MONTHS(SYSDATE,-2) GROUP BY a.agent_id,a.agent_name,a.ivr_registered_district,s.agent_type,s.district,s.province,a.parent_level1_id,a.parent_level1,a.sales_channel,TO_CHAR(TRUNC(a.connection_date, 'MONTH'), 'MON-YYYY') HAVING COUNT( CASE WHEN a.connection_date > TRUNC( LAST_DAY( a.connection_date ) ) - INTERVAL '4' DAY THEN 1 END ) > COUNT( CASE WHEN a.connection_date < TRUNC( LAST_DAY( a.connection_date ) ) - INTERVAL '4' DAY THEN 1 END ) AND COUNT( CASE WHEN a.connection_date >= TRUNC( LAST_DAY( a.connection_date ) ) - INTERVAL '4' DAY THEN 1 END ) >=3 AND COUNT( CASE WHEN a.connection_date >= TRUNC( LAST_DAY( a.connection_date ) ) - INTERVAL '4' DAY THEN 1 END ) / ( COUNT( CASE WHEN a.connection_date < TRUNC( LAST_DAY( a.connection_date ) ) - INTERVAL '4' DAY THEN 1 END ) + COUNT( CASE WHEN a.connection_date >= TRUNC( LAST_DAY( a.connection_date ) ) - INTERVAL '4' DAY THEN 1 END )) > 0.79
Oracle 11g Sql convert date from blob field
I have a problem in converting a date value stored in a blob field in Oracle 11g sql command. When i execute the sql: select dump(HIGH_VALUE) from all_tab_columns where COLUMN_NAME='TARIH' i receive the following result; Typ=23 Len=7: 120,116,3,6,1,1,1 I know that these numbers represent a date (not datetime), but i don't know how to extract the date from this result. Thanks in advance, Alper
Oracle stores dates in tables as 7-bytes byte 1 - century + 100 byte 2 - (year MOD 100 ) + 100 byte 3 - month byte 4 - day byte 5 - hour + 1 byte 6 - minute + 1 byte 7 - seconds+ 1 So 120,116,3,6,1,1,1 converts to: byte 1 - century = 120 - 100 = 20 byte 2 - year = 116 - 100 = 16 byte 3 - month = 3 byte 4 - day = 6 byte 5 - hour = 1 - 1 = 0 byte 6 - minute = 1 - 1 = 0 byte 7 - seconds = 1 - 1 = 0 So 2016-03-06T00:00:00 Oracle Setup: CREATE TABLE file_upload ( file_blob BLOB ); INSERT INTO file_upload VALUES ( utl_raw.cast_to_raw( CHR(120) || CHR(116) || CHR(3) || CHR(6) || CHR(1) || CHR(1) || CHR(1) ) ); Query: SELECT DUMP( DBMS_LOB.SUBSTR( file_blob, 7, 1 ) ) AS dmp, TO_DATE( TO_CHAR( ( ASCII( SUBSTR( chars, 1, 1 ) ) - 100 ) * 100 + ASCII( SUBSTR( chars, 2, 1 ) ) - 100, '0000' ) || TO_CHAR( ASCII( SUBSTR( chars, 3, 1 ) ), '00' ) || TO_CHAR( ASCII( SUBSTR( chars, 4, 1 ) ), '00' ) || TO_CHAR( ASCII( SUBSTR( chars, 5, 1 ) ) - 1, '00' ) || TO_CHAR( ASCII( SUBSTR( chars, 6, 1 ) ) - 1, '00' ) || TO_CHAR( ASCII( SUBSTR( chars, 7, 1 ) ) - 1, '00' ), 'YYYYMMDDHH24MISS' ) AS converted_date FROM ( SELECT file_blob, UTL_RAW.CAST_TO_VARCHAR2(DBMS_LOB.SUBSTR( file_blob, 7, 1 ) ) AS chars FROM file_upload ); Output: DMP CONVERTED_DATE ------------------------------- ------------------- Typ=23 Len=7: 120,116,3,6,1,1,1 2016-03-06 00:00:00
Invalid number error - [Error Code: 1722, SQL State: 42000] ORA-01722: invalid number
The 1st query from the below 2 queries is giving me [Error Code: 1722, SQL State: 42000] ORA-01722: invalid number error. But when I limit the no of records as in the 2nd query then it is running fine. Other than limiting the rows in the 2nd query, both the queries are identical. SELECT b.first_name, b.last_name, b.device_derived, b.ios_version_group, b.add_date, FIRST_VALUE (b.add_date) OVER (PARTITION BY b.first_name, b.last_name, b.ios_version_group) AS first_date, LAST_VALUE (b.add_date) OVER (PARTITION BY b.first_name, b.last_name, b.ios_version_group) AS last_date FROM (SELECT a.first_name, a.last_name, a.os_version, a.device_type, a.device, a.add_date, a.device_derived, CASE WHEN ( ( UPPER (a.device_derived) = 'IPHONE' OR UPPER (a.device_derived) = 'IPAD') AND TO_NUMBER (SUBSTR (a.os_version, 1, 1)) > 4) THEN 'iOS ' || SUBSTR (a.os_version, 1, 1) ELSE 'Others' END AS ios_version_group FROM (SELECT first_name, last_name, os_version, device_type, device, add_date, CASE WHEN UPPER (device_type) = 'ANDROID' THEN 'Android' WHEN UPPER (device_type) = 'BB' OR UPPER (device_type) = 'BLACKBERRY' THEN 'Blackberry' WHEN UPPER (device_type) = 'IOS' AND ( SUBSTR (UPPER (device), 1, 6) = 'IPHONE' OR SUBSTR (UPPER (device), 1, 4) = 'IPOD') THEN 'iPhone' WHEN UPPER (device_type) = 'IOS' AND (SUBSTR (UPPER (device), 1, 4) = 'IPAD') THEN 'iPad' END AS device_derived FROM vw_mobile_devices_all) a) b; SELECT b.first_name, b.last_name, b.device_derived, b.ios_version_group, b.add_date, FIRST_VALUE (b.add_date) OVER (PARTITION BY b.first_name, b.last_name, b.ios_version_group) AS first_date, LAST_VALUE (b.add_date) OVER (PARTITION BY b.first_name, b.last_name, b.ios_version_group) AS last_date FROM (SELECT a.first_name, a.last_name, a.os_version, a.device_type, a.device, a.add_date, a.device_derived, CASE WHEN ( ( UPPER (a.device_derived) = 'IPHONE' OR UPPER (a.device_derived) = 'IPAD') AND TO_NUMBER (SUBSTR (a.os_version, 1, 1)) > 4) THEN 'iOS ' || SUBSTR (a.os_version, 1, 1) ELSE 'Others' END AS ios_version_group FROM (SELECT first_name, last_name, os_version, device_type, device, add_date, CASE WHEN UPPER (device_type) = 'ANDROID' THEN 'Android' WHEN UPPER (device_type) = 'BB' OR UPPER (device_type) = 'BLACKBERRY' THEN 'Blackberry' WHEN UPPER (device_type) = 'IOS' AND ( SUBSTR (UPPER (device), 1, 6) = 'IPHONE' OR SUBSTR (UPPER (device), 1, 4) = 'IPOD') THEN 'iPhone' WHEN UPPER (device_type) = 'IOS' AND (SUBSTR (UPPER (device), 1, 4) = 'IPAD') THEN 'iPad' END AS device_derived FROM vw_mobile_devices_all) a) b WHERE ROWNUM <= 100; Can somebody tell me why I am getting this error. Is there an efficient way to write this query?
You have TO_NUMBER (SUBSTR (a.os_version, 1, 1) in your queries, so presumably you're hitting data that doesn't have a number at the start of the os_version, when you request more than 100 rows. You need to check your data.
This error happens when you try to convert a non-numeric value with TO_NUMBER. In the second query the first 100 rows seem not to result into a.os_version to a non-numeric value. Try a simple select vw_mobile_devices_all to find the non-numeric os_version. Figure out how you can work around the problem. Maybe you can query the os_version differently.
Oracle performance tuning order by is taking time
Am having query,in which two fields and getting as output pps_id and total_weight. Here pps_id is the column from the table and total_weight we are calculating from inner query. after doing all process in query we are order by the query by total weight. Its taking more cost and response.Is there any way to improve this query performance. SELECT PPS_ID, TOTAL_WEIGHT FROM ( SELECT PPS_ID, TOTAL_WEIGHT FROM (SELECT pps_id, ROUND ( ( ( (60 * name_pct_match / 100) + prs_weight + year_weight + dt_weight) / 90) * 100) total_weight FROM (SELECT pps_id, ROUND (func_compare_name ('aaaa', UPPER (name_en), ' ', 60)) name_pct_match, DECODE (prs_nationality_id, 99, 15, 0) prs_weight, 10 mother_weight, 100 total_attrib_weight, CASE WHEN TO_NUMBER ( TO_CHAR (birth_date, 'yyyy')) = 1986 THEN 5 ELSE 0 END year_weight, CASE WHEN TO_CHAR ( TO_DATE ('12-JAN-86', 'DD-MON-RRRR'), 'dd') = TO_CHAR (birth_date, 'dd') AND TO_CHAR ( TO_DATE ('12-JAN-86', 'DD-MON-RRRR'), 'mm') = TO_CHAR (birth_date, 'mm') THEN 10 WHEN TO_DATE ('12-JAN-86', 'DD-MON-RRRR') BETWEEN birth_date - 6 AND birth_date + 6 THEN 8 WHEN TO_DATE ('12-JAN-86', 'DD-MON-RRRR') BETWEEN birth_date - 28 AND birth_date + 28 THEN 5 WHEN TO_DATE ('12-JAN-86', 'DD-MON-RRRR') BETWEEN birth_date - 90 AND birth_date + 90 THEN 3 ELSE 0 END dt_weight FROM individual_profile WHERE birth_date = '12-JAN-86' AND IS_ACTIVE = 1 AND gender_id = 1 AND ROUND (func_compare_name ('aaa', UPPER (name_en), ' ', 60)) > 20)) WHERE TOTAL_WEIGHT >= 100 ORDER BY total_weight DESC) WHERE ROWNUM <= 10 i have tried by splitting the query and put values in temp tables and tried but it also taking time. I want to improve the performance of the query