I have the query below, and it gets the correct data, but I need to limit the results of the join so that only the first row from the photos table is included. Here's what I have:
SELECT `listings`.*, `photos`.*
FROM `listings` JOIN `photos`
ON `photos`.`listing_id` = `listings`.`id`
WHERE `listings`.`date_expires` >= '2016-08-10' AND `listings`.`visible` = '1' AND `listings`.`spotlightListing` >= '2016-08-10'
How do I limit the above so I only get the first row from the photos table? Thanks!
SELECT `listings`.*, `photos`.*
FROM `listings`
JOIN `photos` ON `photos`.`listing_id` = `listings`.`id`
WHERE `listings`.`date_expires` >= '2016-08-10' AND `listings`.`visible` = '1'
AND `listings`.`spotlightListing` >= '2016-08-10'
limit 1
I am sure you are talking about first photo of the list record.
Related
I have used below query for product listing. Query is working fine but it takes approximately 0.4534 seconds. How can I optimize the same query.
SELECT SQL_CALC_FOUND_ROWS DISTINCT tp.prod_id, tp.prod_name, tp.prod_shop, tp.prod_retail_price, tp.prod_sale_price, tp.prod_initial_price, tp.prod_stock, ts.shop_id, ts.shop_name, ts.shop_logo, ts.shop_description, ts.shop_title, tu.user_profile_image, ( SELECT pdiscount_price FROM tbl_product_discounts tpd WHERE tpd.pdiscount_product_id = tp.prod_id AND tpd.pdiscount_qty = '1' AND( ( tpd.pdiscount_start_date = '0000-00-00' OR tpd.pdiscount_start_date < NOW()) AND( tpd.pdiscount_end_date = '0000-00-00' OR tpd.pdiscount_end_date > NOW()) ) ORDER BY tpd.pdiscount_priority ASC, tpd.pdiscount_price ASC LIMIT 1 ) AS discount FROM tbl_products tp LEFT JOIN tbl_shops ts ON tp.prod_shop = ts.shop_id AND ts.shop_is_deleted = 0 INNER JOIN tbl_users tu ON ts.shop_user_id = tu.user_id WHERE tp.prod_is_deleted = '0' LIMIT 0, 20
Without checking you table or Requirement :
Try to use group by instead of DISTINCT
Do not use sub query if possible .
Try To use indexing in you table .
This will help you to optimize you query.
Overview
I have two tables - tmc_users and tmc_user_usergroup_map.
In tmc_users, there is a list of user_ids and in tmc_usergroup_map each user_id can be associated with multiple group_ids.
I am trying to find all the user_ids who have a group_id of 12 but do not have a group_id of 17.
Each user can be a member of both.
Current query
This is the query to get all the users associated with the group_id 12, which returns a total number of 1439 rows:
SELECT `id`, LTRIM(RTRIM(`name`)), COUNT(`id`) AS `total`
FROM `tmc_users` u
LEFT JOIN `tmc_user_usergroup_map` g
ON u.`id` = g.`user_id`
WHERE g.`group_id` = 12
ORDER BY LTRIM(RTRIM(`name`)) ASC
New query
This is what I've tried in order to filter out users who also are in the group_id 17:
SELECT `id`, LTRIM(RTRIM(`name`)), COUNT(`id`) AS `total`
FROM `tmc_users` u
LEFT JOIN `tmc_user_usergroup_map` g
ON u.`id` = g.`user_id`
WHERE g.`group_id` != 17
AND g.`group_id` = 12
ORDER BY LTRIM(RTRIM(`name`)) ASC
However, this returns the same number of rows - 1439 - whereas the actual number of users this should have is 1353.
How can I make this work in one single query?
You can use NOT EXISTS:
SELECT `id`, LTRIM(RTRIM(`name`)), COUNT(`id`) AS `total`
FROM `tmc_users` u
LEFT JOIN `tmc_user_usergroup_map` g
ON u.`id` = g.`user_id`
WHERE g.`group_id` = 12 AND
NOT EXISTS (SELECT 1
FROM `tmc_user_usergroup_map` AS t
WHERE t.`user_id` = u.`id` AND t.`group_id` = 17)
ORDER BY LTRIM(RTRIM(`name`)) ASC
I am attempting to get the sum of 12 columns (in same table) in a subquery in an inner join.
Here is a link to my schema :
SqlFiddle
The query I am attempting to use is this:
SELECT
`inventory`.`part_number`,
`inventory`.`qty`,
`inventory`.`description`,
`reorder`.`reorder_point` * '1' `point`,
`inventory`.`cost`,
`vendor`.`name` AS `vendor_name`, SELECT (SUM(`saleshistory`.`Sales_1_Month_Prior`)+SUM(`saleshistory`.`Sales_2_Month_Prior`)+SUM(`saleshistory`.`Sales_3_Month_Prior`)+SUM(`saleshistory`.`Sales_4_Month_Prior`)+SUM(`saleshistory`.`Sales_5_Month_Prior`)+SUM(`saleshistory`.`Sales_6_Month_Prior`)+SUM(`saleshistory`.`Sales_7_Month_Prior`)+SUM(`saleshistory`.`Sales_8_Month_Prior`)+SUM(`saleshistory`.`Sales_9_Month_Prior`)+SUM(`saleshistory`.`Sales_10_Month_Prior`)+SUM(`saleshistory`.`Sales_11_Month_Prior`)+SUM(`saleshistory`.`Sales_12_Month_Prior`) AS TTL
FROM `inventory`
LEFT JOIN `reorder` ON `inventory`.`part_number` = `reorder`.`part_number`
LEFT JOIN `vendor` ON `inventory`.`vendor` = `vendor`.`vendor_id`
INNER JOIN `saleshistory` ON `saleshistory`.`location` = `inventory`.`location` AND `saleshistory`.`part_number` = `inventory`.`part_number`
WHERE `inventory`.`qty` <= `reorder`.`reorder_point`
AND `inventory`.`location` = '99'
AND `reorder`.`reorder_point` != '0'
GROUP BY `inventory`.`part_number`
ORDER BY `vendor`.`name` ASC
When using this query, it returns all the values for all the records not just the rows.
Something rare to happen is one to one where the second table can have millions of results for the first one. For example, I have a 'radcliente' table that has millions of 'radacct', but need to filter only with the last acct. The following are examples for better explanation:
This is criteria:
$criteria = new CDbCriteria();
$criteria->with = [
'acct', // slow because it will take millions of lines to have only the last
];
$criteria->together = true;
$clientes = Cliente::model()->findAll($criteria);
This is generated query by Yii (very slow, more then 40 seconds, it return millions of rows to use only one in AR):
SELECT
`t`.`id` AS `t0_c0`,
-- ...
`t`.`spc_serasa` AS `t0_c56`,
`acct`.`radacctid` AS `t1_c0`,
-- ...
`acct`.`cliente_id` AS `t1_c27`
FROM
`radcliente` `t`
LEFT OUTER JOIN `radacct` `acct` ON (`acct`.`cliente_id`=`t`.`id`)
ORDER BY
radacctid DESC
After apply my solution limit join to one row (is this fast! 200ms-):
SELECT
`t`.`id` AS `t0_c0`,
..
`t`.`spc_serasa` AS `t0_c56`,
`acct`.`radacctid` AS `t1_c0`,
-- ...
`acct`.`cliente_id` AS `t1_c27`
FROM
`radcliente` `t`
LEFT OUTER JOIN `radacct` `acct` ON (
acct.radacctid = (
SELECT radacctid
FROM `radacct` `acct`
WHERE (acct.cliente_id = t.id)
ORDER BY radacctid DESC
LIMIT 1
)
)
This is the generated query by CActiveDataProvider to total item count with my solution of limit join to one (slow, 10 seconds to count):
SELECT
COUNT(*)
FROM (
SELECT
`t`.`id` AS `t0_c0`,
-- ...
`t`.`spc_serasa` AS `t0_c56`,
`endereco_instalacao`.`id` AS `t1_c0`,
`telefones`.`id` AS `t2_c0`,
`telefones`.`telefone` AS `t2_c3`,
`emails`.`id` AS `t3_c0`,
`emails`.`email` AS `t3_c3`,
`metodo_cobranca`.`id` AS `t4_c0`,
`acct`.`radacctid` AS `t5_c0`,
`acct`.`framedipaddress` AS `t5_c22`
FROM
`radcliente` `t`
LEFT OUTER JOIN `radcliente_endereco_instalacao` `endereco_instalacao` ON (
endereco_instalacao.id = (
SELECT id
FROM `radcliente_endereco_instalacao` `endereco_instalacao`
WHERE (
endereco_instalacao.cliente_id = t.id
)
LIMIT 1
)
)
LEFT OUTER JOIN `radcliente_telefone` `telefones` ON (`telefones`.`cliente_id`=`t`.`id`)
LEFT OUTER JOIN `radcliente_email` `emails` ON (`emails`.`cliente_id`=`t`.`id`)
LEFT OUTER JOIN `radmetodo_cobranca` `metodo_cobranca` ON (
metodo_cobranca.id = (
SELECT id
FROM `radmetodo_cobranca` `metodo_cobranca`
WHERE (metodo_cobranca.cliente_id = t.id)
AND (metodo_cobranca.arquivo = 'nao')
ORDER BY metodo_cobranca.id DESC
LIMIT 1
)
)
LEFT OUTER JOIN `radacct` `acct` ON (
acct.radacctid = (
SELECT radacctid
FROM `radacct` `acct`
WHERE (acct.cliente_id = t.id)
ORDER BY radacctid DESC
LIMIT 1
)
)
GROUP BY t.id
) sq
But the problem is in the count generated by CActiveDataProvider (about 10 seconds to return the result) would have a way to optimize without having to lose the relationship (because I need to filter by a relationship in the future)?
UPDATE
Thank you for your response. I've been doing some tests and noticed that is slow in all cases, the table 'radacct' exacerbates the problem by its size, which should not therefore limit the 1 in the subquery. Follow the models and the link to access the system, if you need to authenticate is:
To access:
http://177.86.111.30/dev2/teste
username: help
password: 1
To download models and schema of radcliente and radacct: http://177.86.111.30/files.zip
Instead of ON id = ( SELECT ... LIMIT 1 ) try adding another JOIN (not LEFT JOIN):
JOIN ( SELECT ... LIMIT 1 ) x ON ...
The fear I have with your code is that it will be evaluating that subquery repeatedly, whenever it needs to check the ON clause. My rewrite will cause the subquery to happen only once.
Your query looks like a "correlated" subquery, so you would need to rephrase it to be non-correlated, if possible.
Looking for some help with optimising the query below. Seems to be two bottlenecks at the moment which cause it to take around 90s to complete the query. There's only 5000 products so it's not exactly a massive database/table. The bottlenecks are SQL_CALC_FOUND_ROWS and the ORDER BY statement - If I remove both of these it takes around a second to run the query.
I've tried removing SQL_CALC_FOUND_ROWS and running a count() statement, but that takes a long time as well..
Is the best thing going to be to use INNER JOIN's (which I'm not too familiar with) as per the following Stackoverflow post? Slow query when using ORDER BY
SELECT SQL_CALC_FOUND_ROWS *
FROM tbl_products
LEFT JOIN tbl_link_products_categories ON lpc_p_id = p_id
LEFT JOIN tbl_link_products_brands ON lpb_p_id = p_id
LEFT JOIN tbl_link_products_authors ON lpa_p_id = p_id
LEFT JOIN tbl_link_products_narrators ON lpn_p_id = p_id
LEFT JOIN tbl_linkfiles ON lf_id = p_id
AND (
lf_table = 'tbl_products'
OR lf_table IS NULL
)
LEFT JOIN tbl_files ON lf_file_id = file_id
AND (
file_nameid = 'p_main_image_'
OR file_nameid IS NULL
)
WHERE p_live = 'y'
ORDER BY p_title_clean ASC, p_title ASC
LIMIT 0 , 10
You could try reducing the size of the joins by using a derived table to retrieve the filtered and ordered products before joining. This assumes that p_live, p_title_clean and p_title are fields in your tbl_products table -
SELECT *
FROM (SELECT *
FROM tbl_products
WHERE p_live = 'y'
ORDER BY p_title_clean ASC, p_title ASC
LIMIT 0 , 10
) AS tbl_products
LEFT JOIN tbl_link_products_categories
ON lpc_p_id = p_id
LEFT JOIN tbl_link_products_brands
ON lpb_p_id = p_id
LEFT JOIN tbl_link_products_authors
ON lpa_p_id = p_id
LEFT JOIN tbl_link_products_narrators
ON lpn_p_id = p_id
LEFT JOIN tbl_linkfiles
ON lf_id = p_id
AND (
lf_table = 'tbl_products'
OR lf_table IS NULL
)
LEFT JOIN tbl_files
ON lf_file_id = file_id
AND (
file_nameid = 'p_main_image_'
OR file_nameid IS NULL
)
This is a "stab in the dark" as there is not enough detail in your question.