Get the No of Pending, Accepted and Rejected Users from two tables - mysql

I have two tables namely register and expressinterest
Where register table contains (user related columns) some are -
i) matri_id (unique but not primary)
ii) mobile
iii) email
iv) last_login
and expressinterest table contains data related to the matches details where columns are namely
i) ei_sender
ii) ei_receiver
iii) ei_response
iv) ei_sent_date
I am comparing the matri_id of register table to ei_sender and ei_receiver of expressinterest table, where one user can send requests to another users and he can receive request from another users.
I have to get the count of Pending, Accepted and Rejected status of all the users present in the register table, but when I am running the query it's running very slow, It takes around 45-60 seconds to fetch only 5000 rows in which the data is not proper (a single ID is coming in 3 rows like Accepted in one row, Rejected in one row and Pending in one row), But I want all the counts to come in a single row like this
r.matri_id | r._email | r.mobile | pending_count | accepted_ count | rejected_count| r.last_login
Some queries which I had tried so far are
select r.matri_id, r.email, r.mobile, r.last_login, e.receiver_response, count(e.receiver_response), e.ei_sender, e.ei_receiver from register r, expressinterest e where r.matri_id = e.ei_sender or r.matri_id = e.ei_receiver GROUP BY e.receiver_response, r.matri_id ORDER BY r.last_login DESC
This is what I want but its taking 5-6 seconds to execute
select matri_id, email, mobile, last_login, (select count(ei_sender) from expressinterest where ei_receiver=matri_id and receiver_response = 'Pending') AS pending_count_mine,
(select count(ei_sender) from expressinterest where ei_sender=matri_id and receiver_response = 'Accepted') AS accepted_count,
(select count(ei_sender) from expressinterest where ei_sender=matri_id and receiver_response = 'Rejected') AS rejected_count FROM register ORDER BY last_login DESC
Thanks

You can replace the multiple correlated subqueries with a single subquery and a left join:
select r.matri_id,
r.email,
r.mobile,
r.last_login,
t.accepted_count,
t.rejected_count,
t.pending_count
from register r
left join (
select ei_sender,
sum(receiver_response = 'Accepted') as accepted_count,
sum(receiver_response = 'Rejected') as rejected_count,
sum(receiver_response = 'Pending') as pending_count
from expressinterest
where receiver_response in ('Rejected', 'Accepted', 'Pending')
group by ei_sender
) t on r.matri_id = t.ei_sender;

Related

Get Records From Table 1, Comparing With Multiple Records From Table 2

