Select Maximum record - oracle

Here is my Table EMP_EARN_DETAILS.
Emp_Ern_No is the primary key.
I need to get the amount for each emp_no for each earn_no where the emp_earn_no is the maximum.
The output should be as follows.
0004321 ERN001 2345 11
0004321 ERN002 345 10
0004321 ERN003 345 9
000507 ER-01 563 4
000732 ERN001 2345 12
000732 ERN002 9 13
000732 ERN003 678 8
Please help me with the query

You can aggregate by the fields you need and, at the same time, order by the EMP_EARN_NO value; this can be a solution, by analytic functions:
WITH TEST(emp_no, earn_no, amount, emp_earn_no) AS
(
SELECT '0004321' , 'ERN001' ,2345 ,11 FROM DUAL UNION ALL
SELECT '0004321' , 'ERN002' ,345 , 10 FROM DUAL UNION ALL
SELECT '0004321' , 'ERN003' ,345 ,9 FROM DUAL UNION ALL
SELECT '000507' , 'ER-01' ,56 ,1 FROM DUAL UNION ALL
SELECT '000507' , 'ER-01' ,563 , 2 FROM DUAL UNION ALL
SELECT '000507' , 'ER-01' ,563 ,3 FROM DUAL UNION ALL
SELECT '000507' , 'ER-01' ,563 ,4 FROM DUAL UNION ALL
SELECT '00732' , 'ERN001' ,123 ,7 FROM DUAL UNION ALL
SELECT '00732' , 'ERN001' ,2345 ,12 FROM DUAL UNION ALL
SELECT '00732' , 'ERN002' ,9 ,13 FROM DUAL UNION ALL
SELECT '00732' , 'ERN003' ,67 ,5 FROM DUAL UNION ALL
SELECT '00732' , 'ERN003' ,456 ,6 FROM DUAL UNION ALL
SELECT '00732' , 'ERN003' ,678 ,8 FROM DUAL
)
SELECT emp_no, earn_no, amount, emp_earn_no
FROM (
SELECT emp_no,
earn_no,
amount,
emp_earn_no, ROW_NUMBER() OVER ( PARTITION BY EMP_NO, EARN_NO ORDER BY emp_earn_no DESC) AS ROW_NUM
FROM TEST
)
WHERE ROW_NUM = 1

Give this a shot,
SELECT EMP_NO, SUM(AMOUNT)
FROM EMP_EARN_DETAILS
GROUP BY EMP_NO
HAVING EMP_EARN_NO = MAX(EMP_EARN_NO)

Try this query:
select emp_no, earn_no,
sum(amount) keep (dense_rank last order by emp_earn_no) as sum_amount
from emp_earn_details
group by emp_no, earn_no

First by following query , your conditions achieved :
select t.emp_no a ,t.earn_no b ,max(t.amount) c
from EMP_EARN_DETAILS t
group by t.emp_no,t.earn_no
order by t.emp_no
Only things that you must specify , in a same record with different EMP_EARN_NO. You have to specify in same record which must be in result.
So if you want maximum EMP_EARN_NO be in result you can use following query as final query (exactly your target in question):
select t.emp_no a ,t.earn_no b ,max(t.amount) c, max(t.emp_earn_no) emp_earn_no
from EMP_EARN_DETAILS t
group by t.emp_no,t.earn_no
order by t.emp_no
If you want minimum or others EMP_EARN_NO be in result you can above query replace max function by your conditions.

Related

Duplicated rows numbering

I need to number the rows so that the row number with the same ID is the same. For example:
Oracle database. Any ideas?
Use the DENSE_RANK analytic function:
SELECT DENSE_RANK() OVER (ORDER BY id) AS row_number,
id
FROM your_table
Which, for the sample data:
CREATE TABLE your_table ( id ) AS
SELECT 86325 FROM DUAL UNION ALL
SELECT 86325 FROM DUAL UNION ALL
SELECT 86326 FROM DUAL UNION ALL
SELECT 86326 FROM DUAL UNION ALL
SELECT 86352 FROM DUAL UNION ALL
SELECT 86353 FROM DUAL UNION ALL
SELECT 86354 FROM DUAL UNION ALL
SELECT 86354 FROM DUAL;
Outputs:
ROW_NUMBER
ID
1
86325
1
86325
2
86326
2
86326
3
86352
4
86353
5
86354
5
86354
db<>fiddle here

Fix time issue in oracle

