I have a below table structure
When the agreement type for the employee is Basic and Appendix (e.g. row 1,2 & 5,6) then these two rows need to be considered together and status would be active. Below should be the expected outcome
How can this be achieved in oracle 10g. Thanks
This can be achieved using a CASE statement and the LEAD analytic function to see if the next ID is Appendix.
Query
--This is to set up the sample data
WITH
emp_agreements (id, emp_id, agreement_type)
AS
(SELECT 1, 1023, 'Basic' FROM DUAL
UNION ALL
SELECT 2, 1023, 'Appendix' FROM DUAL
UNION ALL
SELECT 3, 1023, 'Basic' FROM DUAL
UNION ALL
SELECT 4, 1023, 'Basic' FROM DUAL
UNION ALL
SELECT 5, 1023, 'Basic' FROM DUAL
UNION ALL
SELECT 6, 1023, 'Appendix' FROM DUAL)
--Real query begins here. You will need to put in your real table name
SELECT emp_id, status
FROM (SELECT id,
emp_id,
agreement_type,
CASE LEAD (agreement_type) OVER (PARTITION BY emp_id ORDER BY id)
WHEN 'Appendix' THEN 'Active'
ELSE 'Pending'
END AS status
FROM emp_agreements)
WHERE agreement_type = 'Basic'
ORDER BY id;
Result
EMP_ID STATUS
_________ __________
1023 Active
1023 Pending
1023 Pending
1023 Active
Related
There is a employees salary history table, sal_hist which has id,name, salary and effective_date. Requirement is to get the employee who has not been appraised. Below is the table:
Id
name
salary
date
1
a
1000
10-5-2020
1
a
2000
12-6-2020
1
a
3000
12-7-2020
2
b
2500
12-5-2020
2
b
3500
12-7-2020
3
c
2500
12-5-2020
Below is the query I have:
Select id,name from sal_hist group by id,name having count(1)=1;
Is there a different way to achieve the result?
If your date column is the appraisal date and you want the user who has not got an appraisal at the latest date then:
SELECT id, name, salary, appraisal_date
FROM (
SELECT s.*,
MAX(appraisal_date) OVER (PARTITION BY id) AS max_user_appraisal_date,
MAX(appraisal_date) OVER () AS max_appraisal_date
FROM salary_history s
)
WHERE appraisal_date = max_user_appraisal_date
AND max_user_appraisal_date < max_appraisal_date
Which, for the sample data:
CREATE TABLE salary_history (Id, name, salary, appraisal_date) AS
SELECT 1, 'a', 1000, DATE '2020-05-10' FROM DUAL UNION ALL
SELECT 1, 'a', 2000, DATE '2020-06-12' FROM DUAL UNION ALL
SELECT 1, 'a', 3000, DATE '2020-07-12' FROM DUAL UNION ALL
SELECT 2, 'b', 2500, DATE '2020-05-12' FROM DUAL UNION ALL
SELECT 2, 'b', 3500, DATE '2020-07-12' FROM DUAL UNION ALL
SELECT 3, 'c', 2500, DATE '2020-05-12' FROM DUAL;
Outputs:
ID
NAME
SALARY
APPRAISAL_DATE
3
c
2500
12-MAY-20
db<>fiddle here
If you are looking for another way to achieve the result and find the employee with only 1 salary listed (no appraisals in the past) you can use a subquery like this:
SELECT id, name
FROM (
SELECT id, name, COUNT(id) AS [count]
FROM sal_hist
GROUP BY id,name)
WHERE count=1;
But I would note that using HAVING as you have currently is a better method.
In my database that represents a car service station, I am trying to figure out a SQL query that would give me a total average of how much does the customer pays for a single service but instead of getting AVG() of the price on all existing Invoices, I want to group the invoices by the same reservation_id. After that, I would like to get the total average of all of those grouped results.
I am using the two tables listed in the picture below. I want to get the value of a total average price by applying AVG() on all averages that are made by grouping prices by the same FK Reservation_reservation_id.
I tried to make this into a single query but I failed so I came looking for help from more experienced users. Also, I need to select (get) only the result of the total average. This result should give me an overview of how much each customer pays on average for one reservation.
Thanks for your time
You appear to want to aggregate twice:
SELECT AVG( avg_price ) avg_avg_price
FROM (
SELECT AVG( price ) AS avg_price
FROM invoice
GROUP BY reservation_reservation_id
)
Which, for the sample data:
CREATE TABLE invoice ( reservation_reservation_id, price ) AS
SELECT 1, 10 FROM DUAL UNION ALL
SELECT 1, 12 FROM DUAL UNION ALL
SELECT 1, 14 FROM DUAL UNION ALL
SELECT 1, 16 FROM DUAL UNION ALL
SELECT 2, 10 FROM DUAL UNION ALL
SELECT 2, 11 FROM DUAL UNION ALL
SELECT 2, 12 FROM DUAL;
Outputs:
AVG_AVG_PRICE
12
db<>fiddle here
If you want this per customer:
SELECT customer_customer_id, AVG(avg_reservation_price)
FROM (SELECT i.customer_customer_id, i.reservation_reservation_id,
AVG(i.price) as avg_reservation_price
FROM invoice i
GROUP BY i.customer_customer_id, i.reservation_reservation_id
) ir
GROUP BY customer_customer_id;
If you want this for a particular "checkout reason" -- which is the closest that I imagine that "service" means -- then join in the reservations table and filter:
SELECT customer_customer_id, AVG(avg_reservation_price)
FROM (SELECT i.customer_customer_id, i.reservation_reservation_id,
AVG(i.price) as avg_reservation_price
FROM invoice i JOIN
reservation r
ON i.reservation_reservation_id = r.reservation_id
WHERE r.checkup_type = ?
GROUP BY i.customer_customer_id, i.reservation_reservation_id
) ir
GROUP BY customer_customer_id;
You might want to try the below:
with aux (gr, subgr, val) as (
select 'a', 'a1', 1 from dual union all
select 'a', 'a2', 2 from dual union all
select 'a', 'a3', 3 from dual union all
select 'a', 'a4', 4 from dual union all
select 'b', 'b1', 5 from dual union all
select 'b', 'b2', 6 from dual union all
select 'b', 'b3', 7 from dual union all
select 'b', 'b4', 8 from dual)
SELECT
gr,
avg(val) average_gr,
avg(avg(val)) over () average_total
FROM
aux
group by gr;
Which, applied to your table, would result in:
SELECT
reservation_id,
avg(price) average_rn,
avg(avg(price)) over () average_total
FROM
invoices
group by reservation_id;
i'm working with oracle, plSql, i need to query a table and select the max id where a key is matched, now i have this query
select t.* from (
select distinct (TO_CHAR(I.DATE, 'YYMMDD') || I.AUTH_CODE || I.AMOUNT || I.CARD_NUMBER) as kies, I.SID as ids
from transactions I) t group by kies, ids order by ids desc;
It's displaying this data
If i remove the ID from the query, it displays the distinct keys (in the query i use the alias KIES because keys was in blue, so i thought it might be a reserved word)
How can i display the max id (last one inserted) for every different key without displaying all the data like in the first image??
greetings.
Do you just want aggregation?
select thekey, max(sid)
from (select t.*,
(TO_CHAR(t.DATE, 'YYMMDD') || t.AUTH_CODE || t.AMOUNT || t.CARD_NUMBER) as thekey,
t.SID
from transactions t
) t
group by thekey
order by max(ids) desc;
Since you haven't provided data in text format, its difficult to type such long numbers and recreated the data.
However I think you can simply use the MAX analytical function to achieve your results.
with data as (
select 1111 keys,1 id from dual
union
select 2222, 1 from dual
union
select 1111, 2 from dual
union
select 2222,3 from dual
union
select 9999, 1 from dual
union
select 1111, 5 from dual
)
select distinct keys, max(id) over( partition by (keys)) from data
This query returns -
KEYS MAX(ID)OVER(PARTITIONBY(KEYS))
1111 5
9999 1
2222 3
I have a subquery inside a big query which returns multiple values sometime and some time only one value. Below is my query and the returned values
select tran.customer_type from transaction_record tran where tran.TRANSACTION_ID=txn.id
customer_type can be 2 records - "LP" and "NA"
or
customer_type can be 2 records - "SOEMTHING ELSE" and "NA"
or
customer_type can be 1 records - "NA"
Here my probem is if i have 2 records i have to print value without NA and if i have one record i have to print what ever be the value is
Not exectly efficient (2 queries), but it should work!
Inner query counts status, id combinatios per group and outer query
removes all NA statuses that have another record on same ID.
Innermost query is just for table simulation (I like it more than create table, insert scripts).
SELECT * FROM
(
SELECT status, id, count(*)
OVER (PARTITION BY id ORDER BY 3 ) AS rn
from (
SELECT 'NA' status, 1 id FROM dual
UNION ALL
SELECT 'LP' status, 1 id FROM dual
UNION ALL
SELECT 'NA' status, 2 id FROM dual
UNION ALL
SELECT 'SOEMTHING ELSE' status, 2 id FROM dual
UNION ALL
SELECT 'NA' status, 3 id FROM dual
UNION ALL
SELECT 'NA' status, 5 id FROM dual
UNION ALL
SELECT 'LP' status, 5 id FROM dual
UNION ALL
SELECT 'NA' status, 6 id FROM dual
UNION ALL
SELECT 'SOEMTHING ELSE' status, 6 id FROM dual
UNION ALL
SELECT 'NA' status, 22 id FROM dual
))
WHERE NOT (status = 'NA' AND rn=2)
I have a SQL query.
Join of two columns.
I want to sort my search results by a column of the child table which is neither in select clause not in group by ( as I cannot group by it and cannot include it in the select ).
Is there some way I can achieve it?
In SQL Server, it results in error
Column "test2.DATE" is invalid in the ORDER BY clause because it is not contained in either an aggregate function or the GROUP BY clause.:
Fiddle here : http://sqlfiddle.com/#!6/d3d28/1
In Oracle, it results in error
ORA-00979: not a GROUP BY expression
00979. 00000 - "not a GROUP BY expression"
With test2 as
(
SELECT 1 ID, 'Hari' fName,30 KEYID ,sysdate DATEE FROM DUAL UNION ALL
SELECT 1, 'Hari' ,20 , sysdate FROM DUAL UNION ALL
SELECT 2, 'John' ,55, sysdate FROM DUAL UNION ALL
SELECT 2, 'John' ,89, sysdate FROM DUAL UNION ALL
SELECT 2, 'John' ,38, sysdate FROM DUAL
)
select id, fname, sum(keyid) from test2
group by id, fname
order by dateE desc;
So, in oracle, it is advisable to include the child-table column in your select clause. In your display UI Logic/resultset processing logic, you can consider ignoring the column.
It doesn't really make sense to order by a field that you are removing duplicates from, since some of the values that are removed could affect the sort order. Just using the example of Hari and John above, imagine this data:
1, 'Hari', 4
1, 'Hari', 6
2, 'John', 5
2, 'John', 7
2, 'John', 8
If you want these to be ordered Hari then John, because Hari has the lowest sort field and John has the next lowest (i.e. for the purposes of ordering, you ignore the sort field values 6, 7 and 8) then order by Min(SortField)
Again, using Nishanthi's example, the query would become something like this:
select id, fname, sum(keyid) from test2
group by id, fname
order by Min(dateE) desc;