Multiple Left Joins in MySQL - mysql

I seem to be having some issues getting my multi left join to give me the correct results, it gives me the id just fine however i cannot seem to get the link to give me the resulting question instead of the ID.
Code below.
SELECT
a.id as id,
a.clientid as clientid,
a.comp_id as compid,
a.title as title,
a.firstname as firstname,
a.lastname as lastname,
a.countrycode as countrycode,
a.mobile as mobile,
a.question1_answer as question1_answer,
a.question2_answer as question2_answer,
a.question3_answer as question3_answer,
a.timestamp as timestamp,
b.comp_name as comp_name,
b.comp_id as comp_id,
a.question1 as question1,
a.question2 as question2,
a.question3 as question3
FROM
competition_entries AS a
LEFT JOIN
competition as b
ON
a.comp_id = b.id
LEFT JOIN
questions as q
ON
a.question1 = q.question_id
AND
a.question2 = q.question_id
AND
a.question3 = q.question_id
WHERE
a.comp_id = '$download_id'
However each time i call question1 / question2 / question3 - the only results shown are the number values that are corresponding to their ID within the other table.

You need to join to the question table three times, once for each id you have:
SELECT a.id as id, a.clientid as clientid, a.comp_id as compid, a.title as title,
a.firstname as firstname, a.lastname as lastname, a.countrycode as countrycode,
a.mobile as mobile,
a.question1_answer as question1_answer,
a.question2_answer as question2_answer,
a.question3_answer as question3_answer,
a.timestamp as timestamp,
b.comp_name as comp_name,
b.comp_id as comp_id,
a.question1 as question1id,
a.question2 as question2id,
a.question3 as question3id,
q1.question as question1,
q2.question as question2,
q3.question as question3
FROM competition_entries a LEFT JOIN
competition as b
ON a.comp_id = b.id LEFT JOIN
questions as q1
ON a.question1 = q1.question_id left join
questions q2
on a.question2 = q2.question_id left join
questions q3
on a.question3 = q3.question_id
WHERE a.comp_id = '$download_id'

Related

How Do I Count Number of Males and Females

I have the query as follows:
select d.question, b.response, count(b.response)
from sl_flow a
INNER JOIN ul_attempt_responses b on a.question_id = b.question_id and b.type = 1
INNER JOIN us_attempts c on c.id = b.attempt_id
INNER JOIN ss_questions d on d.id = a.question_id
where a.status = 1
and a.ckm_question = 0
and b.response
group by a.question_id, b.response
order by a.question_order asc
The above gives me the questions that I have in the DB which are active and their responses and counts.
However I need a query that will give me number of males and females that answered each of the question. Therefore, I have another query that gives me the number of males and females which is:
SELECT
concat(a.response, 's') as gender,
count(a.response) as count
FROM
ul_attempt_responses a
INNER JOIN us_attempts b ON a.attempt_id = b.id
WHERE
a.question_id = 6 and a.type = 0 AND trim(a.response) != ''
GROUP by a.response;
I am not sure, how to do so. For the gender, the question_id is 6 and type on the a table has to be 0 (the a table is ul_attempt_responses).
This is what I got so far. However, it appears that the results I am getting may not be consistent:
SELECT
gender.question
,coalesce(sum(case final.Response when 'male' then gender.total end),0) as 'Males'
,coalesce(sum(case final.Response when 'female' then gender.total end),0) as 'Females'
FROM
(SELECT
stats . *,
(CASE concat(stats.userid, stats.QuestionID, stats.type)
WHEN #curType THEN #curRow:=coalesce(#curRow, 0) + 1
ELSE #curROw:=1
AND #curType:=concat(stats.userid, stats.QuestionID, stats.type)
END) + 1 AS rank
FROM
(SELECT
d.question as Question,
a.user_id AS UserID,
c.question_id AS QuestionID,
c.type as Type,
c.response AS Response,
a.campaign_id as campaign_id
FROM
us_attempts a
INNER JOIN ul_attempt_responses c ON a.id = c.attempt_id
RIGHT OUTER JOIN ss_profile_questions d ON c.question_id = d.id AND c.type = 0
LEFT OUTER JOIN sl_profile_flow f ON c.question_id = f.profile_question_id
RIGHT OUTER JOIN us_users g ON g.id = a.user_id
WHERE
f.status = 1
ORDER BY a.user_id , c.question_id , c.type , a.id desc) stats) final
INNER JOIN
(select b.user_id, c.question as question, count(1) as total
from ul_attempt_responses a
INNER JOIN us_attempts b on a.attempt_id = b.id
INNER JOIN ss_questions c on a.question_id = c.id and a.type = 1
group by b.user_id, c.id) gender on final.UserID = gender.user_id
where
final.rank = 2 and final.QuestionID = 6 and final.campaign_id = 3
group by gender.question;
Is there a way I can reduce the above query, or is there a better optimized way?
You could use a combination of sum and case/if to get the counts. Given your full table structures are not clear, I am assuming you have a table (or an SQL that can produce a set of rows) with the following fields:
response_id
question_id
response
Then an SQL such as
select question_id
, response
, sum(if(gender='M',1,0)) as males
, sum(if(gender='F',1,0)) as females
from (select q.question_id
, q.response
, g.response as gender from answers as q
left join answers as g on q.response_id=g.response_id and g.question_id=6
where q.question_id!=6) as t
group by question_id, response
would give you a result of the form
question_id,response,males,females
1,A,1,2
1,B,1,0
2,A,0,1
2,B,1,1
2,C,1,0
To explain the code, the sub query produces a set of rows for each response with the question mapped with the gender question's response. In the main select statement the if statement produces a 1 for the specific gender in the proper column and summing them up gives you how many of that specific gender responded to that question.
EDIT
As suggested by #Strawberry, the shorter version would be
select q.question_id
, q.response_id
, sum(g.response='M') as males
, sum(g.response='F') as females
from answers as q
left
join test as g
on q.response_id = g.response_id
and g.question_id = 6
where q.question_id != 6
group
by q.question_id
, q.response

