How to select oldest record from sql - sql

So I have a table of different appraisals saved for a lot of different vehicles and I want to select all appraisals with specific appraisal type but there can be more than 1 entries for the specific record id with that type and I only want to select the oldest
So I have this query (results below)
select
p.seller_opportunity_id
, p.created_at
, p.created_by
, p.type
, p.pricing_output_quote3_rounded_list_price_usd
from
frunk.pricing_events as p
inner join database.opportunity o
inner join database.vehicle_c v on
o.vehicle_id_c = v.id on
p.seller_opportunity_id = o.id
where
o.auto_reject_c is false
and o.stage_name not in (
'Lost'
, 'Sold'
, 'Handover'
)
-- and p.type = 'appraisal-escalated'
and o.id = 'id'
order by
p.created_at desc
Which results in this
Image URL
I want to create a nested query where I can get the pricing_output_quote3_rounded_list_price_usd for one seller_opportunity_id both from the type appraisal-escalated and manual-quote with the values of first records (there can be several as shown on screenshot)
Please note that the o.id where clause is for example sake and in the actual query I'd be querying the whole table with all the ids so adding
where p.created_at = (select min(p.created_at) from frunk) would not work

Use a ranking function like dense_rank.
select *
from (select p.*
,dense_rank() over(partition by seller_opportunity_id order by created_at) as rnk
from appraisals
where type = 'appraisal-escalated'
) t
where rnk = 1
Read more about the function in the documentation

Related

Oracle sql query that returns customers who are coming for the first time in property

I have 3 tables: customer, property and stays. Table customer contains all the data about customers (customer_id, name, surname, email...). Table property contains the list of all the properties (property_id, property_name...) and table stays contains all the earlier stays of customers (customer_id, property_id, stay_id, arrival_date, departure_date...).
Some customers stayed multiple times in more than one properties and some customers are coming for the first time.
Can someone please explain oracle sql query which returns only the customers who are stying in any of the properties for the first time.
Sorry guys for answering late..
This is what I got so far.
Tables:
Customer $A$
Stays $B$
Property $C$
Customer_Fragments $D$
SELECT a.RIID_,
sub.CUSTOMER_ID_,
sub.PROPERTY_ID,
b.ARRIVAL_DATE,
c.PROPERTY_SEGMENT,
ROW_NUMBER() OVER (
PARTITION BY sub.CUSTOMER_ID_,
sub.PROPERTY_ID
ORDER BY
sub.CUSTOMER_ID_ asc
) RN
FROM
(
SELECT
b.CUSTOMER_ID_,
b.PROPERTY_ID
FROM
$B$ b
GROUP BY
b.CUSTOMER_ID_,
b.PROPERTY_ID
HAVING
COUNT(*)= 1
) sub
INNER JOIN $A$ a ON sub.CUSTOMER_ID_ = a.CUSTOMER_ID_
INNER JOIN $B$ b ON sub.CUSTOMER_ID_ = b.CUSTOMER_ID_
INNER JOIN $C$ c ON sub.PROPERTY_ID = c.PROPERTY_ID
LEFT JOIN $D$ d ON a.RIID_ = d.RIID_
WHERE
b.ARRIVAL_DATE = TRUNC(SYSDATE + 7)
AND c.PROPERTY_DESTINATION = 'Destination1'
AND lower(c.NAME_) NOT LIKE ('unknown%')
AND a.NWL_PERMISSION_STATUS = 'I'
AND a.EMAIL_DOMAIN_ NOT IN ('abuse.com', 'guest.booking.com')
AND (d.BLACKLISTED != 'Y'
or d.BLACKLISTED is null
)
I want to select all customers who will come to Destination1, 7days from today to inform them about some activities. Customers can book several
properties in Destination1 and have the same arrival date (example: I can book a room in property1 for me and my wife and also book a room in property2 for my friends.. and we all come to destination1 on the same arrival date).
When this is the case I want to send just one info email to a customer and not two emails. The above SQL query returns two rows when this is the case and I want it to return just one row (one row = one email).
It is always required to post a code you have already tried to write so that we can than help you with eventual mistakes.
After that being said, I'll try to help you nevertheless, writing the full code.
Try this:
select cus.*
from customers cus
join stays st
on st.customer_id = cus.customer_id
where st.arrival_date >= YOUR_DATE --for example SYSDATE or TRUNC(SYSDATE)
and 1 = (select count(*)
from stays st2
where st2.customer_id = cus.customer_id)
You haven't specified it, but I GUESS that you are interested in getting the first-time-customers whose arrival date will be at or after some specified date. I've written that into my code in WHERE clause, where you should input such a date.
If you remove that part of the WHERE clause, you'll get all the customers that stayed just once (even if that one and only stay was 10 years ago, for example). What's more, if you remove that part of the code, you can than also remove the join on stays st table from the query too, as the only reason for that join was the need to have access to arrival date.
If you need explanations for some other parts of the code too, ask in the comments for this answer.
I hope I helped!
WITH first_stays (customer_id, property_id, first_time_arrival_date, stay_no) AS
(
SELECT s.customer_id
, s.property_id
, s.arrival_date AS first_time_arrival_date
, ROW_NUMBER() OVER (PARTITION BY s.customer_id, s.property_id ORDER BY s.arrival_date) stay_no
FROM stays s
)
SELECT c.surname AS customer_surname
, c.name AS customer_name
, p.property_name
, s.first_time_arrival_date
FROM customer c
INNER
JOIN first_stays s
ON s.customer_id = c.customer_id
AND s.stay_no = 1
INNER
JOIN property p
ON p.property_id = s.property_id
The first part WITH first_stays is a CTE (Common Table Expression, called subquery factoring in Oracle) that will number the stays for each pair (customer_id, property_id) ordered by the arrival date using a window function ROW_NUMBER(). Then just join those values to the customer and property tables to get their names or whatever, and apply stay_no = 1 (first stay) condition.
If I understand the question correctly, this is not a complicated query:
select c.*
from c join
(select s.customer_id
from stays s
group by s.customer_id
having count(*) = 1
) s
on s.customer_id = c.customer_id;

