Searching a keyword from multiple tables using my query , - mysql

I want to search "law" from three tables tbl_books, tbl_books_author and tbl_books_subject. I am running following query.
SELECT *
FROM tbl_books p, tbl_books_author d, tbl_books_subject m
WHERE p.title = 'law'
OR d.author = 'law'
OR m.subject = 'law'
LIMIT 0,30;
When I run this query it shows on top "Showing rows 0 - 29 (1759260 total, Query took 5.1206 sec)". can you please explain why it is showing this.
What is the reason for this?

As already pointed out, you are doing a Cartesian product i.e. matching all records from first table with all records from 2nd tables and with 3d table.
You probably have some foreign keys relating tables, so your query should look like:
SELECT *
FROM tbl_books p
INNER JOIN tbl_books_author d ON inner_join_condition1
INNER JOIN tbl_books_subject m ON inner_join_condition2
WHERE p.title = 'law'
OR d.author = 'law'
OR m.subject = 'law'
LIMIT 0,30;
fill in with you inner_join_conditions between tables

Related

MySQL INNER JOIN, get the last entries, not the first

I am having an issue with my multi join SQL statement, where I need to get the last entries of the table and not the first. I have 3 tables that I try to query based on this statement:
SELECT DISTINCT i.id,i.hz,i.v,i.t,i.u,i.temp, i.c1, s.server, s.hostname, h.codes,s.cpus FROM `dc_servers` AS s INNER JOIN `dc_hardware` AS h ON s.server = h.server INNER JOIN `dc_systemusage` AS i ON s.server = i.server GROUP BY i.server
The tables dc_servers & dc_hardware only has 1 row per server, however the table dc_systemusage has many rows with the same server, as new info is being added.
When I run the query, I get the first entries from the dc_systemusage, but I need to get the latest entries from that table, for me it sounds like I need an ORDER BY, however if I add that to the end of the query like this:
SELECT DISTINCT i.id,i.hz,i.v,i.t,i.u,i.temp, i.c1, s.server, s.hostname, h.codes,s.cpus FROM `dc_servers` AS s INNER JOIN `dc_hardware` AS h ON s.server = h.server INNER JOIN `dc_systemusage` AS i ON s.server = i.server GROUP BY i.server ORDER BY i.id DESC
then I am just ordering the result, which is not what I am looking for.
I hope someone can guide me in the right direction as for how I can get the latest rows and not the first from the table dc_systemusage
I hope I have provided the needed information to guide me, else please do let me know and I will add whatever is neeeded.
Thank you all.
You can find dc_systemusage lastest ids in subquery and use with WHERE ... IN
SELECT i.id,i.hz,i.v,i.t,i.u,i.temp, i.c1, s.server, s.hostname, h.codes,s.cpus
FROM `dc_servers` AS s
INNER JOIN `dc_hardware` AS h ON s.server = h.server
INNER JOIN `dc_systemusage` AS i ON s.server = i.server
WHERE i.id IN (SELECT max(dc_systemusage.id) FROM dc_systemusage GROUP BY dc_systemusage.server)
and check a great answer at https://stackoverflow.com/a/3800572/7174186

select count with another select and inner join

Is it possible to use two "select" in the same query?
I tried it but got the syntax error several times.
My query example:
SELECT
comp.id,
comp.document,
comp.dateStart,
comp.companyName,
comp.fantasyName,
comp.legalNature,
comp.mainActivity,
comp.situation,
comp.shareCapital,
comp.idCompanyStatus,
pp.userCredentialId,
uc.name,
cs.name AS 'nameStatus',
cs.color AS 'colorStatus',
cs.description,
comp.idPurchasedProduct,
comp.actived,
comp.createAt,
comp.updateAt,
comp.phone
FROM `PurchasedProduct` pp
INNER JOIN
`Company` comp on comp.idPurchasedProduct = pp.id
INNER JOIN
`UserCustomer` uc on pp.userCredentialId = uc.credentialId
INNER JOIN
`CompanyStatus` cs on cs.id = comp.idCompanyStatus
WHERE
comp.actived = 1
LIMIT 0,5;
SELECT COUNT(id) AS totalItems, CEILING(COUNT(id) / 10) AS totalPages FROM Company;
I would like the result shown to be all queries on the screen.
Basically, what I want is that the result shown when executing the query is the first and second "select" together.
I really don't know how or don't understand how to do this.
Example:
first result with seconde result
I want to show both results at once.
The documents is fake, not real. Only for demo.
You should be able to do by having the second query as its own JOIN query. Since there is no group by, it is only returning a single row. By no join condition, the value will be available for every row otherwise. So you SHOULD be able to get by doing
select
[ all your other columns ],
JustCounts.TotalItems,
JustCounts.TotalPages
from
[PurchasedProduct and all your other joins]
JOIN ( SELECT
COUNT(id) AS totalItems,
CEILING(COUNT(id) / 10) AS totalPages
FROM Company ) as JustCounts
where
[rest of your original query]

Understanding why this query is slow

