I'm working with a third-party database of a vendor we use for our account management. One of the queries we need to run programmatically is to see which accounts are currently active. There is no single column for this -- status is tracked in a separate table from the main information table that tracks all changes in status, from activation to deletion.
I want to do a simple join like this:
SELECT u.id ,
s.status
FROM user_table u
JOIN status_table s ON u.id = s._id
WHERE s.acct_status = "ACTIVE"
OR s.new_status = "ACTIVE";
But this doesn't work because there might be a later record that sets the accounts status to TERMINATED or something else. Note: every account will have a status entry of one sort or another.
For the purposes of this question, it doesn't matter what the user table is like. The status table is very simple:
_id
date_entered
acct_status
new_status
I'm pretty sure that this query would get me the latest status update (thanks to this post, but I'm not sure how to throw in a join here:
select
*
from
(select
_id, new_status
from
aria.get_acct_status_history
order by date_entered desc) as t1
group by _id;
Any ideas?
If you need the latest record per user from your status table then you use a self join on data column by getting max date per user entries and i assume _id from status_table table refers to user id
SELECT s.* FROM status_table s
JOIN (
SELECT _id ,MAX(date_entered) date_entered
FROM status_table
GROUP BY _id
) s1
ON(s._id = s1._id AND s.date_entered = s1.date_entered )
WHERE s.acct_status = "ACTIVE" or s.new_status = "ACTIVE";
Later on you and join you users table to get the user info,joining with max of date column ie. AND s.date_entered = s1.date_entered will satisfy your criteria to have recent row per user entries
SELECT u.id, s.status
FROM user_table u
JOIN status_table s ON u.id = s._id
JOIN (
SELECT _id ,MAX(date_entered) date_entered
FROM status_table
GROUP BY _id
) s1
ON(s._id = s1._id AND s.date_entered = s1.date_entered )
WHERE s.acct_status = "ACTIVE" or s.new_status = "ACTIVE";
Related
I am trying to add a condition(subquery) that basically would filter the output but incase the subquery does not return anything, I want this condition to be ignored somehow.
my main query is very long and complicated so I will try to give a simple example here.
set #userid := 55;
select project, userid
from users_projects
where userid IN
(select userid from activeusers)
AND
project IN (select userid from paidprojects where userid = #userid)
So if select userid from paidprojects where userid = #userid returns an empty output, I want this last condition to be ignored.
I tried this
set #userid := 55;
select project, userid
from users_projects
where userid IN
(select userid from activeusers)
AND
project IN (IF count(select userid from paidprojects where userid = #userid)>0, (select userid from paidprojects where userid = #userid), (select userid from activeusers))
but it's not working and I am getting syntax error:(
So if select userid from paidprojects where userid = #userid returns an empty output, I want this last condition to be ignored.
That is, you want only paid projects if there are any. Otherwise, you want all (unpaid) projects.
First, I assume that you want to compare projects in the last query not a project to a user. That just seems broken.
An explicit way to write this logic is:
select up.project, up.userid
from users_projects up
where up.userid in (select au.userid from activeusers au) and
(up.project in (select pp.project from paidproject pp where pp.userid = #userid) or
not exists (select pp.project from paidproject pp where pp.userid = #userid)
);
Why would you do that ?
Let me see if I understood
you have
user
You’re users table
project
Where yow projects are
user_projects
I is guessing that’s an N to M
Question
Why do you have a
paidprojects table
That table can easily and should be a column on user_projects table as well as active users table that table can also be a column on users table is user active then true else false
Your problem can be solve by a simple left join
SELECT s.user_tbl_col, p.product _tbl_col
FROM users AS s
LEFT JOIN users_projects AS up ON u.id = up.userId
LEFT JOIN products AS p ON up.productID = p.id
If The user hadn’t buy none the users info would be the only data
I have a MYSQL query that I am having difficulties getting to do what I want.
I have a users table (userstbl) containing all my user records, and a listings table (listings) contains all listings posted by each user. I am trying to select the name and address of each user and provide a count of listings for each user which was listed between a certain date range, but only count adverts for unique category_id's which is working fine.
The issue is that I only want to count listings that have been published. I have another table which is identical to my listings table called "listings_log" and contains a record for every change made to every listing record. If one of the records in "listings_log" for the listing has a "listings_log.published=1" than the listing was published. Each record in the "listings_log" table has a "listing_id" which is the same as in the "listings" table.
This is the query I have now :
SELECT
userstbl.userid,
userstbl.fullname,
userstbl.fulladdress,
COUNT(DISTINCT(
CASE WHEN listings.ad_type = 1
AND DATE(listings.date_listed) BETWEEN '2018-01-01' AND '2018-04-01'
THEN listings.category_id
END )
) AS Listings_Count_2018,
DATE_FORMAT(userstbl.reg_date, "%d/%m/%Y") AS RegisteredDate
FROM
users
LEFT JOIN listings ON listings.userid = userstbl.user_id
GROUP BY userstbl.userid
This counts the number of unique listings records between the correct dates for each user.
But I somehow only need to count listings records, where there is a corresponding listings_log record for that listing with published set to "1". The "listings_log" table and "listings" table both have a common listing_id column, but the listings_log table can have multiple records for each listing showing every change to each listing.
So I want to also join on the listings_log.listing_id = listings.listing_id and at least one of the "listings_log" records for that "listing_id" has listings_log.published = "1".
As you did not provide sample tables and a minimal reproducible example, a lot of this is guesswork. I am assuming for each user you want the total number of listing records. I built up the SQL with subqueries that are meant to be read "from the inside out."
select u.userid, u.fullname, u.fulladdress, sq.count from usertbl u join (
select u.userid, sum(c.count) as count from usertbl u join (
select count(*) as count, l.userid, l.listing_id from listings l join (
select distinct listing_id from listings_log where listings_log.published = "1"
) ll on l.listing_id = ll.listing_id
and l.ad_type = 1
and date(l.date_listed) between '2018-01-01' and '2018-04-01'
group by l.userid, l.listing_id
) c on u.userid = c.userid
group by u.userid
) sq on u.userid = sq.userid
;
See DB Fiddle
I have two tables user & user login history. I need to make a report of the times a particular user is logging into the system. The table contains millions of rows of data. So running a nested query to fetch number of logins of users is taking a lot of time.
I am trying to loop through all the users and update the logins column. How can I do this in one query?
The schema is like this:
users table:
id INT(10)
username VARCHAR(7)
logins INT(10)
user_logs table:
id INT(10)
userid INT(10)
login_date DATETIME(19)
http://sqlfiddle.com/#!9/dc4149
I'm running this query
UPDATE users u
SET u.logins = (SELECT COUNT(*)
FROM user_logs
WHERE userid = u.id)
LIMIT 1
This is not working.
Is there any way how I could loop through users & update their respective login count?
I tried doing this with PHP but as the tables are very large. Doing this 1 by 1 takes very time.
Can I do this via command line?
An update should take so long, especially if you have proper indexed on both tables.
Try this:
UPDATE users u
INNER JOIN(SELECT ul.userid,count(1) as cnt FROM user_logs ul GROUP BY ul.userid) u2
ON(u2.userid = u.id)
SET u.logins = u2.cnt
Then make sure you have the following indexes:
users - (id,logins)
user_logins - (userid)
If that doesn't help - try doing this in two steps , build a derived table with the sub query results, and update by it :
CREATE TABLE temp_for_update AS(
SELECT ul.userid,count(1) as cnt
FROM user_logs ul
GROUP BY ul.userid);
CREATE INDEX YourIndex
ON temp_for_update (userid,cnt);
UPDATE users u
INNER JOIN temp_for_update u2
ON(u2.userid = u.id)
SET u.logins = u2.cnt
This should defiantly be faster.
Try using update join like
UPDATE users a
JOIN (
SELECT userid, COUNT(*) as count_login
FROM user_logs
GROUP BY userid) b ON b.userid = a.id
SET a.logins = b.count_login;
I have a query that produces a result like this:
The data is sorted by date DESC, then by time DESC, but also the common 'markers_name' elements are chunked together. (They're only chunked together for each date).
To do this I get the list of MAX(time) values for every combination of (markers_id, date) in conditions, then join that list to the row set I am getting from the present query, and use the MAX(time) values for sorting:
SELECT
m.name AS markers_name,
c.time AS conditions_time,
c.date AS conditions_date,
s.name AS station_name
FROM markers m
INNER JOIN conditions c ON c.markers_id = m.id
INNER JOIN station s ON c.station_id = s.id
INNER JOIN (
SELECT
markers_id,
date,
MAX(time) AS time
FROM conditions
GROUP BY
markers_id,
date
) mx ON c.markers_id = mx.markers_id AND c.date = mx.date
ORDER BY
c.date DESC,
mx.time DESC,
m.name DESC,
c.time DESC
Now I need to restrict user access to some of the rows.
The conditions table has a 'private' column. If 'private' is set to 1 only some people are allowed to see the query row. The people that can see it include the person that created the conditions report and that person's contacts. The conditions table has a 'user_id', which contains the id of the person that created the conditions report. The contacts are obtained from a 'contacts' table which has two fields: 'user_id' and 'friend_id'. I have the user_id of the person requesting the information.
To restate another way, I need to do something like this:
Do the query above, but also check to see if c.private is set to one.
If c.private is set to one use c.user_id to get that user's 'friend_id's from the contacts table.
If the user_id of the person requesting the information matches c.user_id or any of c.user_id's friends return the query row. If not, don't return that row or return something that indicates that the row is private (I could have a markers_name with the name "Private" in the database, for example.
If anyone has any ideas I would love to hear them. I struggled with this all day yesterday. Thank you.
Possibly just adding a filter like this would be enough:
…
WHERE c.Private <> 1
OR c.user_id = #user_id
OR c.user_id IN (
SELECT friend_id
FROM contacts WHERE user_id = #user_id
)
where #user_id is the ID of the person requesting the info.
This would prohibit the private rows from appearing in the output where inappropriate.
If, however, you'd rather like them to be there but be marked as Private (for being dealt with later in the client or something like that), you could use that filter as a column in your SELECT clause:
SELECT
NOT (
c.Private <> 1
OR c.user_id = #user_id
OR c.user_id IN (
SELECT friend_id
FROM contacts WHERE user_id = #user_id
)
) AS IsPrivate,
…
FROM …
I don't have similar tables to play around with, so I'm writing this for you to try out, alright? Here is the WHERE clause for you to add to your query:
WHERE
-- all non-1 valued `private` columns are public, right? remove if not
c.private <> 1
-- all private but #user_id is entitled to view
OR (
c.private = 1
AND (
(c.user_id = #user_id) -- requestor is creator
OR (
EXISTS (
SELECT ct.friend_id
FROM contacts ct
WHERE ct.user_id = c.user_id
AND friend_id = #user_id
) -- requestor is a friend of the creator
)
)
)
Again, I wasn't able to test this.. I'll leave that up to you for now.. so please let me know how it goes. :)
Two tables:
user (id, myValue, ...)
user_preferred (id, userid, preferredValue) fk userid -> user(id)
Explanation:
user is a table of all users. user_preferred is a table of any user's preferred values. A user can be listed multiple times in user_preferred but must have different values. Query should return all users that have a myValue that matches the preferred value of the given user. $userid is the php variable of the user passed.
The Trick:
A user could have no preference, in which case there is no entry in the user_preference table. When the above query is done, I want to return every user if the given user has no preference.
Analogy:
I'm at a bar and the bartender asks me what I want to drink. I say give me everything he has that matches my preference. The first round I say I like crappy beers. So he gives me a Fosters. Second round I say I have no preference and he gives me 12 pints ranging from Bud Light to Guinness. Instead of beers, these would be users. Get it?
Query (so far):
SELECT * FROM user WHERE
IF ((SELECT preferredValue FROM user_preferred WHERE userid = $userid) IS NULL,
1,
user.myValue ANY (SELECT preferredValue FROM user_preferred WHERE userid = $userid)
)
Additional Trick:
I don't want to run "SELECT preferredValue FROM user.preferred where id = $userid" twice. Can I save the results from the first run-time and somehow use it in place of the second?
SELECT *,(SELECT preferredValue FROM user_preferred WHERE userid = $userid) AS Result FROM user WHERE
IF (Result IS NULL,1,RESULT)
To return a list of users:
SELECT o.*
FROM `user` o
WHERE o.id IN
( SELECT DISTINCT m.userid
FROM user_preferred m
WHERE EXISTS
( SELECT 1 FROM user_preferred p
WHERE p.preferredValue = m.preferredValue
AND p.userid <> m.userid
AND p.userid = $userid )
)
OR ( o.id <> $userid AND NOT EXISTS
( SELECT 1
FROM user_preferred q
WHERE q.userid = $userid
)
)