I am doing quite a large query to a database and for some reason it is returning many results that do not match any of my search terms. It also seems to duplicate my results so I get the same SQL item 16 times. Any ideas why?
SELECT a.*
FROM
j20e8_datsogallery AS a,
j20e8_datsogallery_tags AS t
WHERE
(a.id LIKE "%bear%" OR
a.imgtitle LIKE "%bear%" OR
a.imgtext LIKE "%bear%" OR
a.imgauthor LIKE "%bear%" OR
t.tag LIKE "%bear%")
ORDER BY a.id DESC
LIMIT 0, 16
I think it maybe something to do with the LIKE %term% section but cannot get it working at all.
I'd make sure you qualify your join. Otherwise you'll end up with a full join, or worse, a Cartesian product from a cross join. Something along these lines:
SELECT a.*
FROM
j20e8_datsogallery AS a
JOIN j20e8_datsogallery_tags AS t ON a.ID = t.GalleryID
WHERE
...
ORDER BY a.id DESC
LIMIT 0, 16
Also, consider using a FULLTEXT INDEX ... it could combine all those columns into a single index, and would make searching all of them quite functional.
A FULLTEXT INDEX in MySql can be used to 'combine' several different columns into one big pile of text, which you can then MATCH() columns AGAINST search terms.
To create a FULLTEXT INDEX, you can simply use the CREATE INDEX syntax documented here.
CREATE FULLTEXT INDEX FDX_datsogallery
ON j20e3_datsogallery ( id, imgtitle, imgtext, imgauthor )
You can then use it in a query with the MATCH() ... AGAINST statements, which are documented here:
SELECT a.*
FROM j20e8_datsogallery AS a
WHERE MATCH( id, imgtitle, imgtext, imgauthor ) AGAINST( 'bear' )
It's bringing back multiples because:
SELECT a.*
FROM j20e8_datsogallery AS a, j20e8_datsogallery_tags AS t
brings back every combination of records from the two tables on it's own. So bear in one table joins to every record in the other table.
You need to specify a relationship between the tables, preferably using an explicit JOIN
You have a cross join between the two tables, which means every row in a will be joined with every row in t, and as I said in my comment, you will be getting every record that has bear in one of those fields.
you should have a join condition somewhere. Then do your filtering.
Your results are a cartesian product of your data, because you don't have a join condition. This means that it is returning every combination of matching rows from a and t.
You probably need to so something like this:
SELECT a.*
FROM
j20e8_datsogallery AS a,
INNER JOIN j20e8_datsogallery_tags AS t ON a.id = t.a_id --(or whatever the foreign key is)
WHERE
(a.id LIKE "%bear%" OR
a.imgtitle LIKE "%bear%" OR
a.imgtext LIKE "%bear%" OR
a.imgauthor LIKE "%bear%" OR
t.tag LIKE "%bear%")
ORDER BY a.id DESC
LIMIT 0, 16
Related
I have what I believe to be a pretty unique use case. I would like to be able to runs a single SELECT statement on a database where I get one column from four tables. I need to run where clauses on each different table where I have one main clause that will be across each of the tables and I am not able to JOIN because the data in each column will be a different length and I don't want to have duplicate items.
I have an example of the Select statement below. Also I understand if this is not possible.
SELECT s.service_id, u.id AS "user_id", h.mac_address, l.id AS "location_id" FROM services s
LEFT JOIN db.av_product ap ON s.product_id = ap.id
WHERE s.customer_code LIKE 'test_customer'
AND u.customer_code LIKE 'test_customer'
AND h.customer_code LIKE 'test_customer'
AND l.customer_code LIKE 'test_customer'
AND s.parent_id IS NULL
AND s.active=0
AND ap.sku NOT REGEXP 'fakeregex'
AND l.active = "1"
AND h.hardware_id NOT IN ('44','45')
AND (u.support_user != 1 OR u.support_user IS NULL);
TIA!
You will need to use joins for your tables to make a single query OR you can try multiple queries merged with UNION keyword.
If you want to make a single query, have a look about SELECT DISTINCT or GROUP BY for handling duplicates.
wut up?
do you know what UNION is?
The UNION operator is used to combine the result-set of two or more SELECT statements.
but every SELECT statement within UNION must have the same number of columns; so there we got a problem.
you can handle it with WHERE operator so I won't get in to it.
anyway, UNION!
shall we?
SELECT column_name(s) FROM table1
UNION
SELECT column_name(s) FROM table2;
anyway; your solution is UNION, maybe not like what I wrote.
you can try this link too.
https://www.w3schools.com/mysql/mysql_union.asp
have a clean code
What is the internal order of operations in a MySQL SELECT query and a relational query?
For instance, a SELECT query to a single table:
SELECT `name`
FROM `users`
WHERE `publication_count`>0
ORDER BY `publication_count` DESC
I know that at first all table fields are fetched and then only name field is left at the end. Does it happen before or after the condition in WHERE is applied? When is ORDER BY applied?
A relational query using two tables:
SELECT `users`.`name`, `post`.`text`
FROM `users`, `posts`
WHERE `posts`.`author_id`=`user`.`id`
ORDER BY `posts`.`date` DESC
Same question. What happens after what? (I know that at first the Cartesian product is generated)
Processing regarding your example simplifying the rules goes as follow:
1. FROM -- all elements in list (including multiple tables)
2. WHERE -- discard rows not matching conditions
3. SELECT -- output rows are computed (not fetched)
4. ORDER BY -- sort output rows
Also, you shouldn't be using old-fashioned implicit join syntax in WHERE condition. Instead, please use JOIN:
SELECT ...
FROM users
INNER JOIN posts ON users.id = posts.author_id
ORDER BY ...
Related to my last question (MySQLi performance, multiple (separate) queries vs subqueries) I came across another question.
Sometimes I'm using a subquery to select the value from another table (eg. the username connected to an ID), but I'm not sure about the select-in-select, because it doesn't seem to be very clean and I'm not sure about the performance.
The subquery could look like this:
SELECT
(SELECT `user_name` FROM `users`
WHERE `user_id` = table2.user_id) AS `user_name`
, `value1`
, `value2`
FROM
`table2`
....
Would it be "better" to use a separate query for the result from table1 and another for table2 (doubles the connections, but no need to cross tables), or should I even use a JOIN to get the results in a single query?
I don't have much experience with JOINS and subqueries yet, so I'm not sure if a JOIN would be "too much" in this case, because I really just need one name connected to an ID (or maybe count the number of rows from a table), or if it doesn't matter, because the select-in-select is treated like some kind of JOIN, too..
Solution with JOIN could look like this:
SELECT
users.user_name , table2.value1, table2.value2
FROM
`table2`
INNER JOIN
`users`
ON
users.user_id = table2.user_id
....
And if I should prefer JOIN, which one would be best in this case: left join, inner join or something else?
The very fact that you are asking whether to use inner join or left join indeed shows that you haven't done much work with them.
The purposes of these two are entirely different, inner join is used to return columns from two or more tables where some columns have matching values. left join is used when you want the rows from the table specified left in the join clause to return even when there is no matching column in the other tables. It depends on your application. If one table has names of players, and another table contains details of penalties paid by them, then you will most certainly want to use left join, to account for players without a penalty, and thus without a record in the 2nd table.
Regarding whether to use subquery or join, joins can be much faster when properly used. By properly I mean, when there are indices on the join columns, the tables are specified in increasing order of the number of containing rows (generally. There might be exceptions), the join columns have similar data-types, etc. If all these conditions match, join would be the better option.
I have a complex nested-query which is inside a join, is it possible to find several columns that match that query instead of repeating the query in the Join? ie:
select * from
A left join B on a.xid=b.xid and
(a.userid or b.userid) in (select userid from A where..)
^^^ don't want to duplicate the nested-query...
There is a nested query that should match several columns from the parent-query (as seen in the example above). The simple way is to duplicate the nested query several times. ie-
select * from A
left join B
on a.xid=b.xid
and a.userid in (select userid from ...)
and b.userid in (Select userid from ....)
BUT - since the subquery is bit complicated I don't want mysql to run it twice, but rather only once and than match it against several of the parent query columns.
If your subquery is working properly and you have the query cache turned on you won't have to worry about performance. If its a question of it being overly complex then maybe you could use a proc for this query: put the results of the sub into a temp table and join to it.
There are lots of ways to approach this.
Is it possible to order the GROUP BY chosen results of a MySQL query w/out using a subquery? I'm finding that, with my large dataset, the subquery adds a significant amount of load time to my query.
Here is a similar situation: how to sort order of LEFT JOIN in SQL query?
This is my code that works, but it takes way too long to load:
SELECT tags.contact_id, n.last
FROM tags
LEFT JOIN ( SELECT * FROM names ORDER BY timestamp DESC ) n
ON (n.contact_id=tags.contact_id)
WHERE tags.tag='$tag'
GROUP BY tags.contact_id
ORDER BY n.last ASC;
I can get a fast result doing a simple join w/ a table name, but the "group by" command gives me the first row of the joined table, not the last row.
I'm not really sure what you're trying to do. Here are some of the problems with your query:
selecting n.last, although it is neither in the group by clause, nor an aggregate value. Although MySQL allows this, it's really not a good idea to take advantage of.
needlessly sorting a table before joining, instead of just joining
the subquery isn't really doing anything
I would suggest carefully writing down the desired query results, i.e. "I want the contact id and latest date for each tag" or something similar. It's possible that will lead to a natural, easy-to-write and semantically correct query that is also more efficient than what you showed in the OP.
To answer the question "is it possible to order a GROUP BY query": yes, it's quite easy, and here's an example:
select a, b, sum(c) as `c sum`
from <table_name>
group by a,b
order by `c sum`
You are doing a LEFT JOIN on contact ID which implies you want all tag contacts REGARDLESS of finding a match in the names table. Is that really the case, or will the tags table ALWAYS have a "Names" contact ID record. Additionally, your column "n.Last". Is this the person's last name, or last time something done (which I would assume is actually the timestamp)...
So, that being said, I would just do a simple direct join
SELECT DISTINCT
t.contact_id,
n.last
FROM
tags t
JOIN names n
ON t.contact_id = n.contact_id
WHERE
t.tag = '$tag'
ORDER BY
n.last ASC