The below query is very slow (takes around 1 second), but is only searching approx 2500 records (+ inner joined tables).
if i remove the ORDER BY, the query runs in much less time (0.05 or less)
OR if i remove the part nested select below "# used to select where no ProfilePhoto specified" it also runs fast, but i need both of these included.
I have indexes (or primary key) on :tPhoto_PhotoID, PhotoID, p.Enabled, CustomerID, tCustomer_CustomerID, ProfilePhoto (bool), u.UserName, e.PrivateEmail, m.tUser_UserID, Enabled, Active, m.tMemberStatuses_MemberStatusID, e.tCustomerMembership_MembershipID, e.DateCreated
(do i have too many indexes? my understanding is add them anywhere i use WHERE or ON)
The Query :
SELECT e.CustomerID,
e.CustomerName,
e.Location,
SUBSTRING_INDEX(e.CustomerProfile,' ', 25) AS Description,
IFNULL(p.PhotoURL, PhotoTable.PhotoURL) AS PhotoURL
FROM tCustomer e
LEFT JOIN (tCustomerPhoto ep INNER JOIN tPhoto p ON (ep.tPhoto_PhotoID = p.PhotoID AND p.Enabled=1))
ON e.CustomerID = ep.tCustomer_CustomerID AND ep.ProfilePhoto = 1
# used to select where no ProfilePhoto specified
LEFT JOIN ((SELECT pp.PhotoURL, epp.tCustomer_CustomerID
FROM tPhoto pp
LEFT JOIN tCustomerPhoto epp ON epp.tPhoto_PhotoID = pp.PhotoID
GROUP BY epp.tCustomer_CustomerID) AS PhotoTable) ON e.CustomerID = PhotoTable.tCustomer_CustomerID
INNER JOIN tUser u ON u.UserName = e.PrivateEmail
INNER JOIN tmembers m ON m.tUser_UserID = u.UserID
WHERE e.Enabled=1
AND e.Active=1
AND m.tMemberStatuses_MemberStatusID = 2
AND e.tCustomerMembership_MembershipID != 6
ORDER BY e.DateCreated DESC
LIMIT 12
i have similar queries that but they run much faster.
any opinions would be grateful:
Until we get more clarity on your question between working in other query etc..Try EXPLAIN {YourSelectQuery} in MySQL client and see the suggestions to improve the performance.

optimizing query (LEFT JOIN)

My goal is to show search results of companies both: with categories and without (not added yet). My companies table has more or less 12 000 records. Companies with categories are only more or less 200.
There are two search inputs:
$name -> name of company or category.
$id_country -> id of the country
I want to display:
1) how many results is in all database. (that's why i use: SQL_CALC_FOUND_ROWS)
2) i use LIMIT to show 10 results per page (with pagination).
My query:
SELECT SQL_CALC_FOUND_ROWS
c.*,
lc.name as langName,
lc.shortDesc,
lc.longDesc
FROM companies c
JOIN lang_companies lc USING(id_company)
LEFT JOIN categories_companies cc USING(id_company)
LEFT JOIN lang_categories lang_cat USING (id_category)
WHERE
lc.id_lang = '2' AND c.status = 1 AND c.active = 1 AND c.id_country = ".$id_country." AND
(lc.name = LCASE('".$name."') OR (lang_cat.name = LCASE('".$name."') AND lang_cat.id_lang = '2')
OR c.city = '".$name."')
GROUP BY c.id_company
ORDER BY c.id_hierarchi asc
LIMIT 0, 10
This query executes more or less 6 seconds and I want to optimize it. Could you help me?
I will be grateful for any suggestions.
Out of the FROM part of your query, you do not seem to actually use the tables which are joined with these two lines:
LEFT JOIN categories_companies cc USING(id_company)
LEFT JOIN categories cat USING (id_category)
I presume you can simply exclude them from the query, if they are not relevant through something more sublte like the join suppressing rows.

Comparing two values from the same select query

I have a select query which selects all products from my inventory table and joins them with two other tables (tables l_products and a_products)
SELECT
i.*,
b.title,
ROUND((i.price/100*80) - l.price,2) AS margin,
l.price AS l_price,
a.price AS a_price,
ROUND((a.price/100*80) - l.price, 2) AS l_margin
FROM inventory i
LEFT JOIN products b ON i.id = b.id
LEFT JOIN a_products a ON i.id = a.id
LEFT JOIN l_products l ON i.id = l.id
WHERE
a.condition LIKE IF(i.condition = 'New', 'New%', 'Used%')
AND l.condition LIKE IF(i.condition = 'New', 'New%', 'Used%')
This select query will normally give me a table such as...
id, title, condition, margin, l_price, a_price ...
001-new ... new 10 20 10
001-used ... used 10 25 20
002....
Now I need a condition in the query which will ignore all used products that are more expensive (have a higher a_price) than their 'new' counterparts, such as in the example above you can see that 001-used has a higher a_price than 001-new.
How can I achieve this with out having to resolve to using php
FULL JOIN this query with it self on a column which has a uniquely same value for each id prefix.
You may achieve this effect by adding another field to your SELECT call which produces same unique value for 001-new and 001-used, 002-new and 002-used...
Such value generation can be done by defining your own SQL Routine to extract first 3 characters from a column.