Oracle: earliest date of stay (two columns) - sql

i have three columns id_user, date_stay_start, date_stay_stop and I need to return complete date of the first stay (the oldest).
I am currently have something like this:
SELECT users.id_user, Min(orders.date_stay_start), Min(orders.date_stay_stop)
FROM users
JOIN orders ON users.id_user=orders.id_user
WHERE orders.date_stay_start IS NOT NULL
GROUP BY users.id_user;
But there is a problem. If I have two orders from one customer like this:
first order 02/Jun/2014 (date_stay_start) 10/Jun/2014
(date_stay_stop) and
second order 04/Jun/2014 (date_stay_start) 8/Jun/2014
(date_stay_stop).
The returned result will contain 02/Jun/2014 (date_stay_start) and 8/Jun/2014 (date_stay_stop).
But it should be 02/Jun/2014 (date_stay_start) 10/Jun/2014 (date_stay_stop).
I am using Oracle 11g. Thank you for any advice.

Something like this may work...
SELECT users.id_user, orders.date_stay_start, orders.date_stay_stop
FROM users
JOIN orders
ON users.id_user=orders.id_user
INNER JOIN (Select Min(Orders.date_Stay_start) DSS, id_user from orders group by ID_user) o
ON O.DSS = orders.date_stay_start
and O.id_user = orders.Id_user
WHERE orders.date_stay_start IS NOT NULL
GROUP BY users.id_user;

Or you can do something like this
select * from (
SELECT u.id_user
,o.date_stay_start
,o.date_stay_stop
,row_number() over (partition by u.id_user order by o.date_stay_start) rn
FROM users u
JOIN orders o
ON u.id_user = o.id_user
WHERE o.date_stay_start IS NOT NULL
) where rn = 1;

Related

simple SQL subquery

It seems im a complete idiot when it comes to SQL....
All i need is get one value from other table, but there is multiple rows with same customerId on second table.. and i would need to get one with highest timestamp
CREATE OR REPLACE VIEW CUS_SETTINGS as
SELECT
c.id as id,
c.LANG as Language,
c.ALLOWEMAIL as AllowEmail,
l.CONFIRMED as confirmed
FROM cus.CUSTOMER c
????? something with l
/
LEFT JOIN will bring every row so i have multiple duplicate id's
What i need is propably subquery, but i cant get it to work...
(SELECT CONFIRMED FROM settings WHERE ?? c.id == l.id ?? AND MAX(TIMESTAMP) )
i've tried many many variations of joins and subqueries.. but for some reason.. SQL is just
too confusing....
You can use a ROW_NUMBER() in the subquery:
SELECT c.id as id, c.LANG as Language, c.ALLOWEMAIL as AllowEmail,
l.CONFIRMED as confirmed
FROM cus.CUSTOMER c JOIN
(SELECT s.*,
ROW_NUMBER() OVER (PARTITION BY s.id ORDER BY s.timestamp DESC) as seqnum
FROM settings s
) s
ON s.id = c.id AND s.seqnum = 1;
Note: You might want a LEFT JOIN if you want to keep all customers, even those with no settings.
You can use analytic functions. MAX() OVER(PARTITION BY) clause can give you max timestamped id.
Analytic Functions Docs 11gR2
SELECT SECONDD.CONFIRMED
FROM CUSTOMER CU
INNER JOIN
(SELECT
*
FROM (SELECT SECONDD.*,
MAX (S.TIMESTAMP) OVER (PARTITION BY S.ID)
AS MAXTIMESTAMP
FROM SETTINGS SECONDD)
WHERE TIMESTAMP = MAXTIMESTAMP) SECONDD
ON SECONDD.ID = CU.ID
Don't worry; while this sounds very basic, it isn't :-)
The easiest way to get the CONFIRMED for the latest TIMESTAMP in Oracle is KEEP LAST. E.g.:
SELECT customer_id, MAX(confirmed) KEEP (DENSE_RANK LAST ORDER BY timestamp)
FROM settings
GROUP BY customer_id;
The related CREATE VIEW statement:
CREATE OR REPLACE VIEW cus_settings as
SELECT
c.id AS id,
c.lang AS language,
c.allowemail AS allowemail,
l.last_confirmed AS confirmed
FROM cus.customer c
LEFT JOIN
(
SELECT
customer_id,
MAX(confirmed) KEEP (DENSE_RANK LAST ORDER BY timestamp) AS last_confirmed
FROM settings
GROUP BY customer_id;
) l ON l.customer_id = c.id;
Or:
CREATE OR REPLACE VIEW cus_settings as
SELECT
c.id AS id,
c.lang AS language,
c.allowemail AS allowemail,
(
SELECT MAX(confirmed) KEEP (DENSE_RANK LAST ORDER BY timestamp)
FROM settings s
WHERE s.customer_id = c.id
) AS confirmed
FROM cus.customer c;

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

How to group my table for latest date and ID?

I have a table like this:
I need group this table latest date for every ID.
I mean, I want to get last row every ID. Here is my query:
SELECT DISTINCT ch.Date,ID FROM dbo.tblrisk AS rk
inner join (Select TableIdentity, [Date] from tblCommonHistory ) ch
ON ch.TableIDentity = rk.ID order by ID
How can I do what I want?
EDIT: This query worked for me:
SELECT DISTINCT ch.dt,ID FROM dbo.tblrisk AS rk
inner join (Select TableIdentity, max([Date]) as dt from tblCommonHistory group by TableIdentity) ch ON ch.TableIDentity = rk.ID order by ID
Just use aggregation:
select TableIdentity, max([date])
from tblCommonHistory
group by TableIdentity;
Your question only mentions one table. Your query has two; I don't understand the discrepancy.
It's strange that you have duplicated TableIdentity in tblCommonHistory, but otherwise you should not be getting multiple dates for the same ID from your query.
And also, the only reason to join the 2 tables seems to be that you need to skip those ID that are not present in the tblrisk (is it what you need to do?)
In that case, I'd suggest
SELECT max(ch.Date) AS [Date],ID FROM dbo.tblrisk AS rk
inner join tblCommonHistory AS ch ON ch.TableIDentity = rk.ID
group by ID order by ID

