I currently have an issue with an SQL query. I have a product table which contains a colour_code field. I cannot alter the product table as it is taken in from an external source.
On the website a user can search a product by colour_code and return all the products available in this colour.
The task at hand is to have a different search term return a certain product which has a different colour code. For this, I added a new table called colour_code_alias which simply has a colour_code field which corresponds to the colour_code field in the product table and an alias field which would return this result. See table examples below.
**Product_tb**
id, colour_code
1, "ABC"
**colour_code_alias_td**
colour_code,alias
"ABC","XYZ"
So, if a user searches for XYZ, they should be returned product with the id of 1. If they search for "ABC" they should also be returned the product with the id of 1.
My problem is that the query is taking too long to execute as it isn't using an index. My simplified query is below:
Select * from product
left join colour_code_alias cca on cca.colour_code = product.colour_code
where (product.colour_code = 'XYZ' or cca.alias = "XYZ")
When I use the explain it shows its not using a key for this query.
When I remove the 'or cca.alias = "XYZ"' in the where clause, the colour_code index from the product table is being used.
I'm looking for help as to increase performance of such a query, how I should index this type of query or even should I rewrite it?
Any help is appreciated.
Thanks,
Martin.
just as a note as to what I've done.. I've removed the left join and added a select query into the where clause. The query looks like the following:
Select * from product
where (product.colour_code = 'XYZ' or product.colour_code = (select colour_code from colour_code_alias where alias = 'XYZ') );
you should have an index on product.colour_code and alias for sure.
another thought is to avoid the OR part entirely by populating the alias table with the original as well... something like:
'ABC','ABC'
that way you have one place to look.
EDIT:
one more thought - use numeric keys instead of strings - this will be more efficient also. (but may be difficult if you can't change the table)
You can try this query:
select *,
(select id from product where colour_code = cod.colour_code ) as id_prod
from
colour_code_alias cod
where (cod.colour_code = 'ABC' or cod.alias = 'XYZ')
Related
I want to replace tags rows in my database news table product where the product name is equal to the product name in another table product.
I want to copy the tags column from the products database to the product database tags must be in the correct row like the name column must match both tables.
I tried a query but it send me an error:
Table to copy = product
Table from copy products
Condition (name=name) or (slug=slug)
In both Table:
UPDATE product
set tags = (
select tags
FROM products
where product.name = products.name
);
It gives an error:
Subquery returns more than 1 row
It works with:
UPDATE product
set tags = (
select tags
FROM products
where product.id = products.id
);
What I have found to better understand and make sure you ultimately want in the final update, yet also make sure you are getting the records intended. Write the select first.
select
np.name,
np.tags NowTags,
op.tags OtherTags
from
NowProduct np
JOIN OtherProduct op
on np.Name = op.Name
Once you have this confirmed, just change the SELECT to an UPDATE. You can use the "alias" for the table being updated. I found its best to make sure your query is correct to see what records WILL be queried and what the before and what you WANT updated values should be. Once good, then apply update.
update np set
tags = op.tags
from
NowProduct np
JOIN OtherProduct op
on np.Name = op.Name
I just can't see the problem with how I'm making my foreign keys and I'm just really confused why I keep getting the wrong result. Here are screenshots from my workbench
Here are my tables:
And here's my diagram
I've also tried to normalize my tables and I was kinda expecting my query to return a similar result like in the sample table (Questions table) where it will only show 2 results since I want to query where idsurvey = 1 I made in this image:
My question is that, how do I fix my foreign key so that if I want to query
select * from survey.survey, survey.questions where idsurvey = 1
it will only return 2 rows? (based on sample data in the workbench screenshot)
Any comments and suggestions on my diagram would also be greatly appreciated.
When you have two tables in the from clause, every row from the first table is matched with every table from the second table. This is known as a Cartesian Product. Usually, this isn't the behavior you'd want (like it isn't in this case), and you'd use a condition to tell the database how to match these two tables:
SELECT *
FROM survey.survey s, survey.questions q
WHERE s.idsurvey = q.survey_id AND idsurvey = 1
While this should work, it's quite outdated to use multiple tables in the same from clause. You should probably use an explicit join clause instead:
SELECT *
FROM survey.survey s
JOIN survey.questions q ON s.idsurvey = q.survey_id
WHERE idsurvey = 1
I have a table for users. But when a user makes any changes to their profile, I store them in a temp table until I approve them. The data then is copied over to the live table and deleted from the temp table.
What I want to achieve is that when viewing the data in the admin panel, or in the page where the user can double check before submitting, I want to write a single query that will allow me to fetch the data from both tables where the id in both equals $userid. Then I want to display them a table form, where old value appears in the left column and the new value appears in the right column.
I've found some sql solutions, but I'm not sure how to use them in php to echo the results as the columns in both have the same name.
Adding AS to a column name will allow you to alias it to a different name.
SELECT table1.name AS name1, table2.name AS name2, ...
FROM table1
INNER JOIN table2
ON ...
If you use the AS SQL keyword, you can rename a column just for that query's result.
SELECT
`member.uid`,
`member.column` AS `oldvalue`,
`edit.column` AS `newvalue`
FROM member, edit
WHERE
`member.uid` = $userId AND
`edit.uid` = $userId;
Something along those lines should work for you. Although SQL is not my strong point, so I'm pretty sure that this query would not work as is, even on a table with the correct fields and values.
Here is your required query.
Let suppose you have for example name field in two tables. Table one login and table 2 information. Now
SELECT login.name as LoginName , information.name InofName
FROM login left join information on information.user_id = login.id
Now you can use LoginName and InofName anywhere you need.
Use MySQL JOIN. And you can get all data from 2 tables in one mysql query.
SELECT * FROM `table1`
JOIN `table2` ON `table1`.`userid` = `table2`.`userid`
WHERE `table1`.`userid` = 1
I have a table called PRODUCTS. It has a field of language. I want to list all rows of language = 'es' which do lack a traduction (corresponding ID) in other language. I have tried the following (id_products is the key relating rows of the same product in different language). It is extremely slow (seconds for a few thousand rows):
SELECT
*
FROM
products AS source
LEFT JOIN products AS target ON source.id_products = target.id_products
AND source.`language` = 'es'
AND target.`language` = 'en'
WHERE
target.id_products IS NULL
My guess is that this is happening due to lack of indexes on the table.
Try adding index on (id_products,language) , that should speed up your query.
In addition you can try to use NOT EXISTS() instead of a left join, maybe it will speed things up a bit as well:
SELECT * FROM products t
WHERE t.language = 'es'
AND NOT EXISTS(SELECT 1 FROM products s
WHERE s.language = 'en'
and s.id_products = t.id_products)
Better index
It will be faster with the composite index in this order:
INDEX(language, id_products)
The query will start with source. For that it needs to look at rows with language = 'es', then reach into target. For target it does not matter which order the index columns are in.
Don't be mislead by the Query cache
If you get a time of less than 1 millisecond, the you are probably getting the answer from the "Query cache". For testing, avoid it by doing
SELECT SQL_NO_CACHE ...
There is no use doing SELECT * ... since you only want source columns, not all the NULLs from target. So either say SELECT source.* or spell out just the columns you want.
There is something weird with where you do the filtering in your query.
You'll get a list of all products, regardless of if source is in 'es' or not. I always recommend to put all the ON-conditions inside parenthesis for clarity.
SELECT *
FROM products AS source
LEFT JOIN products AS target
ON (source.id_products = target.id_products AND target.language = 'en')
WHERE source.language = 'es'
AND target.id_products IS NULL;
And as other points out you also need an index on language for the filtering on source, and depending on how large your tabell is, also on id_products.
alter table products add index search_index (language, id_products);
See this sql fiddle to see it in action.
I wonder if any can help me understand something I'm trying to solve.
I'm working on a wordpress site but this is more a sql question as I'm just querying to get some results within a template file.
I have a gallery of pictures which are advert boxes, and I need to pull these in relation to a supplied movie name, to do this Im using some custom fields on the ad pic called 'adlink' (link off ad) and ad
I'm using the nextgen gallery plugin and querying those tables, and I have three tables in total that contain the data I need to query.
ngg_pictures, nggcf_field_values & nggcf_fields.
the nggcf tables are custom fields tables,
I have got so far I can get what I need in two seperate queries, but I can't combine these into one query as it means querying the nggcf_field_values table twice, which I can't seem to sort.
I have hardcoded the search criteria in for the mo, but the 'close-encounters' bit would be a passed var, and the '156' would be the pid from the first query.
SELECT `eg_ngg_pictures`.`filename`, `eg_nggcf_field_values`.`fid`, `eg_nggcf_field_values`.`pid`
FROM eg_ngg_pictures, eg_nggcf_field_values
WHERE ((`eg_nggcf_field_values`.`field_value` LIKE 'close-encounters') AND (`eg_nggcf_field_values`.`pid` = eg_ngg_pictures.pid))
SELECT `eg_nggcf_field_values`.`field_value`
FROM eg_nggcf_field_values, eg_nggcf_fields
WHERE ((`eg_nggcf_fields`.`field_name` = 'adlink') AND (`eg_nggcf_fields`.`id` = eg_nggcf_field_values.fid) AND (`eg_nggcf_field_values`.`pid` = '156'))
any help would be greatly appreciated, I can get the results with what I have, but I like to understand how to combine these two and write better SQl. Thanks MRO
After looking at the Wordpress extension, I think the eg_nggcf_fields is the table that contains the name for a custom field. The eg_nggcf_field_values table contains the values of that custom field per picture.
So if you're looking for two fields called moviename and adlink, you have to look up two rows in the field_values table. You can join a table twice if you give it a different alias:
select pic.filename
, pic.pid
, fv1.field_value as MovieName
, fv2.field_value as Adlink
from eg_ngg_pictures pic
inner join -- Find ID for the field called 'moviename'
eg_nggcf_fields f1
on f1.field_name = 'moviename'
inner join -- Find value for field moviename for this picture
eg_nggcf_field_values as fv1
on fv1.pid = pic.pid
and fv1.fid = f1.fid
inner join -- Find ID for the field called 'adlink'
eg_nggcf_fields f2
on f2.field_name = 'adlink'
inner join -- Find value for field adlink for this picture
eg_nggcf_field_values as fv2
on fv2.pid = pic.pid
and fv2.fid = f2.fid
where fv1.field_value like 'close-encounters'
First of all, I'd recommend sticking to modern ANSI syntax for JOINing tables, which means using the JOIN clause.
Instead of using:
FROM table1, table2 WHERE table1.id = table2.pid
use:
FROM Table 1 JOIN table2 ON table1.id = table2.id
For simplicity's sake, I'd also recommend you to alias tables, as that tends to make the code more readable. Instead of having to write out egg_ngg_pictures every time, you can simply refer to the alias you assign it instead.
Lastly, when you use a LIKE operator, you usually add a wild-card character (typically %. I.e. LIKE '%123' or LIKE '123%'). You seem to look only for complete matches, which means you can just stick to using =, as that should give you slightly better performance.
Now to rewrite your query, I'd use something like the following:
SELECT
pic.filename
, fieldval.fid
, fieldval.pid
, fieldval.field_value
FROM
eg_ngg_pictures pic
JOIN eg_nggcf_field_values fieldval ON fieldval.pid = pic.pid
JOIN eg_nggcf_fields fields ON fields.id = fieldval.fid
WHERE
((fieldval.field_value = 'close-encounters')
AND fields.field_name = 'ad_link'
Note that I am not able to test the query, as I do not have your schema. But by incorporating the two queries into a single query, the join on the field_Values.PID retreieved with the 'close_encounters' value should already exist.
If the query does not work, feel free to create a SQL fiddle with the relevant tables and some data, and I'll try and get it to work with that.