choosing the sql statement which use less loading time

i have 2 sql statements which produce the same result, but wondering which one to choose?
lets say 1 have 3 tables:
supplier
supplier_status
supplier_contact
statement 1)
SELECT a.*, b.status_name
(SELECT c.name FROM contact c
WHERE c.supplier_id = a.supplier_id
ORDER BY c.contact_id DESC limit 1) AS contact_name
FROM supplier a LEFT JOIN supplier_status b
ON a.status_id = b.status_id
statement 2)
SELECT a.*, b.status_name, c.name AS contact_name
FROM supplier a LEFT JOIN supplier_status b
ON a.status_id = b.status_id
LEFT JOIN (SELECT name, supplier_id
FROM contact
ORDER BY contact_id DESC
) c ON a.supplier_id = c.supplier_id
GROUP BY a.supplier_id
Try this query:
SELECT a.*, b.status_name, c.name AS contact_name
FROM supplier a
LEFT JOIN supplier_status b ON a.status_id = b.status_id
LEFT JOIN contact c ON a.supplier_id = c.supplier_id
LEFT JOIN contact d ON c.supplier_id = d.supplier_id AND c.contact_id < d.contact_id
WHERE d.contact_id IS NULL
It's possible that it doesn't produce the same result as yours (I didn't test it) but if it does then all you have to do is to make sure the fields that appear in the JOIN conditions are indexed (they probably are FKs, so they already are).

Issue to get total amount while using inner join in MYSQL

I get an wrong TotalPrice from the ItemDetails table while join the taxdetails table.
Code 1:
select Distinct B.ID as BillId,
I.ID as ItemDetailId,
I.TotalPrice as ItemPrice,
T.Amount as TaxAmount from Bill B
inner join ItemDetails I on I.BillNoID = B.ID
inner join TaxDetails T on T.ItemDetailId = I.Id;
Refer below image,
While sum the TotalPrice and TotalTaxAmount on the same query i got an wrong TotalPrice result,
Code 2:
select Distinct B.ID as BillId,
SUM(I.TotalPrice) as TotalPrice,
SUM(T.Amount) as TotalTaxAmount from Bill B
inner join ItemDetails I on I.BillNoID = B.ID
inner join TaxDetails T on T.ItemDetailId = I.Id
group by B.ID;
Please refer below image,
Actual issue is as per taxdetails per itemdetail each row the rows become multiple so the totalprice get differs.
Expected Output for code 2 (i have listed the first row expected result) is,
Billid TotalPrice TotalTaxAmount
1 70 30
Try this,you have multiple items/bill, that is why you can't make inner join directly.Remove group by also.
select B.ID as BillId,
I.TotalPrice as TotalPrice,
T.Amount as TotalTaxAmount from Bill B
inner join
(
select BillNoID,SUM(TotalPrice) as TotalPrice from ItemDetails
group by BillNoID
)as I on I.BillNoID = B.ID
inner join
(
Select ItemDetailId,SUM(Amount) as Amount from TaxDetails
group by ItemDetailId
)as T on T.ItemDetailId = I.Id

Issue while Combining multiple rows in MySQL

I want to build the query according to the following conditions,
I just want to combine the sum the Total price of both type 1 and type 2.
Combine 2 rows into 1 and avoid null values in that rows.
Query,
select B.ID as BillId,
I.Id as ItemID,
t.Type,
SUM(I.TotalPrice) as TotalPrice,
Case when t.Type = 1 then SUM(T.Amount) end as TaxAmountType1,
Case when t.Type = 2 then SUM(T.Amount) end as TaxAmountType2
from Bill B
inner join ItemDetails I
on I.BillNoID = B.ID
inner join TaxDetails T
on T.ItemDetailId = I.Id
group by
B.ID,
I.Id,
I.TotalPrice,
t.Type;
Please refer below image,
Expected Output:
'1', '1', NULL, '40.00', '3.00', '5.00'
Note:
1. I dont want to use sub-query.
2. Expected output "NULL" refers i don't want to show that column seperately.
Sounds like this would solve your problem. If not please give more informations.
SELECT B.ID as BillId, I.Id as ItemId,
t.type, SUM(TotalPrice), SUM(TaxAmountType1),
SUM(TaxAmountType2)
FROM Bill B
GROUP BY BillId, ItemId, t.type
Don't group by the column that you're trying to aggregate. Remove the I.TotalPrice from the GROUP BY:
select B.ID as BillId, I.Id as ItemID, t.Type, SUM(I.TotalPrice) as TotalPrice,
Case when t.Type = 1 then SUM(T.Amount) end as TaxAmountType1,
Case when t.Type = 2 then SUM(T.Amount) end as TaxAmountType2 from Bill B
inner join ItemDetails I on I.BillNoID = B.ID
inner join TaxDetails T on T.ItemDetailId = I.Id
group by B.ID, I.Id, t.Type;`
Try
select B.ID as BillId, I.Id as ItemID, null as Type, SUM(I.TotalPrice) as TotalPrice,
Case when t.Type = 1 then SUM(T.Amount) end as TaxAmountType1,
Case when t.Type = 2 then SUM(T.Amount) end as TaxAmountType2
from Bill B
inner join ItemDetails I on I.BillNoID = B.ID
inner join TaxDetails T on T.ItemDetailId = I.Id
group by B.ID, I.Id, I.TotalPrice
You don't want to group by type, that's the issue (you also can remove the ", null as Type" from the select)
If you group by t.type, you wont be able to have those instances in the same line.
Try:
select B.ID as BillId, I.Id as ItemID, t.Type, SUM(I.TotalPrice) as TotalPrice,
Case when t.Type = 1 then SUM(T.Amount) end as TaxAmountType1,
Case when t.Type = 2 then SUM(T.Amount) end as TaxAmountType2 from Bill B
inner join ItemDetails I on I.BillNoID = B.ID
inner join TaxDetails T on T.ItemDetailId = I.Id
group by B.ID, I.Id, I.TotalPrice;

Optimizing this SQL Query

How would you optimize the following query?
'example_companies' contains companies data.
'example_roles_companies' contains companies roles (pivot)
'example_industries_companies' contains companies industries (pivot)
SELECT DISTINCT a.id,
a.mode,
a.name,
a.city,
b.name AS USER,
b.phone
FROM example_companies a
LEFT JOIN example_users b
ON a.contact_id = b.id
LEFT JOIN example_roles_companies c
ON a.id = c.company_id
WHERE "2" IN (SELECT industry_id
FROM example_industries_companies
WHERE company_id = a.id)
AND c.role_id = 2
AND a.account_mode != 2
ORDER BY a.id
Query:
SELECT DISTINCT a.id,
a.mode,
a.name,
a.city,
b.name AS USER,
b.phone
FROM example_companies a
LEFT JOIN example_users b ON a.contact_id = b.id
INNER JOIN example_roles_companies c ON a.id = c.company_id AND c.role_id = 2
INNER JOIN example_industries_companies i
ON i.company_id = a.id AND i.industry_id = "2"
WHERE
a.account_mode != 2
ORDER BY
a.id
Structure:
Index on a.id, not null
Index on b.id, not null [analyze the opportunity of adding another index (b.id, b.name, b.phone) to this table as well]
Index on (c.company_id, c.role_id) not null both
Index on (i.company_id, i.industry_id), not null both
Remarks:
Please note that your industry_id = "2" seems weird to me, ids are generally numbers and if they are not then it should be looked since integers are faster to process than strings. Additionally, this way of double-quoting is not usual in mysql. Are you sure of your syntax?