I have a quite complex Mysql query:
SELECT
metabase_field.description, rows_to_copy.description,
metabase_field.display_name, rows_to_copy.display_name
FROM
metabase_field LEFT JOIN (select id as table_id, name as t_name from metabase_table) metabase_field_table ON metabase_field.table_id=metabase_field_table.table_id,
(
SELECT metabase_field.name as name, metabase_field_table.t_name as t_name, metabase_field.display_name as display_name, metabase_field.description as description, metabase_field.special_type as type
FROM metabase_field
LEFT JOIN (select id as table_id, name as t_name, db_id, active, visibility_type from metabase_table) metabase_field_table ON metabase_field.table_id = metabase_field_table.table_id
LEFT JOIN metabase_database metabase_field_table_database ON metabase_field_table.db_id = metabase_field_table_database.id
where metabase_field_table.active=1 and metabase_field_table.visibility_type is null and metabase_field_table_database.name = 'Prod'
) as rows_to_copy
WHERE
metabase_field_table.table_id IN (
SELECT distinct(metabase_table.id) as ids
from metabase_table
LEFT JOIN metabase_database metabase_table_database ON metabase_table.db_id = metabase_table_database.id
where metabase_table_database.name = 'Dev' and metabase_table.active=1 and metabase_table.visibility_type is null
)
and metabase_field_table.t_name = rows_to_copy.t_name
and metabase_field.name = rows_to_copy.name
This returns a table looking a bit like this:
+-------------+-------------+--------------+--------------+
| description | description | display_name | display_name |
+-------------+-------------+--------------+--------------+
| NULL | to copy | Application | Application |
Without going to deep into details, I just wanted to copty results from rows_to_copy to metabase_field fields, which means to set:
metabase_field.description = rows_to_copy.description,
metabase_field.display_name = rows_to_copy.display_name
I tried to just change SELECT to UPDATE:
UPDATE
metabase_field LEFT JOIN (select id as table_id, name as t_name from metabase_table) metabase_field_table ON metabase_field.table_id=metabase_field_table.table_id,
(
SELECT metabase_field.name as name, metabase_field_table.t_name as t_name, metabase_field.display_name as display_name, metabase_field.description as description, metabase_field.special_type as type
FROM metabase_field
LEFT JOIN (select id as table_id, name as t_name, db_id, active, visibility_type from metabase_table) metabase_field_table ON metabase_field.table_id = metabase_field_table.table_id
LEFT JOIN metabase_database metabase_field_table_database ON metabase_field_table.db_id = metabase_field_table_database.id
where metabase_field_table.active=1 and metabase_field_table.visibility_type is null and metabase_field_table_database.name = 'Prod'
) as rows_to_copy
SET
metabase_field.description = rows_to_copy.description,
metabase_field.display_name = rows_to_copy.display_name
WHERE
metabase_field_table.table_id IN (
SELECT distinct(metabase_table.id) as ids
from metabase_table
LEFT JOIN metabase_database metabase_table_database ON metabase_table.db_id = metabase_table_database.id
where metabase_table_database.name = 'Dev' and metabase_table.active=1 and metabase_table.visibility_type is null
)
and metabase_field_table.t_name = rows_to_copy.t_name
and metabase_field.name = rows_to_copy.name
;
But this query doesn't seem to change anything - the results stay the way they were. Is there any simple way to make it work?
After some formating I realize if almost imposible keep track of table names. use shorter and different alias to avoid bugs. I try to improve the rest of the code but too much work
I think the problem is the update. Update table should have the alias MF, and you SET MF.<field>
If that doesnt work, remove the WHERE and see if you UPDATE something. Of course only if you can do testing on those tables.
If that doesnt work, start with a single table and add one join at each time.
UPDATE metabase_field MF -- main alias for table to update.
LEFT JOIN (SELECT id as table_id, name as t_name
FROM metabase_table) MT1
ON MF.table_id = MT1.table_id
CROSS JOIN ( SELECT MF1.name as name,
MT2.t_name as t_name,
MF1.display_name as display_name,
MF1.description as description,
MF1.special_type as type
FROM metabase_field MF1
LEFT JOIN (SELECT id as table_id,
name as t_name,
db_id, active,
visibility_type
from metabase_table) MT2
ON MF1.table_id = MT2.table_id
LEFT JOIN metabase_database MD
ON MT2.db_id = MD.id
WHERE MT2.active = 1
and MT2.visibility_type is null
and MD.name = 'Prod'
) as rows_to_copy
SET
MF.description = rows_to_copy.description,
MF.display_name = rows_to_copy.display_name
WHERE
metabase_field_table.table_id IN (
SELECT distinct(metabase_table.id) as ids
from metabase_table
LEFT JOIN metabase_database MB
ON MT2.db_id = MB.id
WHERE MB.name = 'Dev'
and MT2.active=1
and MT2.visibility_type is null
)
and metabase_field_table.t_name = rows_to_copy.t_name
and metabase_field.name = rows_to_copy.name
;
Update metabase_field set metabase_field.description=
rows_to_copy.description, metabase_field.display_name=
rows_to_copy.display_name LEFT JOIN (select id as table_id, name as
t_name from metabase_table) metabase_field_table ON
metabase_field.table_id=metabase_field_table.table_id, ( SELECT
metabase_field.name as name, metabase_field_table.t_name as t_name,
metabase_field.display_name as display_name,metabase_field.description as description, metabase_field.special_type
as type FROM metabase_field LEFT JOIN (select id as table_id, name as
t_name, db_id, active, visibility_type from metabase_table)
metabase_field_table ON metabase_field.table_id =
metabase_field_table.table_id LEFT JOIN metabase_database
metabase_field_table_database ON metabase_field_table.db_id =
metabase_field_table_database.id where metabase_field_table.active=1
and metabase_field_table.visibility_type is null and
metabase_field_table_database.name = 'Prod' ) as rows_to_copy WHERE
metabase_field_table.table_id IN ( SELECT distinct(metabase_table.id)
as ids from metabase_table LEFT JOIN metabase_database
metabase_table_database ON metabase_table.db_id =
metabase_table_database.id where metabase_table_database.name = 'Dev'
and metabase_table.active=1 and metabase_table.visibility_type is null
) and metabase_field_table.t_name = rows_to_copy.t_name and
metabase_field.name = rows_to_copy.name
Try this
Related
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'
)
I am joining multiple tables into a single query. I need to do a partial match on values in an IN statement. Here is an example.
SELECT DISTINCT
am.id AS id,
am.flagged AS flagged,
am.name AS name,
am.type AS type,
am.file AS file,
am.s3_tag AS s3_tag,
am.low_s3_tag AS low_s3_tag
FROM accounts_media am
LEFT JOIN accounts_location_media alm ON am.id = alm.media_id
LEFT JOIN accounts_location al ON al.id = alm.location_id
LEFT JOIN accounts_person_media apm ON am.id = apm.media_id
LEFT JOIN accounts_person ap ON ap.id = apm.person_id
LEFT JOIN accounts_event_media_record aemr ON am.id=aemr.media_id
LEFT JOIN accounts_medianote_media_record amma ON am.id=amma.media_id
LEFT JOIN accounts_medianote amn ON amma.medianote_id=amn.id
WHERE
am.account_id = '1234'
AND am.flagged = FALSE
AND ('Da' IN (SELECT first_name FROM accounts_person WHERE account_id = '1234')
AND ('Rob' IN (SELECT first_name FROM accounts_person WHERE account_id = '1234')
In the
AND ('Da' IN (SELECT first_name FROM accounts_person WHERE account_id = '1234')
statement there are values that say 'Dan', 'Daniel', etc. in the table. There is also 'Rob' and 'Robert'. I need that statement to make sure and name that contains 'Da' AND any name that contains 'Rob' from that table. Is there a way to do this?
So a record can be linked to multiple people in the accounts_person table. So lets say I have three records.
Record One: A person named Dan is attached to the record.
Record Two: A person named Robert is attached to the record.
Record Three: A person named Dan and a person named Robert are attached to the record.
I want the query to only return Record Three because it has the match of 'Da' and 'Rob'.
Try this:
WHERE
am.account_id = '1234'
AND am.flagged = FALSE
-- AND ( ap.first_name LIKE '%Da%' OR ap.first_name LIKE '%Rob%')
AND EXISTS
( SELECT 1
FROM accounts_person apx
WHERE apx.first_name LIKE '%Da%'
AND apx.account_id = am.account_id
)
AND EXISTS
( SELECT 1
FROM accounts_person apy
WHERE apy.first_name LIKE '%Rob%'
AND apy.account_id = am.account_id
)
I'm not sure, but I think you want a like statement, with a wild card after the Da.
SELECT DISTINCT
am.id AS id,
am.flagged AS flagged,
am.name AS name,
am.type AS type,
am.file AS file,
am.s3_tag AS s3_tag,
am.low_s3_tag AS low_s3_tag
FROM accounts_media am
LEFT JOIN accounts_location_media alm ON am.id = alm.media_id
LEFT JOIN accounts_location al ON al.id = alm.location_id
LEFT JOIN accounts_person_media apm ON am.id = apm.media_id
LEFT JOIN accounts_person ap ON ap.id = apm.person_id
LEFT JOIN accounts_event_media_record aemr ON am.id=aemr.media_id
LEFT JOIN accounts_medianote_media_record amma ON am.id=amma.media_id
LEFT JOIN accounts_medianote amn ON amma.medianote_id=amn.id
WHERE
am.account_id = '1234'
AND am.flagged = FALSE
AND (accounts_person.first_name like '%Da%'
OR accounts_person.first_name like '%Rob%')
AND accounts_person.account_id = '1234'
I have tables
Tasks- id,name
then i have
userTasks id , task_id , user_id
and
User - id , name
Suppose i have 10 tasks in task table and out of those i have 3 tasks in userTask table
I want query like this
Select task.id , task.name , STATUS (if(presentInUserTasks),1,0) FROM whatever
the STATUS word should 1 if that task id is present in usertasks table for that userid otherwise it should be 0
So that i am able to find which of those tasks are alreadu in userTask table
You're looking for the EXISTS keyword:
SELECT tasks.id, tasks.name,
IF(EXISTS(SELECT id
FROM userTasks
WHERE userTasks.task_id = tasks.id
AND userTasks.user_id = #that_user_id)
,1,0) AS STATUS
FROM tasks
Try this one:
SELECT b.id,
b.name,
IF(coalesce(c.Task_ID, -1) = -1, 0, 1) `Status`
FROM `User` a
CROSS JOIN `Task` b
LEFT JOIN UserTask c
ON a.ID = c.user_ID AND
b.ID = c.Task_ID
Where a.id = 1
Demo: http://sqlfiddle.com/#!2/a22d0/7
try this:
select T.id , T.name ,
case when u.task_id is not null then 1 else 0 end as STATUS
from
Tasks T left outer join usertasks U
on T.id=u.task_id
TRY
SELECT t.id,t.name,
CASE WHEN ut.task_id IS NULL THEN '0' ELSE '1' END
FROM Tasks t
LEFT JOIN UserTask ut ON ut.task_id = t.id
I would like to use JOIN instead of IN in the following SQL query. I can't figure out how to do it.
SELECT * FROM shop_orders WHERE
id IN (SELECT orders_id FROM shop_orders_data WHERE closed='1' /*AND backorder='0'*/ AND exhibition_id='389' AND
exhibition_id IN (SELECT id FROM shop_exhibitions WHERE
country_id IN (SELECT id FROM countries WHERE id='72')) AND in_country = '72' AND
exhibition_id IN (SELECT id FROM shop_exhibitions WHERE start<=1336946400 AND end>1336600800)) AND
id IN (SELECT orders_id FROM shop_orders_products WHERE
products_id IN (SELECT id FROM shop_products WHERE artno='120000' OR name LIKE '%120000%')) AND created>=1333231200 AND created<1333663200 ORDER BY created DESC
I tried this:
SELECT
s.*
FROM
shop_orders s
INNER JOIN shop_orders_data od ON s.id=od.orders_id
INNER JOIN shop_exhibitions se ON od.exhibition_id=se.id
INNER JOIN countries co ON se.country_id=co.id
INNER JOIN shop_orders_products sop ON s.id=sop.orders_id
INNER JOIN shop_products sp
ON sop.products_id=sp.id
WHERE od.closed=1
AND ( sp.artno='120000' or sp.name LIKE '%120000%' )
AND ( od.exhibition_id='389')
AND ( od.in_country = '72')
AND ( se.start <=1336946400)
AND ( se.end >1336600800)
AND ( se.created>=1333231200)
AND ( se.created<1333663200)
ORDER BY `s`.`created` DESC
I this correct??
See if this works (and study the code to learn how it works):
SELECT *
FROM shop_orders so
JOIN shop_orders_data sod ON (
(so.id = sod.orders_id)
AND (sod.closed = '1')
/*AND (sod.backorder = '0') */
AND (sod.exhibition_id = '389')
AND (sod.in_country = '72')
)
JOIN shop_exhibitions se ON (
(sod.exhibition_id = se.id)
AND (se.start <= 1336946400)
AND (se.end > 1336600800)
)
JOIN countries c ON (
(se.country_id = c.id)
AND (c.id = '72')
)
JOIN shop_orders_products sop ON (
(so.id = sop.orders_id)
)
JOIN shop_products sp ON (
(sop.products_id = sp.id)
AND ((sp.artno='120000') OR (sp.name LIKE '%120000%'))
)
WHERE (so.created >= 1333231200) AND (so.created < 1333663200)
ORDER BY so.created DESC;
The join syntax works like this:
SELECT field1,field2,field3
FROM FirstTable
JOIN SecondTable ON (FirstTable.PrimaryKey = SecondTable.ForeignKey)
JOIN ThirdTable ON (FirstTable.PrimaryKey = ThirdTable.ForeignKey)
Try applying this approach to your query.