How to reformulate an sql query - mysql

i am not an expert in sql programming and i was wondering if you can help me reformulate the following query using INNER JOIN?
db_query("
select max(field_date_and_time_value2) as last_time
from field_data_field_date_and_time
where (field_date_and_time_value2 > '".$today."')
AND (".$node->uid." = (select uid from node where nid = " . $node->nid ."))");

Would something like this work?
SELECT
max(a.field_date_and_time_value2) as last_time
, b.uid
FROM field_data_field_date_and_time a
INNER JOIN
node b
ON
/* this piece might be wrong. what is the relationship between the first table and the second one? */
b.nid = '".$node->nid."'
where
a.field_date_and_time_value2 > '".$today."' AND
b.uid = $node->nid

Assuming your field_date_and_time table has a column called uid having the same meaning as that column in your node table, here's what you need to do.
SELECT MAX(A.field_date_and_time_value2) AS last_time
FROM field_date_and_time A
INNER JOIN node B ON A.uid = B.uid
WHERE B.nid = '".$node->nid."'
AND A.field_date_and_time_value2 > '".$today."'
Beware SQL injection attacks! Avoid substituting variables directly into SQL statements unless you're really sure those variables can't be corrupted by badguy users! Remember the story of the guy named
"johnny ; drop tables *;"

Related

How to optimize a query with inner join

My mysql query is too slow and i don't know how to optimize it. My webapp cant load this query because take too much time to run and the webserver have a limit time to get the result.
SELECT rc.trial_id,
rc.created,
rc.date_registration,
rc.agemin_value,
rc.agemin_unit,
rc.agemax_value,
rc.agemax_unit,
rc.exclusion_criteria,
rc.study_design,
rc.expanded_access_program,
rc.number_of_arms,
rc.enrollment_start_actual,
rc.target_sample_size,
(select name from repository_institution where id = rc.primary_sponsor_id) as
primary_sponsor,
(select label from vocabulary_studytype where id = rc.study_type_id) as study_type,
(select label from vocabulary_interventionassigment where id =
rc.intervention_assignment_id) as intervention_assignment,
(select label from vocabulary_studypurpose where id = rc.purpose_id) as study_purpose,
(select label from vocabulary_studymasking where id = rc.masking_id) as study_mask,
(select label from vocabulary_studyallocation where id = rc.allocation_id) as
study_allocation,
(select label from vocabulary_studyphase where id = rc.phase_id) as phase,
(select label from vocabulary_recruitmentstatus where id = rc.recruitment_status_id) as
recruitment_status,
GROUP_CONCAT(vi.label)
FROM
repository_clinicaltrial rc
inner JOIN repository_clinicaltrial_i_code rcic ON rcic.clinicaltrial_id = rc.id JOIN
vocabulary_interventioncode vi ON vi.id = rcic.interventioncode_id
GROUP BY rc.id;
Using inner join instead join could be a solution?
Changing to JOINs vs continuous selects per every row will definitely improve. Also, since you are using MySQL, using the keyword "STRAIGHT_JOIN" tells MySQL to do the query in the order I provided. Since your "rc" table is the primary and all the others are lookups, this will make MySQL use it in that context rather than hoping some other lookup table be the basis of the rest of the joins.
SELECT STRAIGHT_JOIN
rc.trial_id,
rc.created,
rc.date_registration,
rc.agemin_value,
rc.agemin_unit,
rc.agemax_value,
rc.agemax_unit,
rc.exclusion_criteria,
rc.study_design,
rc.expanded_access_program,
rc.number_of_arms,
rc.enrollment_start_actual,
rc.target_sample_size,
ri.name primary_sponsor,
st.label study_type,
via.label intervention_assignment,
vsp.label study_purpose,
vsm.label study_mask,
vsa.label study_allocation,
vsph.label phase,
vrs.label recruitment_status,
GROUP_CONCAT(vi.label)
FROM
repository_clinicaltrial rc
JOIN repository_clinicaltrial_i_code rcic
ON rc.id = rcic.clinicaltrial_id
JOIN vocabulary_interventioncode vi
ON rcic.interventioncode_id = vi.id
JOIN repository_institution ri
on rc.primary_sponsor_id = ri.id
JOIN vocabulary_studytype st
on rc.study_type_id = st.id
JOIN vocabulary_interventionassigment via
on rc.intervention_assignment_id = via.id
JOIN vocabulary_studypurpose vsp
ON rc.purpose_id = vsp.id
JOIN vocabulary_studymasking vsm
ON rc.masking_id = vsm.id
JOIN vocabulary_studyallocation vsa
ON rc.allocation_id = vsa.id
JOIN vocabulary_studyphase vsph
ON rc.phase_id = vsph.id
JOIN vocabulary_recruitmentstatus vrs
ON rc.recruitment_status_id = vrs.id
GROUP BY
rc.id;
One final note. You are using a GROUP BY and applying to the GROUP_CONCAT() which is ok. However, proper group by says you need to group by all non-aggregate columns, which in this case is every other column in the list. You may know this, and the fact the lookups will be the same based on the "rc" associated columns, but its not good practice to do so.
Your joins and subqueries are probably not the problem. Assuming you have correct indexes on the tables, then these are fast. "Correct indexes" means that the id column is the primary key -- a very reasonable assumption.
My guess is that the GROUP BY is the performance issue. So, I would suggest structuring the query with no `GROUP BY:
select . . .
(select group_concat(vi.label)
from repository_clinicaltrial_i_code rcic
vocabulary_interventioncode vi
on vi.id = rcic.interventioncode_id
where rcic.clinicaltrial_id = rc.id
)
from repository_clinicaltrial rc ;
For this, you want indexes on:
repository_clinicaltrial_i_code(clinicaltrial_id, interventioncode_id)
vocabulary_interventioncode(id, label)

SQL join tables based on if else if conditions

New to doing SQL stuff so please excuse me.
I want to create a SQL query that joins a column to table A from table B based on the following match logic:
B.Source = ‘SOURCE1’ and A.NameCode= B.Code
If the above return NULL then I’d like to match on:
B.Source <> ‘SOURCE1’ and A.UEN = B.UEN**
Any help on how to structure this?
I currently have a union all select query that can get the values based on the above conditions. Should I be using an If/or/case_when in the join process?
A few questions in which I thought could be helpful and that I've looked at are:
How to perform a LEFT JOIN in SQL Server between two SELECT statements?
Using IS NULL or IS NOT NULL on join conditions - Theory question
But I was not able to come up with anything :(
Thank you so much!
Try something like this:
SELECT *
FROM A
JOIN B ON (
(B.Source = 'Source1' AND A.NameCode = B.Code) OR
(B.Source <> 'Source1' AND A.UEN = B.[UEN**]) --Not sure what the ** is? Part of the field name?
)

Sql query selecting from both tables.

I have a query which looks like this
$db->query("SELECT A.page_id, A.page_name FROM user_likes_pages as A , user_likes as B WHERE A.page_id = B.page_id AND B.country_id = ".$user_reg." ");
The thing is, I want to select a column from user_likes. Do I have to make a join or I can do it in different way. Thank you.
You have a join in your query, but it is implicit. You should write the query as:
SELECT ulp.page_id, ulp.page_name, ul.<whatever>
FROM user_likes ul JOIN
user_likes_pages ulp
ON ul.page_id = ulp.page_id
WHERE ul.country_id = ".$user_reg."
In addition to adding the explicit join syntax, I also changed the table aliases so they are abbreviations of the table name. This makes it easier to read the query and avoid mistakes.
You select B.columnname. You don't need a join, because you have the A.page_id = B.page_id.

Convert MS SQL Server Query in MYSQL QUERY

I have written a Query,
SELECT dbo.boat.boatno, dbo.boat.boattype, dbo.staff.staffFirstName, dbo.staff.staffLastName,
dbo.branch.branchAddress
FROM dbo.boat INNER JOIN
dbo.BoatOwner ON dbo.boat.OwnerNo = dbo.BoatOwner.OwnerNo INNER JOIN
dbo.branch ON dbo.boat.BranchNo = dbo.branch.branchno INNER JOIN
dbo.staff ON dbo.branch.branchno = dbo.staff.Branchno
WHERE (dbo.branch.branchAddress LIKE '%LONDON%')
But It doesn't work in MYSQL QUERY
How can i convert this into MYSQL QUERY?
You need to know correct table names for MySQL. Assuming a similar structure, I might try:
SELECT b.boatno, b.boattype, s.staffFirstName, s.staffLastName, br.branchAddress
FROM boat b INNER JOIN
BoatOwner bo
ON b.OwnerNo = bo.OwnerNo INNER JOIN
branch br
ON b.BranchNo = br.branchno INNER JOIN
staff s
ON br.branchno = s.Branchno
WHERE br.branchAddress LIKE '%LONDON%';
MySQL does not use the three-part naming that SQL Server does. There is no "schema" in the middle of the name. The additional periods in the column names are probably one source of confusion. Using table aliases should work in both databases and makes the code more readable.
Just a guess from general principles, but perhaps the simpler
SELECT A.boatno, A.boattype, D.staffFirstName, D.staffLastName, C.branchAddress
FROM dbo.boat A, dbo.BoatOwner B, dbo.branch C, dbo.staff D
WHERE B.OwnerNo = A.OwnerNo AND C.branchno = A.BranchNo AND D.Branchno = C.branchno
AND C.branchAddress LIKE '%LONDON%'
may work.
To begin, make sure also that you can SELECT from dbo.boat, dbo.BoatOwner, dbo.branch and dbo.staff using your PHPmyAdmin environment. Sometimes the simple things trip us up...
SELECT b.boatno, b.boattype, s.staffFirstName, s.staffLastName, br.branchAddress
FROM boat b INNER JOIN
BoatOwner bo
ON b.OwnerNo = bo.OwnerNo INNER JOIN
branch br
ON b.BranchNo = br.branchno INNER JOIN
staff s
ON br.branchno = s.Branchno
WHERE br.branchAddress LIKE '%LONDON%';
GROUP BY b.boatno
Isn't that enought?

Correlated Subquery in a MySQL CASE Statement

Here is a brief explanation of what I'm trying to accomplish; my query follows below.
There are 4 tables and 1 view which are relevant for this particular query (sorry the names look messy, but they follow a strict convention that would make sense if you saw the full list):
Performances may have many Performers, and those associations are stored in PPerformer. Fans can have favorites, which are stored in Favorite_Performer. The _UpcomingPerformances view contains all the information needed to display a user-friendly list of upcoming performances.
My goal is to select all the data from _UpcomingPerformances, then include one additional column that specifies whether the given Performance has a Performer which the Fan added as their favorite. This involves selecting the list of Performers associated with the Performance, and also the list of Performers who are in Favorite_Performer for that Fan, and intersecting the two arrays to determine if anything is in common.
When I execute the below query, I get the error #1054 - Unknown column 'up.pID' in 'where clause'. I suspect it's somehow related to a misuse of Correlated Subqueries but as far as I can tell what I'm doing should work. It works when I replace up.pID (in the WHERE clause of t2) with a hard-coded number, and yes, pID is an existing column of _UpcomingPerformances.
Thanks for any help you can provide.
SELECT
up.*,
CASE
WHEN EXISTS (
SELECT * FROM (
SELECT RID FROM Favorite_Performer
WHERE FanID = 107
) t1
INNER JOIN
(
SELECT r.ID as RID
FROM PPerformer pr
JOIN Performer r ON r.ID = pr.Performer_ID
WHERE pr.Performance_ID = up.pID
) t2
ON t1.RID = t2.RID
)
THEN "yes"
ELSE "no"
END as pText
FROM
_UpcomingPerformances up
The problem is scope related. The nested Selects make the up table invisible inside the internal select. Try this:
SELECT
up.*,
CASE
WHEN EXISTS (
SELECT *
FROM Favorite_Performer fp
JOIN Performer r ON fp.RID = r.ID
JOIN PPerformer pr ON r.ID = pr.Performer_ID
WHERE fp.FanID = 107
AND pr.Performance_ID = up.pID
)
THEN 'yes'
ELSE 'no'
END as pText
FROM
_UpcomingPerformances up