Oracle SQL STATS_MODE with two tables

I have the tables listed in the image. I need to display the institution and loan type of the most used financing plan in the sale_financing table. I have tried using the stats_mode function but I have not been able to get it to work. I am supposed to only display the most used financing plan and I keep getting 3 showing up. Here is an image of the tables.
My image may not work so here are the tables:
financing_plan
id
institution
loan_type
sale_financings
id
plan_id ------> foreign key linking to - financing_plan.id
I have tried several different ways in the Query Builder and I cannot get it to work.
Here is one :
SELECT
financing_plans.institution,
financing_plans.loan_type,
STATS_MODE(sale_financings.plan_id) AS stats_mode_plan_id
FROM
financing_plans
INNER JOIN sale_financings ON financing_plans.id =
sale_financings.plan_id
GROUP BY
financing_plans.institution,
financing_plans.loan_type
Another:
SELECT
financing_plans.institution,
financing_plans.loan_type,
STATS_MODE(sale_financings.plan_id) AS stats_mode_plan_id
FROM
financing_plans
INNER JOIN sale_financings ON financing_plans.id =
sale_financings.plan_id
GROUP BY
financing_plans.institution,
financing_plans.loan_type
HAVING
STATS_MODE(sale_financings.plan_id) = sale_financings.plan_id
Count the use of each plan_id, then rank these (using dense_rank()) by the count (descending order) allows "top" and "equal top" to be shown.
select
fp.institution, fp.loan_type, s.plan_count
from financing_plan fp
inner join (
select plan_id, plan_count, dense_rank() over(order by plan_count DESC) as rnk
from (
select plan_id, count(id) plan_count
from sale_financings
Group by plan_id
)
) s on fp.id = s.plan_id and s.rnk = 1
order by
fp.institution, fp.loan_type
;

How to filter data out, when using GROUP in SQL