I have 2 tables (users and usages)
USERS TABLE
username usage
a 32
b 5
c 5
USAGES TABLE
username usage_added
a 7
b 7
c 7
a 30
I want to get all items from USERS table, that have USAGE BIGGER than X (in this case, let's say X is 30) AND if either NO RECORDS are found with the same username in USAGES TABLE or if the usage_added for this username in USAGES TABLE are SMALLER than X (30 in our case)
So in this case, it should return no records. I have a codeigniter query
$this->db->select('users.username');
$this->db->from('users');
$this->db->join('usages', 'usages.username = users.username','left');
$this->db->where("(usages.email is NULL OR (usages.usage_added<30 AND usages.username=users.username))", NULL, FALSE);
$this->db->where("users.usage>30", NULL, FALSE);
By using above query, I still get "username a" returned.
Normally it should not return user A, because user a already has date 30 added. But it seems it compares to first record (a=7) and it says a<30 and it shows it again.
I hope it makes sense and somebody can help.
Written SQL Server syntax, this query should work for you:
DECLARE #usage_limit int = 30;
SELECT A.username
FROM users as A
LEFT OUTER JOIN
(
SELECT username,
usage_added = sum(usage_added)
FROM usages
GROUP BY
username
) as B
ON A.username = B.username
WHERE A.usage > #usage_limit
AND (B.username is null OR B.usage_added < #usage_limit)
This returns no records.
Hope this helps!
You seem to be describing logic like this:
select u.*
from users u
where u.usage > 30 or
not exists (select 1
from usages us
where us.username = u.username and
us.usage > 30
);
You should replace the 30 with a parameter if it varies.

Trying to use multiple AS, but I'm getting: Subquery returns more than 1 row

I'm using 3 tables from my database which I read data for my rank (top15) table. I'm trying to fill one 'tr' with only one query (using multiple Aliases), but I'm stuck here:
My last try was:
SELECT DISTINCT(mapname),
(SELECT his_time FROM primekz_records
WHERE primekz_records.id=$player_id AND his_aa = 10 AND tp > 0) AS nub10,
(SELECT his_time FROM primekz_records
WHERE primekz_records.id=$player_id AND his_aa = 10 AND tp = 0) AS pro10
FROM primekz_records
JOIN primekz_players ON primekz_records.id=primekz_players.id
JOIN primekz_maps ON primekz_maps.mid=primekz_records.mid
WHERE primekz_players.id=$player_id
Tables are structured:
primekz_players( id, steamid, name ...)
primekz_maps( mid, mapname )
primekz_records( id, mid, his_time, his_aa, tp, ... ) <-- this means one ID(player) can be max 4 times for one mid (map), variations are: his_aa (10/100), tp (0/more)
If I try with only one alias I get this result, which is totally wrong (see Noob100 column).
https://i.snag.gy/tHpUK8.jpg
Does it have something to do with ROW_NUMBER() + 4x AS ?

How do I count multiple columns of events for users?

I have a table of events that stores the events for users and I want to get the number of two specific events for each user.
An example table is called "events" and it has 2 columns
user_id VARCHAR(50)
event_name VARCHAR(50)
The user_ids are all unique and the event names can be things like login, sent_message, liked_post
How do I, for example, query for the total messages sent per user AND the number of liked_posts per user?
This is the pattern of query you can use:
select user_id,
sent_message_count=sum(case when event_name = 'Sent Message' then 1 else 0 end),
liked_post_count=sum(case when event_name = 'Liked Post' then 1 else 0 end),
from events
group by user_id
Now, you just need to make sure the when part of each case statement fits the criteria you need. The pattern itself - summing a bunch of 1's where the criteria fits, is really the key to achieving the result you're after.
SELECT user_id,
SUM(IF(event_name = 'sent_message', 1, 0)) AS sent_message,
SUM(IF(event_name = 'liked_posts', 1, 0)) AS liked_posts
FROM `events`
GROUP BY user_id

mySQL: LEFT JOIN where joining needs to be done on different type of data

I have 2 my tables with data and 2 "not mine" tables (in ReferenceDB) where thing ID can be mapped to its name.
One of mine tables is orders with following important columns: charName, stationID, typeID, bid.
Another table has following important columns: transactionDateTime, stationID, typeID, person, transactionType
I started my head braking with idea how to find orders that doesn't have any records for them lately (e.g. given amount of days). But for beginning I set me a task just to find orders that has no records for them at all. For that I figured out LEFT JOIN see biggest query below.
An order for me is a combination of charName/persone + stationID + typeID + transactionType/bid so if actually one of those four changes it is different order then.
Problem is that transactionType can be "yes" or "no" and bid is 0 or not 0. So I cant or DON'T KNOW HOW to JOIN ON different data types. So logically I'd like to join on 4 columns like:
FROM ordersTable LEFT JOIN recordsTable ON ordersTable.typeID = recordsTable.typeID
AND ordersTable.stationID = recordsTable.stationID
AND ordersTable.charName = recordsTable.person
AND ordersTable.bid = recordsTable.transactionType
Clearly last string of above wouldn't work cause of different data types.
So for a moment I thought that I can do such query twice for bid=0 with transactionType="yes" and second time for bid != 0 and transactionType = "no" see my query below for 0/"yes" combination. But seems it doesn't works exactly as I'd like it to. because AND ordersTable.bid IN (0) AND recordsTable.transactionType="yes" in JOIN ON doesn't sem do anything. (As I do get results where bid=1)
SELECT invTypes.typeName, stastations.stationName, main.* FROM referenceDB.invTypes, referenceDB.stastations, (
SELECT ordersTable.charName, ordersTable.stationID, ordersTable.typeID, ordersTable.bid, ordersTable.orderState, ordersTable.volRemaining
FROM ordersTable LEFT JOIN recordsTable ON ordersTable.typeID = recordsTable.typeID
AND ordersTable.stationID = recordsTable.stationID
AND ordersTable.charName = recordsTable.person
AND ordersTable.bid IN (0) AND recordsTable.transactionType="yes"
WHERE recordsTable.typeID IS NULL
AND ordersTable.orderState IN (0) ) as main
WHERE stastations.stationID = main.stationID AND invTypes.typeID = main.typeID;
Questions:
Is it possible to tell mySQL to treat "yes" as 0 or vise versa? If yes how do I do it in my query? If no what would be my work around (to find orders that doesn't have records related to them)?
And possibly some one can suggset a query that will find orders that didn't have records within given amount of days?
Thank you in advance!
One way is to use the explicit comparisons:
((ordersTable.bid = 0 and recordsTable.transactionType = 'No') or
(ordersTable.bid = 1 and recordsTable.transactionType = 'Yes')
)
Another would be to use a case statement:
(case when recordsTable.transactionType = 'No' then 0 else 1 end) = ordersTable.bid
SELECT invTypes.typeName, stastations.stationName, main.* FROM referenceDB.invTypes, referenceDB.stastations, (
SELECT ordersTable.charName, ordersTable.stationID, ordersTable.typeID, ordersTable.bid, ordersTable.orderState, ordersTable.volRemaining
FROM ordersTable LEFT JOIN recordsTable ON ordersTable.typeID = recordsTable.typeID
AND ordersTable.stationID = recordsTable.stationID
AND ordersTable.charName = recordsTable.person
AND ((ordersTable.bid = 0 AND recordsTable.transactionType = 'yes') OR
(ordersTable.bid != 0 AND recordsTable.transactionType = 'no'))
WHERE recordsTable.typeID IS NULL
AND ordersTable.orderState IN (0) ) as main
WHERE stastations.stationID = main.stationID AND invTypes.typeID = main.typeID;

mysql view to contain running status

I'm designing a web based time clock for a school for logging in both students and staff.
I have two tables:
student_time_clock: student_id (foreign key to student), time_stamp, by_adult_id (foreign key to adult)
staff_time_clock: staff_id (foreign key to staff), time_stamp
One of the requirements I've been given is that an observer be able to see the records in one view like the following:
+----------+------------+-------------------------+---------------------+
| In / Out | Time Stamp | Person Logged in or out | Logged in or out by |
+----------+------------+-------------------------+---------------------+
I can do all but the first column with a union. I can't figure out how to get that first column though. Here's the query I'm using for the union:
SELECT stc.entry AS "Time Stamp",
Concat(s.lastname, ",", s.firstname) AS "Punched",
Concat(a.lastname, ",", a.firstname) AS "By"
FROM student_time_clock stc,
student s,
adult a
WHERE stc.student_id = s.id
AND stc.by_adult_id = a.id
UNION
SELECT atc.entry AS "at",
Concat(a.lastname, ",", a.firstname) AS "Staff",
Concat(a.lastname, ",", a.firstname) AS "By"
FROM staff_time_clock atc,
staff s,
adult a
WHERE atc.staff_id = s.id
ORDER BY "time stamp" DESC;
I've tried using a CASE such as:
CASE COUNT( entry ) % 2 WHEN 1 THEN "In" WHEN 0 THEN "Out"
When that case is there though I only get a single row in the result.
Any suggestions? The front end is in PHP but I'd like to create this as a view in the database
I think better to add a flag column in first table to capture the type or entry i.e. "In" or "Out". This can simplify your query with certain result.