I am trying to check if the current user is already following the selected user, and I am doing this like so:
(I know it's not the best way, but as I am new to MYSQL this is as much as I have been able to come up with)
SELECT EXISTS (SELECT 1 FROM Activity WHERE IdOtherUser = 86 AND id = 145)
I am '145' and the user I selected is '86'.
Now that return '0' If I am not following and '1' If I am following that person.
Seems to be working already but it definetly needs improving!
Now what I would like to do is count the followers in the same query.
So count the people I am following and the people following me.
'Activity' is the table where I store the followers and I save them like this:
'id' = me
'idOtherUser' = other user I followed
'type' = type of action "follow"
I have done count's before when calculating the like counts, but I just cannot get my head around this!!
If anyone could spare some time to help me it is much appreciated!
I am sorry if the question is not the best, but I am still learning and trying my best to format them as clear as possible to understand.
Thanks in advance!!
If you trying to count the followers from specific id from table Activity you might do this way:
SELECT COUNT(idOtherUser) AS "I Follow",
(SELECT COUNT(idOtherUser) FROM Activity WHERE idOtherUser = 145 AND type = "follow"
) AS "FOLLOW ME",
(SELECT COALESCE(id,0) FROM Activity WHERE IdOtherUser = 86 AND id = 145 AND type = "follow")
FROM Activity WHERE id = 145 AND type = "follow"
you can use a "correlated subquery" to simplify the query and you might want distinct in the count also (depends on you data). I would avoid using spaces in column aliases too.
SELECT
COUNT(DISTINCT A1.idOtherUser) as i_follow
, (
SELECT
COUNT(DISTINCT A2.id)
FROM Activity A2
WHERE A2.idOtherUser = A1.id
AND A2.type = 'follow'
) as following_me
FROM Activity A1
WHERE A1.id = 145
AND A1.idOtherUser = 86
AND A1.type = 'follow'
Try it with distinct then without, if the result is the same leave distinct out of the query.
Related
I am trying to create a MySQL query of game discs to find some duplicates based on some values being the same and some not.
I need the fields 'name', 'disc', 'platform', 'region' to be the same.
But I also need the field 'version' to be different.
I have already tried a number of queries to do this such as the one below but none seem to work as desired.
SELECT *
FROM media.amps_2000_box_a
INNER JOIN (SELECT *
FROM media.amps_2000_box_a
GROUP BY name
HAVING COUNT(name) > 1) dup
ON media.amps_2000_box_a.name = dup.name and media.amps_2000_box_a.disk = dup.disk and media.amps_2000_box_a.format = dup.format and media.amps_2000_box_a.region = dup.region and media.amps_2000_box_a.version<> dup.version
order by dup.name;
Would anyone be able to help me fix this query?
Thanks in advance.
slick
Maybe I'm missing something but the solution seems quite trivial:
SELECT DISTINCT
amps1.name,
amps1.disk,
amps1.platform,
amps1.region
FROM media.amps_2000_box_a amps1
JOIN media.amps_2000_box_a amps2
ON amps1.name = amps2.name
AND amps1.disk = amps2.disk
AND amps1.platform = amps2.platform
AND amps1.region = amps2.region
AND amps1.version <> amps2.version
ORDER BY amps1.name;
I have DB with two tables:
rmonth and alternatives
The rmonth is an aggregated table of data for each alternative a complete month - if they have any - otherwise the row don't exist in the rmonth table.
Now I want to join them, and this is my code:
SELECT
COALESCE(rmAntal, 0) AS sumMonth, aID, aText, rmUnitID
FROM
alternatives
LEFT JOIN
rmonth ON aID = rmAltID
WHERE aToQuestID = 4418
AND rmMonth = 3
AND rmYear = 2018
AND rmUnitID IN (10603,10960,10496)
GROUP BY aID, rmUnitID
ORDER BY aID ASC
But it doesn't give me the rows not existing in rmonth.
So this scenario gives me the result as I want it - except that it can't handle where the alternative does not exist for that specific unitID in rmonth.
I want them listed with just 0 in sumMonth.
Unfortunately that's where my MySQL-knowledge is limited.
Thanks.
You could add an OR operator, for example
...
WHERE aToQuestID = 4418 AND rmMonth IS NULL OR (
AND rmMonth = 3
AND rmYear = 2018
AND rmUnitID IN (10603,10960,10496)
)
...
This way, you'll get all your alternatives data, even when it's counter part in rmonth is null.
(I work on php and MySQL)
Here's the situation : through an ajax request, I check each 10sec if there's something new for the user in the calendars he's part of.
There are a few things to check, for each calendars (w/e it's a calendar or an other element, but in this case, it's a calendar), so I did a "big" query to return all datas for each calendars, and I treat it with php, and then with js (to pop notifications or w/e).
Three things to check :
is there a "dates" modification since he last visited the calendar ?
is there a new talk in the chat's calendar since he last saw it ?
is there a request to join the calendar which has no answer ?
I did it this way :
SELECT DISTINCT
ci.ci_cid as c_id,
MAX(cc.cc_timestamp) as chat_lastmsg, umchat.um_value as chat_lastview,
MAX(cr.cr_id) as request_id,
cmodif.cm_value as modification_timestamp,
umodif.um_value as modification_view
FROM c_individuals as ci
LEFT JOIN c_chats as cc ON cc.cc_cid = ci.ci_cid
LEFT JOIN u_metas as umchat ON (umchat.um_uid = ci.ci_ciuid AND umchat.um_cid = ci.ci_cid AND umchat.um_name = "chat_last_view")
LEFT JOIN c_requests as cr ON (cr.cr_cid = ci.ci_cid AND cr.cr_answer = "0")
LEFT JOIN c_metas as cmodif ON (cmodif.cm_cid = ci.ci_cid AND cmodif.cm_name = "last_modifications")
LEFT JOIN u_metas as umodif ON (umodif.um_uid = ci.ci_uid AND umodif.um_cid = ci.ci_cid AND umodif.um_name = "last_view")
WHERE ci.ci_uid = :u_id
GROUP BY ci.ci_cid
The c_individuals table has the users who are in a calendar.
The u_metas table has users'metas with um_uid(user id), um_cid (calendar id related to the meta), um_name (name of the meta), um_value (value of the meta)
The c_requests table has requests'informations (u_id, c_id, answer and stuff)
My query gives me what I want, meaning something like :
0 =>
array (size=6)
'c_id' => string '50' (length=2)
'chat_lastmsg' => null
'chat_lastview' => null
'request_id' => null
'modification_timestamp' => string '1488878397.703508' (length=17)
'modification_view' => string '1488877914.048585' (length=17)
1 =>
array (size=6)
'c_id' => string '51' (length=2)
'chat_lastmsg' => string '1485326492' (length=10)
'chat_lastview' => string '1488470529' (length=10)
'request_id' => null
'modification_timestamp' => string '1488878397.703508' (length=17)
'modification_vue' => string '1488878065.811320' (length=17)
But to be honest, I think it's kinda slow. Without treatment, so just to get the results of the query, it takes like 3.5sec to repeat it 1000 times.
It's not a big deal, but this query is repeated a lot, for a potential big number of users.
So my question is : is there any way to improve it, or am I good with this ?
Thank you for your time, and sorry for my bad english.
Don't see anything wrong with your posted query except that you don't need DISTINCT since you are doing a GROUP BY. Also, make sure you have proper index on the columns which are used in JOIN ON condition and WHERE condition.
It's more of a system/database design question rather than a query design.
The query looks adequate enough, and gives the results that you expect, so it's fine (although unsure why you need LEFT joins - but that's down to your data.)
Things to consider in the system design space:
Denormalising the database structure - whenever you enter a c_chat or
c_request, etc. you could look to store the latest timestamp against
the user, so you aren't doing joins - which are very slow.
Could you benefit from a cache closer to the server (e.g. Memcache)?
if you have lots of requests you may want to look into it if the
database is slow. You probably don't need a cache if you're
denormalising the database.
Indexing on anything you use as a filter in the WHERE if you use more than just the Id
For the record,
I finally found something much faster (on my "benchmark test", it's five to seven times faster).
The fact is I don't need to get the informations (dates etc), I just want to know if there is something new since the user saw it for the last time, whenever it was, whenever the new thing was posted.
So I made this (it's in french, plz don't bother) :
SELECT
ci.ci_cid as c_id,
(SELECT COUNT(cc_id)
FROM c_chats
LEFT JOIN u_metas ON um_nom = "chat_derniere_vue"
WHERE cc_cid = ci.ci_cid AND um_uid = ci.ci_uid AND um_cid = ci.ci_cid AND CAST(cc_timestamp as decimal) > CAST(um_valeur as decimal)
) as chat,
(SELECT COUNT(cr_id)
FROM c_requetes
WHERE cr_cid = ci.ci_cid AND ci.ci_ustatut = "titulaire" AND cr_reponse = "0"
) as notifications,
(SELECT COUNT(cm_cid)
FROM c_metas
LEFT JOIN u_metas ON um_nom = "derniere_vue"
WHERE um_uid = ci.ci_uid AND um_cid = ci.ci_cid AND cm_cid = ci.ci_cid AND cm_nom = "derniere_modification_periodes" AND CAST(cm_valeur as decimal) > CAST(um_valeur as decimal)
) as modifications
FROM c_individus as ci
WHERE ci.ci_uid = :u_id
GROUP BY ci.ci_cid
In this way, chat gives the number of chats with a new message, notifications gives the number of unanswer requests, modifications gives the number of calendars with new dates.
And "tada" !
I have 2 tables. 1 table shows location information, and another shows wifi ssids and passwords for the location. These tables are joined by a column 'LocationID'. The reason for the 2 separate tables is so that I can keep a historical trail of ssids and passwords for a specific location.
My query is as follows:
SELECT Location.LocationID,
Location.SystemName,
Location.SiteNameLocation,
Location.SiteAddress1,
Location.SiteAddress2,
Location.SiteCity,
Location.SiteProvince,
Location.SitePostalCode,
Location.ContactName,
Location.ContactPhone,
Location.ContactEmail,
Location.ID1POC,
Location.ID2District,
Location.SiteLocationHours,
LocationWiFi.WiFiSSID,
LocationWiFi.WiFiPassphrase,
LocationWiFi.WiFiDate
FROM Location
LEFT JOIN LocationWiFi ON LocationWiFi.LocationID = Location.LocationID
What I need to do is obtain the most recent wifi ssid and passphrase from the table to show it with the corresponding locationID
I can do it with the following query:
SELECT * FROM LocationWiFi WHERE WiFiDate = (SELECT MAX(WiFiDate) FROM LocationWiFi) AND LocationID = xxxx
I am sure it isnt that hard, I just can not quite figure it out. Thanks in advance for any help!
EDIT...
Sorry for the confusion here everyone. let me try and be more clear. I have 1500+ entrys in location table. 2 entries in LocationWiFi table with the same locationid. I need the first query (the one with the join) to return all 1500+ rows, but only pull the wifi ssid and password with the max date. For the locations that do not have wifi ssid and passphrase, i simply want to show the column with a null value.
Again I apologize
SOLUTION
Hi Everyone,
I have solved this issue. For anyone who is having a similar solution, here is what worked for me.
SELECT Location.LocationID,
Location.SystemName,
Location.SiteNameLocation,
Location.SiteAddress1,
Location.SiteAddress2,
Location.SiteCity,
Location.SiteProvince,
Location.SitePostalCode,
Location.ContactName,
Location.ContactPhone,
Location.ContactEmail,
Location.ID1POC,
Location.ID2District,
Location.SiteLocationHours,
a.WiFiSSID,
a.WiFiPassphrase
FROM Location
LEFT JOIN(
SELECT LocationWiFi.WiFiSSID,
LocationWiFi.WiFiPassphrase,
LocationWiFi.LocationID
FROM LocationWiFi
WHERE LocationWiFi.WiFiDate = (SELECT MAX(WiFiDate) FROM LocationWiFi)
) AS a
ON a.LocationID = Location.LocationID;
The following query is more efficient since it is not using a sub query:
SELECT *
FROM LocationWiFi
WHERE LocationID = xxxx
ORDER BY WiFiDate DESC
LIMIT 1
You had everything you needed, just have to put them together:
SELECT l.*, lw.*
FROM Location l
JOIN LocationWifi lw ON l.locationId= lw.locationId
WHERE lw.WiFiDate = (
SELECT MAX(WiFiDate)
FROM locationWifi
WHERE locationId = l.locationId
);
It's subquery per row, but I don't think there is any good way around it.
SQLFiddle: http://sqlfiddle.com/#!2/350ac/1
I've been trying to write a few little plugins for personal use with WHMCS. Essentially what I'm trying to do here is grab a bunch of information about a certain order(s), and return it as an array in Perl.
The Perl bit I'm fine with, it's the MySQL query I've formed that's giving me stress..
I know it's big and messy, but what I have is:
SELECT tblhosting.id, tblhosting.userid, tblhosting.orderid, tblhosting.packageid, tblhosting.server, tblhosting.domain, tblhosting.username, tblorders.invoiceid, tblproducts.gid, tblservers.ipaddress, tblinvoices.status
FROM tblhosting, tblproducts, tblorders, tblinvoices, tblservers
WHERE tblorders.status = 'Pending'
AND tblproducts.gid = '2'
AND tblservers.id = tblhosting.server
AND tblorders.id = tblhosting.orderid
AND tblinvoices.id = tblorders.invoiceid
AND tblinvoices.status = 'Paid'
I don't know if this /should/ work, but I assume I'm on the right track as it does return what I'm looking for, however it returns everything twice.
For example, I created a new account with the domain 'sunshineee.info', and then in PHPMyAdmin ran the above query.
id userid orderid packageid server domain username invoiceid gid ipaddress status
13 7 17 6 1 sunshineee.info sunshine 293 2 184.22.145.196 Paid
13 7 17 6 1 sunshineee.info sunshine 293 2 184.22.145.196 Paid
Could anyone give me a heads up on where I've gone wrong with this one.. Obvioiusly (maybe not obviously enough) I want this as only one row returned per match.. I've tried it with >1 domain in the database and it returned duplicates for each of the matches..
Any help would be much appreciated
:)
SELECT distinct tblhosting.id, tblhosting.userid, tblhosting.orderid, tblhosting.packageid, tblhosting.server, tblhosting.domain, tblhosting.username, tblorders.invoiceid, tblproducts.gid, tblservers.ipaddress, tblinvoices.status
FROM tblhosting, tblproducts, tblorders, tblinvoices, tblservers
WHERE tblorders.status = 'Pending'
AND tblproducts.gid = '2'
AND tblservers.id = tblhosting.server
AND tblorders.id = tblhosting.orderid
AND tblinvoices.id = tblorders.invoiceid
AND tblinvoices.status = 'Paid'
Well, its near impossible without any table definitions, but you are doing a lot of joins there. You are starting with tblhosting.id and working your way 'up' from there. If any of the connected tables has a double entry, you'll get more hits
You could add a DISTINCT to your query, but that would not fix the underlying issue. It could be a problem with your data: do you have 2 invoices? Maybe you should select everything (SELECT * FROM) and check what is returned, maybe check your tables for double content.
Using DISTINCT is most of the time not a good choice: it means either your query or your data is incorrect (or you don't understand them thoroughly). It might get you the right result for now, but can get you in trouble later.
A guess about the reason this happens:
You do not connect the products table to the chain of id's. So you are basically adding a '2' to your result as far as I can see. You join on products, and the only thing that limits that table is that "gid" should be 2. So if you add a product with gid 2 you get another result. Either join it (maybe tblproduct.orderid = tblorders.id ? just guessing here) or just remove it, as it does nothing as far as I can see.
If you want to make your query a bit clearer, try not implicitly joining, but do it like this. So you can actually see what's happening
SELECT tblhosting.id, tblhosting.userid, tblhosting.orderid, tblhosting.packageid, tblhosting.server, tblhosting.domain, tblhosting.username, tblorders.invoiceid, tblproducts.gid, tblservers.ipaddress, tblinvoices.status
FROM tblhosting
JOIN tblproducts ON /*you're missing something here!*/
JOIN tblorders ON tblorders.id = tblhosting.orderid
JOIN tblinvoices ON tblinvoices.id = tblorders.invoiceid
JOIN tblservers ON tblservers.id = tblhosting.server
WHERE
tblorders.status = 'Pending'
AND tblproducts.gid = '2'
AND tblinvoices.status = 'Paid'
I don't see in your query JOIN to tblproducts, it seems to be a reason.