I have a table USERS with 3 columns
user_id, user_status and usr_update.
This last column says the date and time of the last change of status, I want to get the last change of status of a user.
I try this but doesn't work.
SELECT user_id, user_status, max(usr_update)
FROM USERS u1 INNER JOIN USERS u2
ON u1.user_id=u2.user_id
WHERE u1.user_id='123456' AND
u1.user_status<>u2.user_status
anyone can help?
#jarlh
it's ok but what if I have more consecutive record with the same state and I want to get the firs record with the new state?
for example
I want to get the record (id_15,blocked,17/10/2015)
SELECT user_id, user_status, usr_update
FROM USERS u1
WHERE NOT EXISTS (select 1 from users u2
where u1.user_id=u2.user_id
and u2.usr_update > u1.usr_update)
I.e. return a row if there are no later row for the same user.
If you only care about one user, then use order by and fetch only one row:
SELECT u.*
FROM (SELECT u.*
FROM users u
WHERE u.user_id = '123456'
ORDER BY u.usr_update DESC
) u
WHERE rownum = 1;
(Note: In Oracle 12+, you can use FETCH FIRST 1 ROW ONLY so the subquery is not needed.)
You can also do this using keep:
SELECT u.user_id, MAX(u.usr_update),
MAX(user_status) KEEP (DENSE_RANK FIRST OVER ORDER BY u.usr_update DESC) as last_user_status
FROM users u
WHERE u.user_id = '123456'
GROUP BY u.user_id;
This method will work without the WHERE clause. And, in my experience, KEEP performs quite well.
Related
i have to fetch the details of ride provider who have offered their ride most to users.
the user_id in user_detail table is same as ride_provider_id in RIDE table.
i tried this but getting error 'ORA-00920: invalid relational operator' at last line ;
select u.*
from user_details u,
(select ride_provider_id,count(ride_provider_id) as of_ride
from ride
group by ride_provider_id) r2
where u.user_id= r2.ride_provider_id
having max(r2.of_ride);
In Oracle, you can phrase this using order by and the fetch first clause:
select u.*
from user_details u join
(select ride_provider_id, count(*) as of_ride
from ride
group by ride_provider_id
) r
on u.user_id = r.ride_provider_id
order by of_ride desc
fetch first 1 row only;
However, this seems rather inefficient. If you are using a subquery for the count, then the query can do the limit in the subquery:
select u.*
from user_details u join
(select ride_provider_id, count(*) as of_ride
from ride
group by ride_provider_id
order by count(*) desc
fetch first 1 row only
) r
on u.user_id = r.ride_provider_id
I am using python on a SQlite3 DB i created. I have the DB created and currently just using command line to try and get the sql statement correct.
I have 2 tables.
Table 1 - users
user_id, name, message_count
Table 2 - messages
id, date, message, user_id
When I setup table two, I added this statement in the creation of my messages table, but I have no clue what, if anything, it does:
FOREIGN KEY (user_id) REFERENCES users (user_id)
What I am trying to do is return a list containing the name and message count during 2020. I have used this statement to get the TOTAL number of posts in 2020, and it works:
SELECT COUNT(*) FROM messages WHERE substr(date,1,4)='2020';
But I am struggling with figuring out if I should Join the tables, or if there is a way to pull just the info I need. The statement I want would look something like this:
SELECT name, COUNT(*) FROM users JOIN messages ON messages.user_id = users.user_id WHERE substr(date,1,4)='2020';
One option uses a correlated subquery:
select u.*,
(
select count(*)
from messages m
where m.user_id = u.user_id and m.date >= '2020-01-01' and m.date < '2021-01-01'
) as cnt_messages
from users u
This query would take advantage of an index on messages(user_id, date).
You could also join and aggregate. If you want to allow users that have no messages, a left join is a appropriate:
select u.name, count(m.user_id) as cnt_messages
from users u
left join messages m
on m.user_id = u.user_id and m.date >= '2020-01-01' and m.date < '2021-01-01'
group by u.user_id, u.name
Note that it is more efficient to filter the date column against literal dates than applying a function on it (which precludes the use of an index).
You are missing a GROUP BY clause to group by user:
SELECT u.user_id, u.name, COUNT(*) AS counter
FROM users u JOIN messages m
ON m.user_id = u.user_id
WHERE substr(m.date,1,4)='2020'
GROUP BY u.user_id, u.name
I've seen many posts about this subject but none of the solutions solved my problem.
In a nutshell, I have a users table and a user_history table. Each user can have 0 or more user_history entries. The user_history table has a status column. All I want to do is get a list of users and the value of the status column for their most recent user_history entry. And I can't get it to work. I've tried:
select u.id, u.name,
(select status from (select status, rownum as rn from user_history uh where uh.user_id = u.id
order by created_date desc) where rn = 1) status
from users u;
This gives me a "ORA-00904: invalid identifier, u.id" error. From what I've read, Oracle does not allow you to access the outer-select 'u.id' from within a sub-sub-select (the one with rownum). From the first sub-select it works fine but as I said, I can have n entries in user_history, I only need the most recent.
I've also tried using an inner join:
select u.id, u.name, h.status
from users u
inner join (select user_id, status, rownum as rn from user_history where user_id = u.id order by created_date desc) h on u.id = h.user_id where h.rn = 1;
This gives me the dreaded "ORA-06553: wrong number or types of arguments in call to u" ... which I tried fixing by using distinct but to no avail.
I've also tried using row_number(), over and partition ... other types of inner joins with select ... nothing gets me the data I need.
Can someone give me a hand with this (seemingly) simple query?
In old days query would look something like this
select
u.id,
u.name,
uh.status
from
users u
inner join
(select
user_id,
status
from
user_history h
where
created_date = (select
max(created_date)
from
user_history d
where
h.user_id = d.user_id)
) uh
on u.id = uh.user_id;
What you have here is a correlated subquery that will get you latest date in history for the user. It is going to execute for each row so it is a bit slow performer. And you Join it with your user table to get your status.
I haven't tested it but it looks right.
Would something like this work? It would also eliminate the scalar within your query and be a little easier to debug, since you can run the inner query (uh) independently and evaluate its results.
with uh as (
select
u.id, u.name, uh.status, uh.created_date,
max (uh.created_date) over (partition by uh.user_id) as max_date
from
users u,
user_history uh
where
u.id = uh.user_id
)
select
id, name, status
from uh
where created_date = max_date
-- Edit --
For what it's worth, I loaded some sample data:
Users
1 Bilbo
2 Fatty
3 Pippin
4 Balin
User History
1 one 1/1/2014
1 two 1/2/2014
1 three 1/3/2014
2 four 1/4/2014
2 five 1/5/2014
2 six 1/6/2014
3 seven 1/7/2014
3 eight 1/8/2014
3 nine 1/9/2014
This was the output:
1 Bilbo three
2 Fatty six
3 Pippin nine
Here is the row_number alternative if you have multiple history records with the exact same "date" field.
with uh as (
select
u.id, u.name, uh.status,
row_number() over
(partition by u.id order by uh.created_date desc) as rn
from
users u,
user_history uh
where
u.id = uh.user_id
)
select
id, name, status
from uh
where rn = 1
I wanted to know what would be the best way to get a count of all the active connections per user in a DB setup like this. Only the first two groups should be used in the query. The Result Set is what I would like the output of the query to look like.
One thing to keep in mind is that it is possible that a Users record might have been deleted and not reflected in the Connections table. The result set should only count connections with other accounts that are still in the users table. I would also like to sort the results by the Count.
SELECT Users.UserId,count(*) Count
FROM ConnectionsTable
JOIN Users ON ( Users.UserId = Requestor OR Users.UserId = Requestee)
GROUP BY Users.UserId
ORDER BY count(*) DESC
SELECT source.UserId, COUNT(*) as [Count]
FROM
(
(
SELECT Requestor as UserID
FROM Connections
)
UNION ALL
(
SELECT Requestee as UserID
FROM Connections
)
) source
WHERE Exists (SELECT top 1 1 FROM Users us WHERE us.UserId = source.UserId)
GROUP BY source.UserId
I'm trying to turn this query into a view:
SELECT t.*
FROM user t
JOIN (SELECT t.UserId,
MAX( t.creationDate ) 'max_date'
FROM user t
GROUP BY t.UserId) x ON x.UserId = t.UserId
AND x.max_date = t.creationDate
But views do not accept subqueries.
What this does is look for the latest, newest record of a user.
I got the idea from this other stackoverflow question
Is there a way to turn this into a query with joins, perhaps?
Create two views
Create View MaxCreationDate
As
SELECT t.userId, Max(t2.CreationDate) MaxCreated
FROM user t
Group By t.UserId
Create View UserWithMaxDate
As
Select t.*, m.MaxCreated From user t
Join MaxCreationDate m
On m.UserId= t.UserId
and then just call the second one...
EDIT: hey, based on comment from Quassnoi, and your inclusion of
where t.CreationDate = MaxDate in yr orig sql, I wonder if you want to see all rows for each distinct user, with the max creation date for that user in every row, or, do you want only one row per user, the one row that was created most recently?
If the latter is the case, as #Quassnoi suggested in comment, change the second view query as follows
Create View UserWithMaxDate
As
Select t.*, m.MaxCreated From user t
Join MaxCreationDate m
On m.UserId= t.UserId
And m.MaxCreated = t.Creationdate
CREATE INDEX ix_user_userid_creationdate_id ON user (userid, creationdate, id);
CREATE VIEW v_duser AS
SELECT DISTINCT userId
FROM user;
CREATE VIEW v_lastuser AS
SELECT u.*
FROM v_duser ud
JOIN user u
ON u.id =
(
SELECT ui.id
FROM user ui
WHERE ui.userid = ud.userid
ORDER BY
ui.userid DESC, ui.creationdate DESC, ui.id DESC
LIMIT 1
);
This is fast and deals with possible duplicates on (userid, creationdate).