Hi developer/dba friends I have small issues for fetching details with mysql tables as following :
I have cid lets say cid=xxx
I want output(cid,ruser_id,dtoken,akey,prase) in one record using cid as key input
what mysql query I should perform that can also optimise this fetch with smooth less time on execution?
table structure is as following:
tbl_mk(cid,pro_id) -> pro_id primary key of tbl_pro
tbl_luser(cid,ruser_id) -> ruser_id primary key of tbl_ruser
tbl_ruser(id,dtoken)->id is primary key of this tbl_ruser where its referenced in tbl_luser as ruser_id
tbl_pro(id,akey)-> id is primary key of this tbl_pro which its referenced in tbl_mk as pro_id
tbl_app(akey,prase)
primary id/reference naming convention is i.e like if name of table is
tbl_name then id referenced in other table for tbl_name is name_id. where id is primary key of tbl_name.
I know there are lot of mysql experts here so how to make it working with less efforts, fyi I am basically mobile app developer but there is time m working on some mysql stuffs for web apis needs :)
Thanks and I really appreciate and admire if some one can solve this problem for me.I did one query and getting details but seems its not proper way I need more efficient way thats why m posting here.
Waiting for some best reply with expected answer.
Just join the tables. Assuming :cid is your input:
SELECT l.cid, l.ruser_id, r.dtoken, p.akey, prase
FROM tbl_luser l
JOIN tbl_ruser r ON l.ruser_id = r.id
JOIN tbl_mk m ON l.cid = m.cid
JOIN tbl_pro p ON p.id = m.prod_id
JOIN tbl_app a ON a.akey = p.akey
WHERE l.cid = :cid
Related
I have a table Customer with Primary key customerNumber. I also have a table table customerOrder that has a foreign key FK_customerNumber to customerNumber in the Customer table.
I know the customerNumber and need to select only order information related to that user.
I see a lot of tutorials using a JOIN like this
SELECT
projectNumber, orderNumber
FROM
`customerOrder` t1
INNER JOIN `customer` t2
ON t1.`FK_customerNumber` = t2.`customerNumber`
WHERE
t2.`customerNumber` = 50;
It's working but why can't I just select the FK? I get the same result. The value of the FK in customerOrder and PK in customer are the same.
This gives me the same result without JOIN
SELECT
projectNumber, orderNumber
FROM
`customerOrder`
WHERE
`FK_customerNumber` = 50;
I understand if I need info from both tables like this but now I only need info from the customerOrder
SELECT customerOrder.`projectNumber`, customer.`username`
FROM `customerOrder`
INNER JOIN customer ON customerOrder.`FK_customerNumber` = customer.`customerNumber`;
Why can't I just select the FK
You can.
I can't speak for the tutorial writers, but I'd hazard a guess that they're trying to demonstrate how the JOIN works - the principle that you've something on the left and something related on the right, and a JOIN is how you associate those two things.
If you perform an EXPLAIN SELECT ... - you'll likely see that MySQL has optimised out looking at the left table altogether, as it knows you're only really dealing with data on the right.
The only scenario I could foresee necessitating the JOIN is if there's no foreign key constraint on the right. In that scenario, the more verbose SELECT ... FROM ... JOIN ... would ensure that you don't get anything from the right if it's missing from the left (which the foreign key constraint would prevent from being the case).
Other reasons you might opt to be more verbose:
The query is "more explicit" - someone coming to it afresh can see the relationship of the two tables at a glance (that might be desirable, depending on context)
You intend to pull some additional data from the left at some point soon (feature isn't completed in code yet)
Equally you might explicitly choose not to include the join for the sake of ensuring optimal performance. (But as I say, you'd be surprised at how good MySQL is at optimising on its own :-))
I’m using Wordpress quiz plugin. It has two tables (in fact more, but I’m trying to focus on the issue) – ‘questions’ and ‘questionpots’:
‘questions’: questionID ---- Question ---- potID
‘questionpots’: potID ---- potName
And the default query is:
$SQL = 'Select * FROM questions WHERE potID='.$potID;
So by default every question is assigned to a specific pot (‘potID’ in ‘questions’ table) and the relation is ‘one to many’. What I want to do is to assign questions to MORE than just one pot, so that for example the question “When did Rome fell?” would be asked whether someone choose “Rome history” pot OR “Ancient history” pot.
So I added the third table, ‘relations’, which matches questionIDs and potIDs.
The problem is I can’t figure out the query to select * from ‘questions’ WHERE potID='.$potID assuming that there’s one or MORE than one question for $potID.
How should I join this tables?
Thanks.
To resolve a many-to-many relationship between two entities, we add a third table, a relationship table, with foreign keys referencing the two entity tables.
A row added to the relationship table represents a (wait for it...) relationship between the two entities.
As an example, assuming tables question and pot both have an id column as the primary key:
CREATE TABLE question_pot
( question_id INT UNSIGNED NOT NULL COMMENT 'fk ref question'
, pot_id INT UNSIGNED NOT NULL COMMENT 'fk ref pot'
, PRIMARY KEY (question_id, pot_id)
, CONSTRAINT FK_question_pot_question
FOREIGN KEY (question_id) REFERENCES question(id)
, CONSTRAINT FK_question_pot_pot
FOREIGN KEY (pot_id) REFERENCES pot(id)
) ENGINE=InnoDB
To add a relationship from question id=444 to two pots pot id=7 and pot id=13:
INSERT INTO question_pot VALUES (444,7), (444,13);
And scrap the pot_id column in the question table. You can save those first...
INSERT INTO question_pot (question_id, pot_id)
SELECT q.id
, q.pot_id
FROM question q
WHERE q.pot_id IS NOT NULL
;
And then drop the pot_id column from question.
If you've gotten that far, now you just need to perform JOIN operations...
To get all questions in pot id=13, for example:
SELECT q.*
FROM question q
JOIN question_pot r
ON r.question_id = q.id
WHERE r.pot_id = 13
FOLLOWUP
The query above gives an example of assigning an alias to a table, and using the alias to qualify column references.
Qualifying column references is best practice; it makes the statement easier for someone to read and interpret, without requiring them to lookup the definitions of the tables to figure out which column is coming from which table.
Compare the query above to this:
SELECT *
FROM question
JOIN question_pot
ON question_id = id
WHERE pot_id = 13
Now, try answering these questions: Is id a reference to a column from question or question_pot. (If this query is in a MySQL stored program (procedure, function, trigger), is the reference to id a reference to a column, or to a procedure variable.)
In some cases, we have to qualify column references to make the reference unambiguous, when the reference can refer to a column in multiple tables, and causes MySQL to throw an ambiguous column reference error.
It's possible to have a query working just fine, and then add a column to a table, e.g. adding id column to the question_pot table, and then the query will start failing with the "ambiguous column" error.
In my way of thinking, it's not acceptable that the addition of a column to a table should cause a "working" query to break. We can prevent that kind of error popping up in the future, simply by explicitly qualifying the column reference, even if it's not required right now.
As far as why we choose to use short aliases like q and r in place of just the table name.
In EXACTLY the same way you've identified the table names in your comment:
wp_ai_quiz_tblquestions (=question)
wp_ai_quiz_tblquestionpots (=pot)
wp_ai_quiz_question_pot (=question_pot)
I'm essentially saying the same thing with the table aliases:
wp_ai_quiz_tblquestions (=q)
wp_ai_quiz_tblquestionpots (=p)
wp_ai_quiz_question_pot (=r)
Compare reading this:
SELECT q.*
FROM wp_ai_quiz_tblquestions q
JOIN wp_ai_quiz_question_pot r
ON r.question_id = q.id
WHERE r.pot_id = 13
To reading this:
SELECT wp_ai_quiz_tblquestions.*
FROM wp_ai_quiz_tblquestions
JOIN wp_ai_quiz_question_pot
ON wp_ai_quiz_question_pot.question_id = wp_ai_quiz_tblquestions.id
WHERE wp_ai_quiz_question_pot.pot_id = 13
Throw in a few more tables, and also don't line things up like I always line things up, and it requires more effort from the reader to decipher what the statement is doing. In really complicated queries, referencing half a dozen or more tables, I'll add comments above the query, explaining the usage of the aliases.
-- find all questions in a particular pot
-- q = question row to be returned from wp_ai_tblquestion
-- r = relationship between question and pot to be searched
SELECT q.id
, q.name
, ...
SELECT COUNT(DISTINCT r.id)
FROM views v
INNER JOIN emails e ON v.email_id = e.id
INNER JOIN recipients r ON e.recipient_id = r.id
INNER JOIN campaigns c ON e.campaign_id = c.id
WHERE c.centre_id IS NULL;
... or, "how many unique email opens have we had? (on general campaigns)"
Currently takes about a minute and a half to run on an Amazon RDS instance. Total rows for the tables involved are roughly:
campaigns: 250
recipients: 330,000
views: 530,000
emails: 1,380,000
EXPLAIN gives me:
1 SIMPLE r index PRIMARY UNIQ_146632C4E7927C74 767 NULL 329196 Using index
1 SIMPLE e ref PRIMARY,IDX_4C81E852E92F8F78,IDX_4C81E852F639F774 IDX_4C81E852E92F8F78 111 ecomms.r.id 1 Using where
1 SIMPLE v ref IDX_11F09C87A832C1C9 IDX_11F09C87A832C1C9 111 ecomms.e.id 1 Using where; Using index
1 SIMPLE c eq_ref PRIMARY,IDX_E3737470463CD7C3 PRIMARY 110 ecomms.e.campaign_id 1 Using where
What can I do to get this total faster?
You need to join recipients only if you are not enforcing a foreign key constraint between recipients.id and emails.recipent_id, and you want to exclude recipients who are not (any longer) enlisted in the recipients table. Otherwise, omit that table from the join straight away; you can use emails.recipient_id instead of recipients.id. Omitting that join should be a big win.
Alternatively, omit recipients from the join on the basis that it is not relevant to the question posed, which is about unique emails opened, not about unique recipients to open any email. In that case you should be able to just SELECT COUNT(*) FROM ... because each emails row is already unique.
Other than that, it looks like you're already getting good use of your indexes, though I confess I find the EXPLAIN PLAN output difficult to read, especially without headings. Still, it looks like your query doesn't read the base tables at all, so it's unlikely that adding new indexes would help.
You could try executing an OPTIMIZE TABLE on the tables involved in your query, though that probably sounds more hopeful than it should.
You should periodically run ANALYZE TABLE on the tables involved in this query, to give the query optimizer has the greatest likelihood of choosing the best possible plan. It looks like the optimizer is already choosing a reasonable plan, though, so this may not help much.
If you still need better performance then there are other possibilities (including moving to faster hardware), but they are too numerous to discuss here.
You want MySQL to be able to utilize the WHERE clause to limit the result set immediately. In order to do that, you need the proper indexes to join from campaigns to emails, then from emails to recipients and views.
Put an index on campaigns.centre_id to aid the search (satisfy the WHERE clause). I'm assuming campaigns.id is the primary key on that table.
Put an index on emails.campaign_id to aid the join to emails from campaigns. Add recipient_id and email_id to that index to provide a covering index.
Now, the EXPLAIN result should show the tables in order, starting from campaigns, then emails, then the other two. MySQL will still need an internal temporary table to apply the DISTINCT. Are you sure you need that?
I'm assuming emails.id and recipients.id are the primary keys.
Yesterday I found a slow query running on the server(this query costs more than 1 minute).It looks like this:
select a.* from a
left join b on a.hotel_id=b.hotel_id and a.hotel_type=b.hotel_type
where b.hotel_id is null
There are 40000+ rows in table a and 10000+ rows in table b.An unique key had already been created on columns hotel_id and hotel_type in table b like UNIQUE KEY idx_hotel_id (hotel_id,hotel_type).So I used the explain keyword to check the query plan on this sql and I got a result like the following:
type key rows
1 SIMPLE a ALL NULL NULL NULL NULL 36804
1 SIMPLE b index NULL idx_hotel_id 185 NULL 8353 Using where; Using index; Not exists
According to the reference manual of MySQL, when all parts of an index are used by the join and the index is a PRIMARY KEY or UNIQUE NOT NULL index the join type will be "eq_ref".See the second row of the query plan,the value of column type is "index".But I really had en unique index on hotel_id and hotel_type and both the two columns were used by the join.The join type "ef_ref" is more efficient than the join type "ref" and "ref" is more efficient than "range"."index" is the last join type wo wanna hava except "ALL".This is what I'm confused about and I wanna know why the join type here is "index". I hope I describe my question clear and I'm looking forward to get answers from you guys,thanks!
Where Is Null checks can be slow, so maybe it is that.
select * from a
where not exists ( select 1 from b where a.hotel_id=b.hotel_id and a.hotel_type=b.hotel_type )
Also: how many records are you returning? If you are returning all 36804 records this could slow things down as well.
Thanks all the people above!I found the way to solve my problem myself.The columns hotel_id and hotel_type didn't have the same character set.After I made them both "utf8",my query returned result in about less than 10 millisecond.There is an good article about left join and index in MySQL,I strongly recommend it to you guys.Here is the site:http://explainextended.com/2009/09/18/not-in-vs-not-exists-vs-left-join-is-null-mysql/
the code below provide a result too much Infact i want to list the customer that never buy somethink How can i fix the code below
SELECT
webboard.listweb.id,
webboard.listweb.iditempro,
webboard.listweb.url,
webboard.listweb.useradddate,
webboard.listweb.expiredate,
webboard.prorecord.urlpostonweb
webboard.prorecord.urlpostonweb
FROM
webboard.listweb ,
webboard.prorecord
Where listweb.id Not In
(select webboard.prorecord.idlist From webboard.prorecord )
Using the syntax
FROM
webboard.listweb ,
webboard.prorecord
will perform a cartesian, or cross, join on the tables involved. So for every row in the table listweb all the rows in prorecord are displayed.
You need to use an INNER JOIN to only select the rows in listweb that have related rows in the prorecord table. What are the fields which identify the rows (your Primary Keys) and what is the name of the foreign key field in the prorecord table?
EDIT: Just re-read the question and comments and I see you want the rows in listweb which do not have an entry in prorecord
Your SELECT will then look like:
SELECT
webboard.listweb.id,
webboard.listweb.iditempro,
webboard.listweb.url,
webboard.listweb.useradddate,
webboard.listweb.expiredate,
webboard.prorecord.urlpostonweb
-- webboard.prorecord.urlpostonweb -- You have this field twice
FROM webboard.listweb LEFT JOIN webboard.prorecord
ON webboard.listweb.id = webboard.prorecord.idlist -- I'm guessing at the foreign key here
WHERE webboard.prorecord.idlist IS NULL