I got this SQL-statement:
SELECT t.*
FROM (SELECT *
FROM accelerator_clinic_patient_status
ORDER BY status_id DESC) t
INNER JOIN accelerator_clinic_campaign_patient_signup signup
ON (signup.patient_id = t.patient_id)
INNER JOIN accelerator_clinic_campaign campaign
ON (signup.campaign_id = campaign.campaign_id
AND campaign.clinic_user_id = 4978)
GROUP BY t.patient_id
The code finds out the latest status in the table "accelerator_clinic_patient_status"
It contains columns patient_id which is a foregin-key, each patient_id can contain multiple status's.
But what I am interested in, is getting a list of patient id whose LATEST status is "Booked" -- I want to filter out Not Booked in the list, when doing the select-statement (for example in the posted image, the data should not be shown in the query, because the latest status is Not Booked). The code right now returns a list with the latest status.
Any idea how to do this?
Try This,
Please Improve the following code syntactically,
select *,Rank() over (partiton by X.Patient_Id order by X.date_added desc) as Rankk from (SELECT t.*
FROM (SELECT *
FROM accelerator_clinic_patient_status
ORDER BY status_id DESC) t
INNER JOIN accelerator_clinic_campaign_patient_signup signup
ON (signup.patient_id = t.patient_id)
INNER JOIN accelerator_clinic_campaign campaign
ON (signup.campaign_id = campaign.campaign_id
AND campaign.clinic_user_id = 4978)
GROUP BY t.patient_id) as X where Rankk=1 and Status = 'Booked'
In Mysql ,Something like this,
SET #rank=0;
SELECT #rank:=#rank+1,*
FROM (accelerator_clinic_patient_status
ORDER BY status_id DESC) t
INNER JOIN accelerator_clinic_campaign_patient_signup signup
ON (signup.patient_id = t.patient_id)
INNER JOIN accelerator_clinic_campaign campaign
ON (signup.campaign_id = campaign.campaign_id
AND campaign.clinic_user_id = 4978)
GROUP BY t.patient_id) X
Group By Patient_Id Order By date_added Desc

Find MAX with JOIN where Field also shows up in another Table

I have 3 tables: Master, Paper and iCodes. For a certain set of Master.Ref's, I need to find Max(Paper.Date), where the Paper.Code is also in the iCodes table (i.e., Paper.Code is a type of iCode). Master is joined to Paper by the File field.
EDIT:
I only need the Max(Paper.Date) its corresponding Code; I do not need all of the Codes.
I wrote the following but it is very slow. I have a few hundred ref #'s to look for. What is a better way to do this?
SELECT Master.Ref,
Paper.Code,
mp.MaxDate
FROM ( SELECT p.File ,
MAX(p.Date) AS MaxDate ,
FROM Paper AS p
LEFT JOIN Master AS m ON p.File = m.File
WHERE m.Ref IN ('ref1', 'ref2', 'ref3', 'ref4', 'ref5', 'ref6'... )
AND p.Code IN ( SELECT DISTINCT i.iCode
FROM iCodes AS i
)
GROUP BY p.File
) AS mp
LEFT JOIN Master ON mp.File = Master.File
LEFT JOIN Paper ON Master.File = Paper.File
AND mp.MaxDate = Paper.Date
WHERE Paper.Code IN ( SELECT DISTINCT iCodes.iCode
FROM iCodes
)
Does this do what you want?
SELECT m.Ref, p.Code, max(p.date)
FROM Master m LEFT JOIN
Paper
ON m.File = p.File
WHERE p.Code IN (SELECT DISTINCT iCodes.iCode FROM iCodes) and
m.Ref IN ('ref1','ref2','ref3','ref4','ref5','ref6'...)
GROUP BY m.Ref, p.Code;
EDIT:
To get the code on the max date, then use window functions:
select ref, code, date
from (SELECT m.Ref, p.Code, p.date
row_number() over (partition by m.Ref order by p.date desc) as seqnum
FROM Master m LEFT JOIN
Paper
ON m.File = p.File
WHERE p.Code IN (SELECT DISTINCT iCodes.iCode FROM iCodes) and
m.Ref IN ('ref1','ref2','ref3','ref4','ref5','ref6'...)
) mp
where seqnum = 1;
The function row_number() assigns a sequential number starting at 1 to a group of rows. The groups are defined by the partition by clause, so in this case everything with the same m.Ref value would be in a single group. Within the group, rows are assigned the number based on the order by clause. So, the one with the biggest date gets the value of 1. That is the row you want.