Table looks like below:
Expected answer below:
Write an oracle query to fix space and return hh:mm format. Consider same time in a same group and return total count
The WITH clause in the query below is just for testing; remove it, and use the actual table and column names in the main query. Note: count is a reserved keyword, so it can't be a column name. I changed it to count_ (with an underscore).
with
test_data (srt_tm, count_) as (
select '1:00' , 125 from dual union all
select '01:00' , 19000 from dual union all
select ' 01:00', 27 from dual union all
select '4:00' , 22000 from dual union all
select '04:00' , 1800 from dual union all
select ' 04:00', 15000 from dual
)
-- END OF TEST DATA; ACTUAL QUERY BEGINS **BELOW THIS LINE**
select lpad(trim(srt_tm), 5, '0') as srt_tm, sum(count_) as count_
from test_data
group by lpad(trim(srt_tm), 5, '0')
order by srt_tm
;
SRT_TM COUNT_
------ --------
01:00 19152
04:00 38800

REGEXP_SUBSTR not able to process only current row

(SELECT LISTAGG(EVENT_DESC, ',') WITHIN GROUP (ORDER BY EVENT_DESC) FROM EVENT_REF WHERE EVENT_ID IN
( SELECT REGEXP_SUBSTR(AFTER_VALUE,'[^,]+', 1, level) FROM DUAL
CONNECT BY REGEXP_SUBSTR(AFTER_VALUE, '[^,]+', 1, level) IS NOT NULL
)
)
A table from which I am fetching AFTER_VALUE has values of integer which is comma seperated like
AFTER_VALUE data
Expected output
1
Event1
1,2
Event1,Event2
1,12,2,5
Event1,Event12,Event2,Event5
15,13
Event15,Event13
these are Ids in EVENT_REF table which have some description. I am trying to basically present
ex. 1,2 as Event1, Event2 and send back from query. There are multiple events so using REPLACE would be very tedious.
When using above query I'm getting error as “ORA-01722: invalid number” whenever there is more than one value in AFTER_VALUE column Ex. if there exists only one id , then the query works but for values like 1,2 or 1,13 etc it throws invalid number error.
PS: The event names are not Event1,Event2 etc , I have just put for reference.
You don't even need regular expressions for this assignment. Standard string function replace() can do the same thing, and faster. You only need an extra 'Event' at the beginning of the string, since that one doesn't "replace" anything.
Like this: (note that you don't need the with clause; I included it only for quick testing)
with
event_ref (after_value) as (
select '1' from dual union all
select '1,2' from dual union all
select '1,12,2,5' from dual union all
select '15,13' from dual
)
select after_value,
'Event' || replace(after_value, ',', ',Event') as desired_output
from event_ref
;
AFTER_VALUE DESIRED_OUTPUT
----------- -----------------------------
1 Event1
1,2 Event1,Event2
1,12,2,5 Event1,Event12,Event2,Event5
15,13 Event15,Event13
Ah,ok, looks, like you have other characters in your comma-separated list, so you can use this query:
with EVENT_REF(EVENT_ID,EVENT_DESC) as (
select 1, 'Desc 1' from dual union all
select 2, 'Desc 2' from dual union all
select 3, 'Desc 3' from dual union all
select 4, 'Desc 4' from dual union all
select 5, 'Desc 5' from dual union all
select 12, 'Desc12' from dual union all
select 13, 'Desc13' from dual union all
select 15, 'Desc15' from dual
)
select
(SELECT LISTAGG(EVENT_DESC, ',')
WITHIN GROUP (ORDER BY EVENT_DESC)
FROM EVENT_REF
WHERE EVENT_ID IN
( SELECT to_number(REGEXP_SUBSTR(AFTER_VALUE,'\d+', 1, level))
FROM DUAL
CONNECT BY level<=REGEXP_COUNT(AFTER_VALUE, '\d+')
)
)
from (
select '1' AFTER_VALUE from dual union all
select '1,2' AFTER_VALUE from dual union all
select '1,12,2,5' AFTER_VALUE from dual union all
select '15,13' AFTER_VALUE from dual
);
PS. And do not forget that to_number has 'default on conversion error' now: https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/TO_NUMBER.html
There is no need to split and concatenate substrings, just use regexp_replace:
with EVENT_REF (AFTER_VALUE) as (
select '1' from dual union all
select '1,2' from dual union all
select '1,12,2,5' from dual union all
select '15,13' from dual
)
select regexp_replace(AFTER_VALUE,'(\d+)','Event\1') from EVENT_REF;
REGEXP_REPLACE(AFTER_VALUE,'(\D+)','EVENT\1')
-----------------------------------------------
Event1
Event1,Event2
Event1,Event12,Event2,Event5
Event15,Event13

How to use the query builder of Symfony to make a date range counter and fill the gaps with zeros

I have a query that count the user by grouping them by sign up date.
return $this->createQueryBuilder('s')
->select(' date(s.created_at) as x, count(1) as y')
->where("s.created_at between datesub(now(), :months, 'Month') and now()")
->setParameter('months', $months)
->groupBy('x')
->orderBy('x')
->getQuery()
->getResult();
But their is currently gaps in my dataset.
So I have the sql request to fill the gaps, but I don't know how to create a complicated request with the Symfony's query builder.
SELECT ranger.ranger_date AS x, COALESCE(counter.counter_value, 0) as y
FROM (
SELECT DATE(s.created_at) AS counter_date, count(*) AS counter_value
FROM statistic AS s
WHERE s.created_at between DATE_SUB(NOW(), INTERVAL 3 MONTH) and now()
GROUP BY counter_date
) AS counter
RIGHT JOIN (
SELECT DATE(DATE_SUB(NOW(), INTERVAL units.i + tens.i * 10 + hundreds.i * 100 DAY)) AS ranger_date
FROM (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9)units
CROSS JOIN (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9)tens
CROSS JOIN (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9)hundreds
WHERE DATE_SUB(NOW(), INTERVAL units.i + tens.i * 10 + hundreds.i * 100 DAY) BETWEEN DATE_SUB(NOW(), INTERVAL 3 MONTH) AND NOW()
) AS ranger
ON ranger.ranger_date = counter.counter_date
ORDER BY ranger.ranger_date
I have already tried with the createQuery method, but it did not work...
If your complex native sql query is successfully returning the result set you want:
You can simply prepare and execute the query as documented by Symfony.
If you need to hydrate entities then you can use the NativeQuery class.

Grouping and aggregation based on a specific condition

My result set from a query looks like this
trackingnumber type price
------------------------------------------
12799467 AVRM 674.0536
12799467 AVRM 860.7415
12799467 PRICESTD 200.00
12799468 PRICESTD 590.85
12799469 PRICESTD 800
12799470 PRICESTD 640
12799471 PRICESTD 160
12799472 PRICESTD 2080
12799473 PRICESTD 354.3779
I want to group this by the trackingnumber and in cases where the count of grouped result set is greater than 1 return the SUM of all the price which has type as AVRM else return the individual price as it is. If the count
is more that zero and the none of them has type AVRM then it's total price would be null
The expected result would be this
trackingnumber Total Price
-----------------------------------------
12799467 1534.7951 --sum of price excluding 200
12799468 590.85
12799469 800
12799470 640
12799471 160
12799472 2080
12799473 354.3779
I couldn't think of a way to get this done except for grouping by trackingnumber and checking for type by using case statement in the select part but that I believe would not work since we do not group by type
I'm not sure if this can be achieved using a single query.
Yes, it can be done in a single query.
with sample_data ( tracking_Number, "TYPE", price ) as
(
SELECT 12799467,'AVRM',674.0536 FROM DUAL UNION ALL
SELECT 12799467,'AVRM',860.7415 FROM DUAL UNION ALL
SELECT 12799467,'PRICESTD',200.00 FROM DUAL UNION ALL
SELECT 12799468,'PRICESTD',590.85 FROM DUAL UNION ALL
SELECT 12799469,'PRICESTD',800 FROM DUAL UNION ALL
SELECT 12799470,'PRICESTD',640 FROM DUAL UNION ALL
SELECT 12799471,'PRICESTD',160 FROM DUAL UNION ALL
SELECT 12799472,'PRICESTD',2080 FROM DUAL UNION ALL
SELECT 12799473,'PRICESTD',354.3779 FROM DUAL )
SELECT tracking_number,
case when count(*) > 1 THEN
sum(decode("TYPE",'AVRM',price,null)) ELSE
sum(price) END price
from sample_data
group by tracking_number
order by tracking_Number;
For example next solution. I add condition to exlude rows with type not equla 'AVRM' if rows with 'AVRM' exests
with s (trackingnumber ,type ,price)
as (
select 12799467,'AVRM',674.0536 from dual union all
select 12799467 ,'AVRM', 860.7415 from dual union all
select 12799467 ,'PRICESTD', 200.00 from dual union all
select 12799468 ,'PRICESTD', 590.85 from dual union all
select 12799469 ,'PRICESTD', 800 from dual union all
select 12799470 ,'PRICESTD', 640 from dual union all
select 12799471 ,'PRICESTD', 160 from dual union all
select 12799472 ,'PRICESTD', 2080 from dual union all
select 12799473 ,'PRICESTD', 354.3779 from dual )
select trackingnumber,
sum(price)
from (select s.*,rownum as rn from s
where not exists (select null
from s subs
where s.trackingnumber = subs.trackingnumber
and s.type != 'AVRM'
and subs.type = 'AVRM')
)
group by trackingnumber,
case when type = 'AVRM' then 0 else rn end;

Resources