i want to modify this SQL statement to return only distinct rows of a column

select
picks.`fbid`,
picks.`time`,
categories.`name` as cname,
options.`name` as oname,
users.`name`
from
picks
left join categories
on (categories.`id` = picks.`cid`)
left join options
on (options.`id` = picks.oid)
left join users
on (users.fbid = picks.`fbid`)
order by
time desc
that query returns a result that like:
my question is.... I would like to modify the query to select only DISTINCT fbid's. (perhaps the first row only sorted by time)
can someone help with this?
select
p2.fbid,
p2.time,
c.`name` as cname,
o.`name` as oname,
u.`name`
from
( select p1.fbid,
min( p1.time ) FirstTimePerID
from picks p1
group by p1.fbid ) as FirstPerID
JOIN Picks p2
on FirstPerID.fbid = p2.fbid
AND FirstPerID.FirstTimePerID = p2.time
LEFT JOIN Categories c
on p2.cid = c.id
LEFT JOIN Options o
on p2.oid = o.id
LEFT JOIN Users u
on p2.fbid = u.fbid
order by
time desc
I don't know why you originally had LEFT JOINs, as it appears that all picks must be associated with a valid category, option and user... I would then remove the left, and change them to INNER joins instead.
The first inner query grabs for each fbid, the FIRST entry time which will result in a single entity for the FBID. From that, it re-joins to the picks table for the same ID and timeslot... then continues for the rest of the category, options, users join criteria of that single entry.
2 options, you could write a group by clause.
Or you could write a nested query joined back to itself to get pertinent info.
Nested aliased table:
SELECT
n.fBids
FROM
MyTable t
INNER JOIN
(SELECT DISTINCT fBids
FROM MyTable) n
ON n.ID = t.ID
Or group by option
SELECT fBId from MyTable
GROUP BY fBID
select picks.`fbid`, picks.`time`, categories.`name` as cname,
options.`name` as oname, users.`name` from picks left join categories
on (categories.`id` = picks.`cid`) left join options on (options.`id` = picks.oid)
left join users on (users.fbid = picks.`fbid`)
order by time desc GROUP BY picks.`fbid`
select
picks.fbid,
MIN(picks.time) as first_time,
MAX(picks.time) as last_time
from
picks
group by
picks.fbid
order by
MIN(picks.time) desc
However, if you want only distinct fbid's you cannot display cname and other columns at the same time.

SQL query for join with condition

I have these two tables:
Customers: Id, Name
Orders: Id, CustomerId, Time, Status
I want to get a list of customers for which the LAST order does not have a status of 'Wrong'.
I know how to use a LEFT JOIN to get a count of orders for each customer, but I don't know how I can use this statement for what I want. Maybe a JOIN is not the right thing to use too, I'm not sure.
It's possible that customers do not have any order, and they should be returned.
I'm abstracting the real tables here, but the scenario is for a windows phone app sending notifications. I want to get all clients for which their last notification does not have a 'Dropped' status. I can sort their notifications (orders) by the 'Time' field. Thanks for the help, while I continue experimenting with subqueries in the where clause.
Select ...
From Customers As C
Where Not Exists (
Select 1
From Orders As O1
Join (
Select O2.CustomerId, Max( O2.Time ) As Time
From Orders As O2
Group By O2.CustomerId
) As LastOrderTime
On LastOrderTime.CustomerId = O1.CustomerId
And LastOrderTime.Time = O1.Time
Where O1.Status = 'Dropped'
And O1.CustomerId = C.Id
)
There are obviously alternatives based on the actual database product and version. For example, in SQL Server one could use the TOP command or a CTE perhaps. However, without knowing what specific product is being used, the above solution should produce the results you want in almost any database product.
Addition
If you were using a product that supported ranking functions (which database product and version isn't mentioned) and common-table expressions, then an alternative solution might be something like so:
With RankedOrders As
(
Select O.CustomerId, O.Status
, Row_Number() Over( Partition By CustomerId Order By Time Desc ) As Rnk
From Orders As O
)
Select ...
From Customers
Where Not Exists (
Select 1
From RankedOrders As O1
Where O1.CustomerId = C.Id
And O1.Rnk = 1
And O1.Status = 'Dropped'
)
Assuming Last order refers to the Time column here is my query:
SELECT C.Id,
C.Name,
MAX(O.Time)
FROM
Customers C
INNER JOIN Orders O
ON C.Id = O.CustomerId
WHERE
O.Status != 'Wrong'
GROUP BY C.Id,
C.Name
EDIT:
Regarding your table configuration. You should really consider revising the structure to include a third table. They would look like this:
Customer
CustomerId | Name
Order
OrderId | Status | Time
CompletedOrders
CoId | CustomerId | OrderId
Now what you do is store the info about a customer or order in their respective tables ... then when an order is made you just create a CompletedOrders entry with the ids of the 2 individual records. This will allow for a 1 to Many relationship between customer and orders.
Didn't check it out, but something like this?
SELECT c.CustmerId, c.Name, MAX(o.Time)
FROM Customers c
LEFT JOIN Orders o ON o.CustomerId = c.CustomerId
WHERE o.Status <> 'Wrong'
GROUP BY c.CustomerId, C.Name
You can get list of customers with the LAST order which has status of 'Wrong' with something like
select customerId from orders where status='Wrong'
group by customerId
having time=max(time)