Complex Query duplicating Result (same id, different columns values)

I have this query, working great:
SELECT * FROM
(
select
p.id,
comparestrings('marco', pc.value) as similarity
from
unit u, person p
inner join person_field pc ON (p.id = pc.id_person)
inner join field c ON (pc.id_field = c.id AND c.flag_name = true)
where ( u.id = 1 ) AND p.id_unit = u.id
) as subQuery
where
similarity is not null
AND
similarity > 0.35
order by
similarity desc;
Let me explain the situation.
TABLES:
person ID as column.
field a table that represents a column, like name, varchar (something like that)
person_field represents the value of that person and that field.. Like this:
unit not relevant for this question
Eg.:
Person id 1
Field id 1 {name, eg)
value "Marco Noronha"
So the function "comparestrings" returns a double from 0 to 1, where 1 is exact ('Marco' == 'Marco').
So, I need all persons that have similarity above 0.35 and i also need its similarity.
No problem, the query works fine and as it was suppost to. But now I have a new requirement that, the table "person_field" will contain an alteration date, to keep track of the changes of those rows.
Eg.:
Person ID 1
Field ID 1
Value "Marco Noronha"
Date - 01/25/2013
Person ID 1
Field ID 1
Value "Marco Tulio Jacovine Noronha"
Date - 02/01/2013
So what I need to do, is consider ONLY the LATEST row!!
If I execute the same query the result would be (eg):
1, 0.8
1, 0.751121
2, 0.51212
3, 0.42454
//other results here, other 'person's
And lets supose that the value I want to bring is 1, 0.751121 (witch is the lattest value by DATE)
I think I should do something like order by date desc limit 1...
But if I do something like that, the query will return only ONE person =/
Like:
1, 0.751121
When I really want:
1, 0.751121
2, 0.51212
3, 0.42454
You can use DISTINCT ON(p.id) on the sub-query:
SELECT * FROM
(
select
DISTINCT ON(p.id)
p.id,
comparestrings('marco', pc.value) as similarity
from
unit u, person p
inner join person_field pc ON (p.id = pc.id_person)
inner join field c ON (pc.id_field = c.id AND c.flag_name = true)
where ( u.id = 1 ) AND p.id_unit = u.id
ORDER BY p.id, pc.alt_date DESC
) as subQuery
where
similarity is not null
AND
similarity > 0.35
order by
similarity desc;
Notice that, to make it work I needed to add ORDER BY p.id, pc.alt_date DESC:
p.id: required by DISTINCT ON (if you use ORDER BY, the first fields must be exactly the same as DISTINCT ON);
pc.alt_date DESC: the alter date you mentioned (we order desc, so we get the oldest ones by each p.id)
By the way, seems that you don't need a sub-query at all (just make sure comparestrings is marked as stable or immutable, and it'll be fast enough):
SELECT
DISTINCT ON(p.id)
p.id,
comparestrings('marco', pc.value) as similarity
FROM
unit u, person p
inner join person_field pc ON (p.id = pc.id_person)
inner join field c ON (pc.id_field = c.id AND c.flag_name = true)
WHERE ( u.id = 1 ) AND p.id_unit = u.id
AND COALESCE(comparestrings('marco', pc.value), 0.0) > 0.35
ORDER BY p.id, pc.alt_date DESC, similarity DESC;
Change the reference to person to a subquery as in the following example (the subquery is the one called p):
. . .
from unit u cross join
(select p.*
from (select p.*,
row_number() over (partition by person_id order by alterationdate desc) as seqnum
from person p
) p
where seqnum = 1
) p
. . .
This uses the row_number() function to identify the last row. I've used an additional subquery to limit the result just to the most recent. You could also include this in an on clause or a where clause.
I also changed the , to an explicit cross join.