I am new to SQL. Can someone help to convert this query, so it uses join syntax?
SELECT groups.name,
users.firstname,
users.lastname,
users.emailaddress,
groupmembers.userid,
reminders.groupid,
reminders.ownerid,
reminderdetails.recno,
reminderdetails.cardid,
reminderdetails.message
FROM reminderdetails,
reminders,
groupmembers,
users,
groups
WHERE assocdate = 'Y'
AND ( reminder1 != 99
AND ( Datediff(reminderdate, '2011-09-22') = reminder1 )
OR ( reminder2 != 99
AND Datediff(reminderdate, '2011-09-22') = reminder2 ) )
AND reminders.cardid = reminderdetails.cardid
AND groupmembers.groupid = reminders.groupid
AND groupmembers.sendemail = 'Y'
AND users.recno = groupmembers.userid
AND groups.recno = reminders.groupid
Try this:
SELECT g.name,
uu.firstname,
uu.lastname,
uu.emailaddress,
gp.userid,
rm.groupid,
rm.ownerid,
rd.recno,
rd.cardid,
rd.message
FROM reminderdetails rd
JOIN reminders rm on rm.cardid=rd.cardId
JOIN groupmembers gp on gp.groupid=rm.groupId and gp.sendemail='Y'
JOIN users uu on uu.recNo=gp.userId,
JOIN groups g ON g.recno=rm.groupId
WHERE assocdate = 'Y'
AND ( reminder1 != 99
AND ( Datediff(reminderdate, '2011-09-22') = reminder1 )
OR ( reminder2 != 99
AND Datediff(reminderdate, '2011-09-22') = reminder2 ) )
Bit of a guess without knowing your table structure, but I think this seems about right.
Edit: Just seen the other one; I'd generally prefer to not load up the JOIN with too many clauses, as you end up going hunting all over the place when you want to find out what WHERE clauses are being applied. If possible, I think it's better to keep JOINs containing just the JOIN and put the rest into the WHERE.
I'm sure someone else can come along and shoot me down on that one, but that's my take on it :)
SELECT groups.name,
users.firstname,
users.lastname,
users.emailaddress,
groupmembers.userid,
reminders.groupid,
reminders.ownerid,
reminderdetails.recno,
reminderdetails.cardid,
reminderdetails.message
FROM groups
INNER JOIN groupmembers ON groups.groupid = groupmembers.groupid
INNER JOIN users ON groupmembers.userid = users.userid
INNER JOIN reminders ON users.userid = reminders.ownderid
INNER JOIN reminderdetails ON reminders.cardid = reminderdetails.cardid
WHERE assocdate = 'Y'
AND ( reminder1 != 99
AND ( Datediff(reminderdate, '2011-09-22') = reminder1 )
OR ( reminder2 != 99
AND Datediff(reminderdate, '2011-09-22') = reminder2 ) )
AND groupmembers.sendemail = 'Y'
Related
First question on here, so I apologise if I have missed something previously asked, or don't format this well....
My company has a custom CRM + database that I am attempting to improve. We need to find a list of properties that will not have their yearly service renewed. Currently, we do this by first finding properties that will have their service renewed, which is done with the following query:
SELECT DISTINCT
j.`property_id`
FROM
`jobs` AS j
LEFT JOIN `property` AS p
ON j.`property_id` = p.`property_id`
LEFT JOIN `agency` AS a
ON p.`agency_id` = a.`agency_id`
INNER JOIN `property_services` AS ps
ON (
j.`property_id` = ps.`property_id`
AND j.`service` = ps.`alarm_job_type_id`
)
WHERE ps.`service` = 1
AND a.`country_id` = 1
AND (
j.`status` = 'Pending'
OR j.`date` IS NULL
OR j.`date` = '0000-00-00'
OR j.`job_type` = 'Once-off'
OR j.`job_type` = '240v Rebook'
OR (
j.`date` >= '2019-04-22'
AND j.`job_type` = 'Yearly Maintenance'
)
)
Then we find the details we want to display for the user, excluding other items in the process:
SELECT DISTINCT
j.`property_id`,
p.`address_1` AS p_address1,
p.`address_2` AS p_address2,
p.`address_3` AS p_address3,
p.`state` AS p_state,
p.`postcode` AS p_postcode,
a.`agency_id`,
a.`agency_name`
FROM
`jobs` AS j
LEFT JOIN `property` AS p
ON j.`property_id` = p.`property_id`
LEFT JOIN `agency` AS a
ON p.`agency_id` = a.`agency_id`
INNER JOIN `property_services` AS ps
ON (
j.`property_id` = ps.`property_id`
AND j.`service` = ps.`alarm_job_type_id`
)
WHERE p.`property_id` NOT IN (INSERT HERE THE IDS YOU GOT FROM THE FIRST QUERY)
AND ps.`service` = 1
AND p.`deleted` = 0
AND p.`agency_deleted` = 0
AND a.`status` = 'active'
AND a.`country_id` = 1
ORDER BY j.`property_id` DESC
LIMIT 0, 50
Ideally, I'd like to combine these queries, or somehow optimise them, as the page currently takes 2+ minutes to load, even with indexing.
Again, my apologies, I am not a database or query expert, pretty sure the degree only included one or two subjects on the matter!
For the record (in case someone would find it helpful), the combined version is:
SELECT DISTINCT
j.`property_id`,
p.`address_1` AS p_address1,
p.`address_2` AS p_address2,
p.`address_3` AS p_address3,
p.`state` AS p_state,
p.`postcode` AS p_postcode,
a.`agency_id`,
a.`agency_name`
FROM
`jobs` AS j
LEFT JOIN `property` AS p
ON j.`property_id` = p.`property_id`
LEFT JOIN `agency` AS a
ON p.`agency_id` = a.`agency_id`
INNER JOIN `property_services` AS ps
ON (
j.`property_id` = ps.`property_id`
AND j.`service` = ps.`alarm_job_type_id`
)
WHERE p.`property_id` NOT IN
(SELECT DISTINCT
j.`property_id`
FROM
`jobs` AS j
LEFT JOIN `property` AS p
ON j.`property_id` = p.`property_id`
LEFT JOIN `agency` AS a
ON p.`agency_id` = a.`agency_id`
INNER JOIN `property_services` AS ps
ON (
j.`property_id` = ps.`property_id`
AND j.`service` = ps.`alarm_job_type_id`
)
WHERE ps.`service` = 1
AND a.`country_id` = 1
AND (
j.`status` = 'Pending'
OR j.`date` IS NULL
OR j.`date` = '0000-00-00'
OR j.`job_type` = 'Once-off'
OR j.`job_type` = '240v Rebook'
OR (
j.`date` >= '2019-05-08'
AND j.`job_type` = 'Yearly Maintenance'
)
))
AND ps.`service` = 1
AND p.`deleted` = 0
AND p.`agency_deleted` = 0
AND a.`status` = 'active'
AND a.`country_id` = 1
AND (
j.`status` != 'Booked'
AND j.`status` != 'To Be Booked'
AND j.`status` != 'Send Letters'
AND j.`status` != 'On Hold'
AND j.`status` != 'On Hold - COVID'
AND j.`status` != 'Pre Completion'
AND j.`status` != 'Merged Certificates'
)
AND j.`date` > DATE_ADD(NOW(), INTERVAL - 350 DAY)
ORDER BY j.`property_id` DESC
Someone outside of StackOverflow helped combine, but it didn't help...
We ended up having to add a marker and search for that, because this query took 193 seconds to run on our database.
Also, I totally get the requirement to provide a minimum reproducible example, and its my fault for not doing that.
I could do with some help here with this issue in which I'm trying to generate a set of results with balances brought forward and balances carried forward.
The MySQL script:
CREATE OR REPLACE VIEW vwbalances AS
SELECT th.user_id usrid
, YEAR(th.date_created) year
, IFNULL(
(SELECT SUM(tx.amount)
FROM transdetail tx
JOIN transhdr th
ON th.thdr_id = tx.thdr_id
JOIN users u
ON th.user_id = u.user_id
JOIN transtype tt
ON tt.ttype_id = tx.ttype_id
WHERE tx.ttype_id in (2,9,11)
AND u.user_id = usrid
and YEAR(tx.date_created) < year
)
,0) bal_bfwd
, SUM(td.amount) bal_ytd
, ifnull(
(SELECT SUM(ty.amount)
FROM transdetail ty
JOIN transhdr th
ON th.thdr_id = ty.thdr_id
JOIN users u
ON th.user_id = u.user_id
JOIN transtype tt
ON tt.ttype_id = ty.ttype_id
WHERE ty.ttype_id in (2,9,11)
AND u.user_id = usrid
AND YEAR(ty.date_created) <= year
)
,0) bal_cfwd
FROM transdetail td
JOIN transhdr th
ON th.thdr_id = td.thdr_id
JOIN users u
ON th.user_id = u.user_id
JOIN transtype tt
ON tt.ttype_id = td.ttype_id
WHERE td.ttype_id in (2,9,11)
GROUP
BY th.user_id
, YEAR(th.date_created)
I get this (incorrect results) when I run SELECT * FROM vwbalances:
And I get this (correct results) when I run the full SELECT statement that I used to create the VIEW:
Thanks in advance.
The query you posted shouldn't even work.
The usrid is an alias in your most outer select. It is not available in your subqueries.
Unless you have a column called year things like year(tx.date_created) < year shouldn't work either
You use the same table alias in your outer query and in your subqueries. This should also not be possible. If it is, that's probably why you get weird results.
Apart from that, you don't have to do the basically same query multiple times. You can shorten your query to something like this:
SELECT `th`.`user_id` AS usrid
, year(`th`.`date_created`) AS 'year'
sum(if(year(td.date_created`) < year, amount, 0)) as bal_ytd,
sum(if(year(td.date_created`) <= year, amount, 0)) as bal_cfwd
FROM `transdetail` `td`
JOIN `transhdr` `th` ON `th`.`thdr_id` = `td`.`thdr_id`
JOIN `users` `u` ON `th`.`user_id` = `u`.`user_id`
JOIN `transtype` `tt` ON `tt`.`ttype_id` = `td`.`ttype_id`
WHERE `td`.`ttype_id` IN (2, 9, 11)
GROUP BY `th`.`user_id`
, year(`th`.`date_created`)
(given of course, that this weird year thing works for you)
The following script has worked correctly. All help and tips appreciated:
CREATE OR REPLACE VIEW vwbalances AS
SELECT tho.user_id AS usrid, YEAR(td.date_created) AS 'year'
, ROUND(IFNULL((SELECT sum(tx.amount) FROM transdetail tx
JOIN transhdr th ON th.thdr_id = tx.thdr_id
JOIN users u ON th.user_id = u.user_id
JOIN transtype tt ON tt.ttype_id = tx.ttype_id
WHERE tx.ttype_id IN (2,9,11) AND u.user_id = tho.user_id AND
YEAR(tx.date_created) < YEAR(td.date_created) ),0),2) AS
bal_bfwd
, round(sum(td.amount),2) AS bal_ytd
, ROUND(IFNULL((select SUM(ty.amount) FROM transdetail ty
JOIN transhdr th on th.thdr_id = ty.thdr_id
JOIN users u ON th.user_id = u.user_id
JOIN transtype tt ON tt.ttype_id = ty.ttype_id
WHERE ty.ttype_id IN (2,9,11) AND u.user_id = tho.user_id AND
YEAR(ty.date_created) <= YEAR(td.date_created)),0),2) AS
bal_cfwd
FROM transdetail td JOIN transhdr tho ON tho.thdr_id =
td.thdr_id
JOIN users u ON tho.user_id = u.user_id
JOIN transtype tt on tt.ttype_id = td.ttype_id
WHERE td.ttype_id IN (2,9,11)
GROUP BY tho.user_id, YEAR(td.date_created);
I'm not sure how to make the following SQL query more efficient. Right now, the query is taking 8 - 12 seconds on a pretty fast server, but that's not close to fast enough for a Website when users are trying to load a page with this code on it. It's looking through tables with many rows, for instance the "Post" table has 717,873 rows. Basically, the query lists all Posts related to what the user is following (newest to oldest).
Is there a way to make it faster by only getting the last 20 results total based on PostTimeOrder?
Any help would be much appreciated or insight on anything that can be done to improve this situation. Thank you.
Here's the full SQL query (lots of nesting):
SELECT DISTINCT p.Id, UNIX_TIMESTAMP(p.PostCreationTime) AS PostCreationTime, p.Content AS Content, p.Bu AS Bu, p.Se AS Se, UNIX_TIMESTAMP(p.PostCreationTime) AS PostTimeOrder
FROM Post p
WHERE (p.Id IN (SELECT pc.PostId
FROM PostCreator pc
WHERE (pc.UserId IN (SELECT uf.FollowedId
FROM UserFollowing uf
WHERE uf.FollowingId = '100')
OR pc.UserId = '100')
))
OR (p.Id IN (SELECT pum.PostId
FROM PostUserMentions pum
WHERE (pum.UserId IN (SELECT uf.FollowedId
FROM UserFollowing uf
WHERE uf.FollowingId = '100')
OR pum.UserId = '100')
))
OR (p.Id IN (SELECT ssp.PostId
FROM SStreamPost ssp
WHERE (ssp.SStreamId IN (SELECT ssf.SStreamId
FROM SStreamFollowing ssf
WHERE ssf.UserId = '100'))
))
OR (p.Id IN (SELECT psm.PostId
FROM PostSMentions psm
WHERE (psm.StockId IN (SELECT sf.StockId
FROM StockFollowing sf
WHERE sf.UserId = '100' ))
))
UNION ALL
SELECT DISTINCT p.Id AS Id, UNIX_TIMESTAMP(p.PostCreationTime) AS PostCreationTime, p.Content AS Content, p.Bu AS Bu, p.Se AS Se, UNIX_TIMESTAMP(upe.PostEchoTime) AS PostTimeOrder
FROM Post p
INNER JOIN UserPostE upe
on p.Id = upe.PostId
INNER JOIN UserFollowing uf
on (upe.UserId = uf.FollowedId AND (uf.FollowingId = '100' OR upe.UserId = '100'))
ORDER BY PostTimeOrder DESC;
Changing your p.ID in (...) predicates to existence predicates with correlated subqueries may help. Also since both halves of your union all query are pulling from the Post table and possibly returning nearly identical records you might be able to combine the two into one query by left outer joining to UserPostE and adding upe.PostID is not null as an OR condition in the WHERE clause. UserFollowing will still inner join to UPE. If you want the same Post record twice once with upe.PostEchoTime and once with p.PostCreationTime as the PostTimeOrder you'll need keep the UNION ALL
SELECT
DISTINCT -- <<=- May not be needed
p.Id
, UNIX_TIMESTAMP(p.PostCreationTime) AS PostCreationTime
, p.Content AS Content
, p.Bu AS Bu
, p.Se AS Se
, UNIX_TIMESTAMP(coalesce( upe.PostEchoTime
, p.PostCreationTime)) AS PostTimeOrder
FROM Post p
LEFT JOIN UserPostE upe
INNER JOIN UserFollowing uf
on (upe.UserId = uf.FollowedId AND
(uf.FollowingId = '100' OR
upe.UserId = '100'))
on p.Id = upe.PostId
WHERE upe.PostID is not null
or exists (SELECT 1
FROM PostCreator pc
WHERE pc.PostId = p.ID
and pc.UserId = '100'
or exists (SELECT 1
FROM UserFollowing uf
WHERE uf.FollowedId = pc.UserID
and uf.FollowingId = '100')
)
OR exists (SELECT 1
FROM PostUserMentions pum
WHERE pum.PostId = p.ID
and pum.UserId = '100'
or exists (SELECT 1
FROM UserFollowing uf
WHERE uf.FollowedId = pum.UserId
and uf.FollowingId = '100')
)
OR exists (SELECT 1
FROM SStreamPost ssp
WHERE ssp.PostId = p.ID
and exists (SELECT 1
FROM SStreamFollowing ssf
WHERE ssf.SStreamId = ssp.SStreamId
and ssf.UserId = '100')
)
OR exists (SELECT 1
FROM PostSMentions psm
WHERE psm.PostId = p.ID
and exists (SELECT
FROM StockFollowing sf
WHERE sf.StockId = psm.StockId
and sf.UserId = '100' )
)
ORDER BY PostTimeOrder DESC
The from section could alternatively be rewritten to also use an existence clause with a correlated sub query:
FROM Post p
LEFT JOIN UserPostE upe
on p.Id = upe.PostId
and ( upe.UserId = '100'
or exists (select 1
from UserFollowing uf
where uf.FollwedID = upe.UserID
and uf.FollowingId = '100'))
Turn IN ( SELECT ... ) into a JOIN .. ON ... (see below)
Turn OR into UNION (see below)
Some the tables are many:many mappings? Such as SStreamFollowing? Follow the tips in http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table
Example of IN:
SELECT ssp.PostId
FROM SStreamPost ssp
WHERE (ssp.SStreamId IN (
SELECT ssf.SStreamId
FROM SStreamFollowing ssf
WHERE ssf.UserId = '100' ))
-->
SELECT ssp.PostId
FROM SStreamPost ssp
JOIN SStreamFollowing ssf ON ssp.SStreamId = ssf.SStreamId
WHERE ssf.UserId = '100'
The big WHERE with all the INs becomes something like
JOIN ( ( SELECT pc.PostId AS id ... )
UNION ( SELECT pum.PostId ... )
UNION ( SELECT ssp.PostId ... )
UNION ( SELECT psm.PostId ... ) )
Get what you can done of that those suggestions, then come back for more advice if you still need it. And bring SHOW CREATE TABLE with you.
I have this:
SELECT users.first_name,
users.last_name,
family_products.costs_obj
FROM users
JOIN family_products
ON users.family_id = family_products.family_id
WHERE users.family_id IN (SELECT family_id
FROM employer_families
WHERE employer_id = 117)
AND family_products.product_id IN (SELECT id
FROM market_products
WHERE type = "medicalplan")
AND users.first_name = 'alexandre'
And i need to be able to update cost_obj to = '' how would i run this select as an update?
Although I have not been able to test this, I think this is what you need:
UPDATE fp
SET fp.costs_obj = ''
FROM
users u
JOIN family_products fp ON u.family_id = fp.family_id
WHERE
u.family_id IN
(
SELECT
family_id
FROM
employer_families
WHERE
employer_id = 117
)
AND
fp.product_id IN
(
SELECT
id
FROM
market_products
WHERE
type = "medicalplan"
)
AND
u.first_name = 'alexandre';
Didn't test this since I don't know the schema, but you can try this:
UPDATE family_products
SET costs_obj = ''
WHERE costs_obj IN(
SELECT
family_products.costs_obj
FROM users
JOIN family_products
ON users.family_id = family_products.family_id
WHERE users.family_id IN (SELECT family_id
FROM employer_families
WHERE employer_id = 117)
AND family_products.product_id IN (SELECT id
FROM market_products
WHERE type = "medicalplan")
AND users.first_name = 'alexandre'
)
Can you please help me optimize this query. I use this query to get a list of friends along with their details and their status.
It takes about 0.08 secs to process this on a Athlon X2 6000
I cant use materizlized view as well because this is frequently changing.
SELECT p.userid, p.firstname, p.lastname, p.gender, p.dob, x.relationship,
IF(p.picture !=1,
IF(p.gender != 'm','/sc/f-t.jpg','/sc/m-t.jpg'),
concat('/sc/pthumb/', p.userid, '.jpg' )) AS picture
FROM `social` AS p
LEFT JOIN `friendlist` AS f1 ON (f1.`userid` = p.`userid` AND f1.`friendid` = 1 AND `f1`.`status` = 1)
LEFT JOIN `friendlist` AS f2 ON (f2.`friendid` = p.`userid` AND f2.`userid` = 1 AND `f2`.`status` = 1)
LEFT JOIN `x_relationship` AS x ON (x.`id` = p.`relationship`)
LEFT JOIN `auth` as a ON (a.`userid` = p.`userid`)
WHERE 1 AND (f1.`userid` IS NOT NULL OR f2.`userid` IS NOT NULL AND ((a.`banned` != 1 AND a.`deleted` != 1)))
ORDER BY RAND() LIMIT 0,10
This is your original query, formatted. Below it are a few thoughts.
SELECT
p.userid,
p.firstname,
p.lastname,
p.gender,
p.dob,
x.relationship,
IF(p.picture !=1, IF(p.gender != 'm', '/sc/f-t.jpg', '/sc/m-t.jpg'), concat('/sc/pthumb/', p.userid, '.jpg' )) AS picture
FROM
`social` AS p
LEFT JOIN `friendlist` AS f1 ON (f1.`friendid` = 1 AND f1.`userid` = p.`userid` AND `f1`.`status` = 1)
LEFT JOIN `friendlist` AS f2 ON (f2.`friendid` = p.`userid` AND f2.`userid` = 1 AND `f2`.`status` = 1)
LEFT JOIN `x_relationship` AS x ON (x.`id` = p.`relationship`)
LEFT JOIN `auth` AS a ON (a.`userid` = p.`userid`)
WHERE
1
AND (
f1.`userid` IS NOT NULL
OR f2.`userid` IS NOT NULL
AND (a.`banned` != 1 AND a.`deleted` != 1)
)
ORDER BY
RAND()
LIMIT
0,10
Think if some of your left joins could be inner joins. If so, change them.
Your WHERE clause is messed up. You are mixing AND and OR without properly prioritizing with parentheses. Try:
WHERE
a.`banned` != 1
AND a.`deleted` != 1
AND (
f1.`userid` IS NOT NULL
OR f2.`userid` IS NOT NULL
)
You could also try:
INNER JOIN `auth` AS a ON (
a.`userid` = p.`userid`
AND a.`banned` != 1
AND a.`deleted` != 1
)
WHERE
f1.`userid` IS NOT NULL
OR f2.`userid` IS NOT NULL
You seem to be joining against friendlist solely to check for record existence. You might want to give this a try as well:
FROM
`social` AS p
INNER JOIN `auth` AS a ON (
a.`userid` = p.`userid`
AND a.`banned` != 1
AND a.`deleted` != 1
)
LEFT JOIN `x_relationship` AS x ON (
x.`id` = p.`relationship`
)
WHERE
EXISTS (
SELECT 1 FROM `friendlist` WHERE `friendid` = 1 AND `userid` = p.`userid` AND `status` = 1
)
OR EXISTS (
SELECT 1 FROM `friendlist` WHERE `friendid` = p.`userid` AND `userid` = 1 AND `status` = 1
)
ORDER BY RAND() might not be the fastest thing on earth, but if this is what you need... Try ordering by a indexed column to see how much impact ORDER BY RAND() has.
Indexing:
You should create a composite index on friendlist(friendid, userid, status).
Make sure there is an index on relationship(id)
Make sure there is an index on auth(userid)